diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmdas/solaris/sysinfo.c | |
download | pcp-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.c | 376 |
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; +} |