|
@@ -1,4 +1,5 @@
|
|
|
/*
|
|
|
+ * Copyright (c) 2014 Willem Dijkstra
|
|
|
* Copyright (c) 2004 Matthew Gream
|
|
|
* All rights reserved.
|
|
|
*
|
|
@@ -34,7 +35,7 @@
|
|
|
*
|
|
|
* user : nice : system : interrupt : idle
|
|
|
*
|
|
|
- * This code is not re-entrant and UP only.
|
|
|
+ * This code is not re-entrant.
|
|
|
*
|
|
|
* This module uses the sysctl interface and can run as any user.
|
|
|
*/
|
|
@@ -45,28 +46,55 @@
|
|
|
#include <sys/dkstat.h>
|
|
|
#include <sys/sysctl.h>
|
|
|
|
|
|
+#include <errno.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <limits.h>
|
|
|
+
|
|
|
#include "error.h"
|
|
|
#include "percentages.h"
|
|
|
#include "symon.h"
|
|
|
+#include "sylimits.h"
|
|
|
+#include "xmalloc.h"
|
|
|
|
|
|
/* Globals for this module all start with cp_ */
|
|
|
+#ifdef HAS_CP_TIMES
|
|
|
+static char cp_time_mib_str[] = "kern.cp_times";
|
|
|
+#else
|
|
|
static char cp_time_mib_str[] = "kern.cp_time";
|
|
|
+#endif
|
|
|
static int cp_time_mib[CTL_MAXNAME];
|
|
|
static size_t cp_time_len = 0;
|
|
|
-static size_t cp_size;
|
|
|
+static void *cp_buf;
|
|
|
+static size_t cp_size = 0;
|
|
|
|
|
|
void
|
|
|
init_cpu(struct stream *st)
|
|
|
{
|
|
|
char buf[SYMON_MAX_OBJSIZE];
|
|
|
+ const char *errstr;
|
|
|
+
|
|
|
+ if (cp_time_len == 0) {
|
|
|
+ cp_time_len = CTL_MAXNAME;
|
|
|
+ if (sysctlnametomib(cp_time_mib_str, cp_time_mib, &cp_time_len) < 0) {
|
|
|
+ warning("sysctlnametomib for cpu failed");
|
|
|
+ cp_time_len = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((sysctl(cp_time_mib, cp_time_len, NULL, &cp_size, NULL, 0) != -1) &&
|
|
|
+ (errno == ENOMEM))
|
|
|
+ fatal("cpu(%.200s): failed to determine sysctl buffer len", st->arg);
|
|
|
|
|
|
- cp_time_len = CTL_MAXNAME;
|
|
|
- if (sysctlnametomib(cp_time_mib_str, cp_time_mib, &cp_time_len) < 0) {
|
|
|
- warning("sysctlnametomib for cpu failed");
|
|
|
- cp_time_len = 0;
|
|
|
+ if (cp_size > SYMON_MAX_OBJSIZE)
|
|
|
+ fatal("cpu(%.200s): sysctl buffer too large", st->arg);
|
|
|
+
|
|
|
+ cp_buf = xmalloc(cp_size);
|
|
|
+ gets_cpu();
|
|
|
}
|
|
|
|
|
|
- cp_size = sizeof(st->parg.cp.time1);
|
|
|
+ st->parg.cp.id = strtonum(st->arg, 0, SYMON_MAXCPUID, &errstr);
|
|
|
+ if (errstr != NULL)
|
|
|
+ fatal("cpu(%.200s) is invalid: %.200s", st->arg, errstr);
|
|
|
+
|
|
|
get_cpu(buf, sizeof(buf), st);
|
|
|
|
|
|
info("started module cpu(%.200s)", st->arg);
|
|
@@ -75,26 +103,29 @@ init_cpu(struct stream *st)
|
|
|
void
|
|
|
gets_cpu()
|
|
|
{
|
|
|
- /* EMPTY */
|
|
|
+ if (sysctl(cp_time_mib, cp_time_len, cp_buf, &cp_size, NULL, 0) < 0) {
|
|
|
+ warning("%s:%d: sysctl failed", __FILE__, __LINE__);
|
|
|
+ return;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
int
|
|
|
get_cpu(char *symon_buf, int maxlen, struct stream *st)
|
|
|
{
|
|
|
int i;
|
|
|
+ long *time1;
|
|
|
|
|
|
- if (!cp_time_len) {
|
|
|
+ if (!cp_time_len)
|
|
|
return 0;
|
|
|
- }
|
|
|
|
|
|
- if (sysctl(cp_time_mib, cp_time_len, &st->parg.cp.time1, &cp_size, NULL, 0) < 0) {
|
|
|
- warning("%s:%d: sysctl kern.cp_time failed", __FILE__, __LINE__);
|
|
|
- return 0;
|
|
|
- }
|
|
|
+ time1 = (long *)(cp_buf + (sizeof(long) * CPUSTATES * st->parg.cp.id));
|
|
|
+
|
|
|
+ if (((void *)time1 - cp_buf) > cp_size)
|
|
|
+ warning("cpu(%d): not in sysctl buffer", st->parg.cp.id);
|
|
|
|
|
|
/* convert cp_time counts to percentages */
|
|
|
for (i = 0; i < CPUSTATES; i++)
|
|
|
- st->parg.cp.time2[i] = (int64_t) st->parg.cp.time1[i];
|
|
|
+ st->parg.cp.time2[i] = (int64_t) time1[i];
|
|
|
|
|
|
(void)percentages(CPUSTATES, st->parg.cp.states, st->parg.cp.time2, st->parg.cp.old, st->parg.cp.diff);
|
|
|
|