summaryrefslogtreecommitdiff
path: root/src/pmdas/solaris/sysinfo.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
committerIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
commit47e6e7c84f008a53061e661f31ae96629bc694ef (patch)
tree648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmdas/solaris/sysinfo.c
downloadpcp-debian/3.9.10.tar.gz
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmdas/solaris/sysinfo.c')
-rw-r--r--src/pmdas/solaris/sysinfo.c376
1 files changed, 376 insertions, 0 deletions
diff --git a/src/pmdas/solaris/sysinfo.c b/src/pmdas/solaris/sysinfo.c
new file mode 100644
index 0000000..1937eed
--- /dev/null
+++ b/src/pmdas/solaris/sysinfo.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved.
+ * Copyright (c) 2010 Max Matveev. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include "common.h"
+#include <sys/utsname.h>
+#include <sys/loadavg.h>
+
+typedef struct {
+ int fetched;
+ int err;
+ kstat_t *ksp;
+ cpu_stat_t cpustat;
+ kstat_t *info;
+ int info_is_good;
+} ctl_t;
+
+static int ncpu;
+static int hz;
+static long pagesize;
+static ctl_t *ctl;
+static char uname_full[SYS_NMLN * 5];
+static int nloadavgs;
+static double loadavgs[3];
+
+void
+sysinfo_init(int first)
+{
+ kstat_t *ksp;
+ int i;
+ char buf[10]; /* cpuXXXXX */
+ kstat_ctl_t *kc;
+
+ if (!first)
+ /* TODO ... not sure if/when we'll use this re-init hook */
+ return;
+
+ if ((kc = kstat_ctl_update()) == NULL)
+ return;
+
+ for (ncpu = 0; ; ncpu++) {
+ ksp = kstat_lookup(kc, "cpu_stat", ncpu, NULL);
+ if (ksp == NULL) break;
+ if ((ctl = (ctl_t *)realloc(ctl, (ncpu+1) * sizeof(ctl_t))) == NULL) {
+ fprintf(stderr, "sysinfo_init: ctl realloc[%d] @ cpu=%d failed: %s\n",
+ (int)((ncpu+1) * sizeof(ctl_t)), ncpu, osstrerror());
+ exit(1);
+ }
+ ctl[ncpu].info = kstat_lookup(kc, "cpu_info", ncpu, NULL);
+ ctl[ncpu].ksp = ksp;
+ ctl[ncpu].err = 0;
+ }
+
+ indomtab[CPU_INDOM].it_numinst = ncpu;
+ indomtab[CPU_INDOM].it_set = (pmdaInstid *)malloc(ncpu * sizeof(pmdaInstid));
+ /* TODO check? */
+
+ for (i = 0; i < ncpu; i++) {
+ indomtab[CPU_INDOM].it_set[i].i_inst = i;
+ snprintf(buf, sizeof(buf), "cpu%d", i);
+ indomtab[CPU_INDOM].it_set[i].i_name = strdup(buf);
+ /* TODO check? */
+ }
+
+ hz = (int)sysconf(_SC_CLK_TCK);
+ pagesize = sysconf(_SC_PAGESIZE);
+
+#ifdef PCP_DEBUG
+ if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) {
+ /* desperate */
+ fprintf(stderr, "sysinfo: ncpu=%d hz=%d\n", ncpu, hz);
+ }
+#endif
+}
+
+static __uint32_t
+sysinfo_derived(pmdaMetric *mdesc, int inst)
+{
+ pmID pmid = mdesc->m_desc.pmid;
+ __pmID_int *ip = (__pmID_int *)&pmid;
+ __uint32_t val;
+
+ ip->domain = 0;
+
+ switch (pmid) {
+
+ case PMDA_PMID(SCLR_SYSINFO,56): /* hinv.ncpu */
+ if (inst == 0)
+ val = ncpu;
+ else
+ val = 0;
+ break;
+
+ default:
+ fprintf(stderr, "cpu_derived: Botch: no method for pmid %s\n",
+ pmIDStr(mdesc->m_desc.pmid));
+ val = 0;
+ break;
+ }
+
+#ifdef PCP_DEBUG
+ if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) {
+ /* desperate */
+ fprintf(stderr, "cpu_derived: pmid %s inst %d val %d\n",
+ pmIDStr(mdesc->m_desc.pmid), inst, val);
+ }
+#endif
+
+ return val;
+}
+
+void
+sysinfo_prefetch(void)
+{
+ int i;
+
+ nloadavgs = -1;
+ for (i = 0; i < ncpu; i++) {
+ ctl[i].fetched = 0;
+ ctl[i].info_is_good = 0;
+ }
+}
+
+int
+kstat_named_to_pmAtom(const kstat_named_t *kn, pmAtomValue *atom)
+{
+ static char chardat[sizeof(kn->value.c) + 1];
+
+ switch (kn->data_type) {
+ case KSTAT_DATA_UINT64:
+ atom->ull = kn->value.ui64;
+ return 1;
+ case KSTAT_DATA_INT64:
+ atom->ull = kn->value.i64;
+ return 1;
+ case KSTAT_DATA_UINT32:
+ atom->ull = kn->value.ui32;
+ return 1;
+ case KSTAT_DATA_INT32:
+ atom->ull = kn->value.i32;
+ return 1;
+ case KSTAT_DATA_STRING:
+ atom->cp = kn->value.str.addr.ptr;
+ return 1;
+ case KSTAT_DATA_CHAR:
+ memcpy(chardat, kn->value.c, sizeof(kn->value.c));
+ chardat[sizeof(chardat)-1] = '\0';
+ atom->cp = chardat;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static int
+kstat_fetch_named(kstat_ctl_t *kc, pmAtomValue *atom, char *metric,
+ int shift_bits)
+{
+ kstat_t *ks;
+
+ if ((ks = kstat_lookup(kc, "unix", -1, "system_pages")) != NULL) {
+ kstat_named_t *kn;
+
+ if (kstat_read(kc, ks, NULL) == -1)
+ return 0;
+
+ if (((kn = kstat_data_lookup(ks, metric)) != NULL) &&
+ kstat_named_to_pmAtom(kn, atom)) {
+ atom->ull = (atom->ull * pagesize) >> shift_bits;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+kstat_named_to_typed_atom(const kstat_named_t *kn, int pmtype,
+ pmAtomValue *atom)
+{
+ static char chardat[sizeof(kn->value.c) + 1];
+
+ switch (pmtype) {
+ case PM_TYPE_32:
+ if (kn->data_type == KSTAT_DATA_INT32) {
+ atom->l = kn->value.i32;
+ return 1;
+ }
+ break;
+ case PM_TYPE_U32:
+ if (kn->data_type == KSTAT_DATA_UINT32) {
+ atom->ul = kn->value.ui32;
+ return 1;
+ }
+ break;
+ case PM_TYPE_64:
+ if (kn->data_type == KSTAT_DATA_INT64) {
+ atom->ll = kn->value.i64;
+ return 1;
+ }
+ break;
+ case PM_TYPE_U64:
+ if (kn->data_type == KSTAT_DATA_UINT64) {
+ atom->ull = kn->value.ui64;
+ return 1;
+ }
+ break;
+ case PM_TYPE_STRING:
+ switch(kn->data_type) {
+ case KSTAT_DATA_STRING:
+ atom->cp = kn->value.str.addr.ptr;
+ return 1;
+ case KSTAT_DATA_CHAR:
+ memcpy(chardat, kn->value.c, sizeof(kn->value.c));
+ chardat[sizeof(chardat)-1] = '\0';
+ atom->cp = chardat;
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+int
+sysinfo_fetch(pmdaMetric *mdesc, int inst, pmAtomValue *atom)
+{
+ __uint64_t ull;
+ int i;
+ int ok;
+ ptrdiff_t offset;
+ struct utsname u;
+ kstat_ctl_t *kc;
+
+ if ((kc = kstat_ctl_update()) == NULL)
+ return 0;
+
+ /* Special processing of metrics which notionally belong
+ * to sysinfo category */
+ switch (pmid_item(mdesc->m_desc.pmid)) {
+ case 109: /* hinv.physmem */
+ return kstat_fetch_named(kc, atom, "physmem", 20);
+ case 136: /* mem.physmem */
+ return kstat_fetch_named(kc, atom, "physmem", 10);
+ case 137: /* mem.freemem */
+ return kstat_fetch_named(kc, atom, "freemem", 10);
+ case 138: /* mem.lotsfree */
+ return kstat_fetch_named(kc, atom, "lotsfree", 10);
+ case 139: /* mem.availrmem */
+ return kstat_fetch_named(kc, atom, "availrmem", 10);
+
+ case 108: /* hinv.pagesize */
+ atom->ul = pagesize;
+ return 1;
+
+ case 107: /* pmda.uname */
+ if (uname(&u) < 0)
+ return 0;
+
+ snprintf(uname_full, sizeof(uname_full), "%s %s %s %s %s",
+ u.sysname, u.nodename, u.release, u.version, u.machine);
+ atom->cp = uname_full;
+ return 1;
+ case 135: /* kernel.all.load */
+ if (nloadavgs < 0) {
+ if ((nloadavgs = getloadavg(loadavgs, 3)) < 0)
+ return 0;
+ }
+
+ switch (inst) {
+ case 1:
+ atom->f = (float)loadavgs[LOADAVG_1MIN];
+ return nloadavgs > LOADAVG_1MIN;
+ case 5:
+ atom->f = (float)loadavgs[LOADAVG_5MIN];
+ return nloadavgs > LOADAVG_5MIN;
+ case 15:
+ atom->f = (float)loadavgs[LOADAVG_15MIN];
+ return nloadavgs > LOADAVG_15MIN;
+ }
+ return PM_ERR_INST;
+ }
+
+ ok = 1;
+ for (i = 0; i < ncpu; i++) {
+ if (inst == PM_IN_NULL || inst == i) {
+ if (!ctl[i].info_is_good) {
+ ctl[i].info_is_good = (ctl[i].info &&
+ (kstat_read(kc, ctl[i].info,
+ NULL) != -1));
+ }
+ if (ctl[i].fetched == 1)
+ continue;
+ if (kstat_read(kc, ctl[i].ksp, &ctl[i].cpustat) == -1) {
+ if (ctl[i].err == 0) {
+ fprintf(stderr, "Error: sysinfo_fetch(pmid=%s cpu=%d ...)\n", pmIDStr(mdesc->m_desc.pmid), i);
+ fprintf(stderr, "kstat_read(kc=%p, ksp=%p, ...) failed: %s\n", kc, ctl[i].ksp, osstrerror());
+ }
+ ctl[i].err++;
+ ctl[i].fetched = -1;
+ ok = 0;
+ }
+ else {
+ ctl[i].fetched = 1;
+ if (ctl[i].err != 0) {
+ fprintf(stderr, "Success: sysinfo_fetch(pmid=%s cpu=%d ...) after %d errors as previously reported\n",
+ pmIDStr(mdesc->m_desc.pmid), i, ctl[i].err);
+ ctl[i].err = 0;
+ }
+ }
+ }
+ }
+
+ if (!ok)
+ return 0;
+
+ ull = 0;
+ for (i = 0; i < ncpu; i++) {
+ if (inst == PM_IN_NULL || inst == i) {
+ offset = ((metricdesc_t *)mdesc->m_user)->md_offset;
+
+ if (offset == -1) {
+ ull += sysinfo_derived(mdesc, i);
+ } else if (offset > sizeof(ctl[i].cpustat)) {
+ char *stat = (char *)offset;
+ kstat_named_t *kn;
+
+ if (!ctl[i].info_is_good)
+ return 0;
+
+ if ((kn = kstat_data_lookup(ctl[i].info, stat)) == NULL) {
+ fprintf(stderr, "No kstat called %s for CPU %d\n", stat, i);
+ return 0;
+ }
+
+ return kstat_named_to_typed_atom(kn, mdesc->m_desc.type, atom);
+ } else {
+ /* all the kstat fields are 32-bit unsigned */
+ __uint32_t *ulp;
+ ulp = (__uint32_t *)&((char *)&ctl[i].cpustat)[offset];
+ ull += *ulp;
+#ifdef PCP_DEBUG
+ if ((pmDebug & (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) == (DBG_TRACE_APPL0|DBG_TRACE_APPL2)) {
+ /* desperate */
+ fprintf(stderr, "sysinfo_fetch: pmid %s inst %d val %u\n",
+ pmIDStr(mdesc->m_desc.pmid), i, *ulp);
+ }
+#endif
+ }
+ }
+ }
+
+ if (mdesc->m_desc.units.dimTime == 1) {
+ /* sysinfo times are in ticks, and we export as 64-bit msec */
+ atom->ull = ull * 1000 / hz;
+ }
+ else if (mdesc->m_desc.type == PM_TYPE_U64) {
+ /* export as 64-bit value */
+ atom->ull = ull;
+ }
+ else {
+ /* else export as a 32-bit */
+ atom->ul = (__uint32_t)ull;
+ }
+
+ return 1;
+}