/* * Copyright (C) [2004, 2005, 2006], Hyperic, Inc. * This file is part of SIGAR. * * SIGAR is free software; you can redistribute it and/or modify * it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. 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. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. */ #include "sigar.h" #include "sigar_private.h" #include "sigar_util.h" #include "sigar_os.h" int sigar_get_kstats(sigar_t *sigar) { kstat_ctl_t *kc = sigar->kc; unsigned int i, id, ncpu = sysconf(_SC_NPROCESSORS_CONF); int is_debug = SIGAR_LOG_IS_DEBUG(sigar); if (ncpu != sigar->ncpu) { if (!sigar->ks.lcpu) { /* init */ sigar->ks.lcpu = ncpu; sigar->ks.cpu = malloc(sizeof(*(sigar->ks.cpu)) * ncpu); sigar->ks.cpu_info = malloc(sizeof(*(sigar->ks.cpu_info)) * ncpu); sigar->ks.cpuid = malloc(sizeof(*(sigar->ks.cpuid)) * ncpu); } else { sigar_log_printf(sigar, SIGAR_LOG_INFO, "ncpu changed from %d to %d", sigar->ncpu, ncpu); if (ncpu > sigar->ks.lcpu) { /* one or more cpus have been added */ sigar->ks.cpu = realloc(sigar->ks.cpu, sizeof(*(sigar->ks.cpu)) * ncpu); sigar->ks.cpu_info = realloc(sigar->ks.cpu_info, sizeof(*(sigar->ks.cpu_info)) * ncpu); sigar->ks.cpuid = realloc(sigar->ks.cpuid, sizeof(*(sigar->ks.cpuid)) * ncpu); sigar->ks.lcpu = ncpu; } /* else or more cpus have been removed */ } sigar->ncpu = ncpu; /* from man p_online: * ``Processor numbers are integers, * greater than or equal to 0, * and are defined by the hardware platform. * Processor numbers are not necessarily contiguous, * but "not too sparse."`` * so we maintain our own mapping in ks.cpuid[] */ /* lookup in order, which kstat chain may not be in */ for (i=0, id=0; iks.cpu_info[i] = cpu_info; sigar->ks.cpu[i] = cpu_stat; sigar->ks.cpuid[i] = id; if (is_debug) { sigar_log_printf(sigar, SIGAR_LOG_DEBUG, "cpu %d id=%d", i, sigar->ks.cpuid[i]); } i++; } } sigar->ks.system = kstat_lookup(kc, "unix", -1, "system_misc"); sigar->ks.syspages = kstat_lookup(kc, "unix", -1, "system_pages"); sigar->ks.mempages = kstat_lookup(kc, "bunyip", -1, "mempages"); return SIGAR_OK; } SIGAR_INLINE kid_t sigar_kstat_update(sigar_t *sigar) { kid_t id = kstat_chain_update(sigar->kc); switch (id) { case -1: sigar_log_printf(sigar, SIGAR_LOG_ERROR, "kstat_chain_update error: %s", sigar_strerror(sigar, errno)); break; case 0: /* up-to-date */ break; default: sigar_get_kstats(sigar); sigar_log(sigar, SIGAR_LOG_DEBUG, "kstat chain updated"); break; } return id; } /* * bincompat is not possible with certain kstat data structures between * solaris 2.6, 2.7, 2.8, etc. alternative is to use kstat_data_lookup() * which means everytime we want a stat, must do a linear search * of ksp->ks_data. eek. so we meet half way and do the search for * each key once per sigar_t instance. once the initial search has * been done, we have a table of offsets to quickly access the stats via * ksp->ks_data + offset. this gives us bincompat without the overhead * of many kstat_data_lookup calls. */ static SIGAR_INLINE int kstat_named_offset(kstat_t *ksp, const char *name) { unsigned int i; kstat_named_t *kn; for (i=0, kn=ksp->ks_data; iks_ndata; i++, kn++) { if (strEQ(kn->name, name)) { return i; } } return -2; /* not found */ } static char *kstat_keys_system[] = { "boot_time", "avenrun_1min", "avenrun_5min", "avenrun_15min", NULL }; static char *kstat_keys_mempages[] = { "pages_anon", "pages_exec", "pages_vnode", NULL }; static char *kstat_keys_syspages[] = { "pagesfree", NULL }; static char **kstat_keys[] = { kstat_keys_system, kstat_keys_mempages, kstat_keys_syspages, }; void sigar_koffsets_lookup(kstat_t *ksp, int *offsets, int kidx) { int i; char **keys = kstat_keys[kidx]; for (i=0; keys[i]; i++) { offsets[i] = kstat_named_offset(ksp, keys[i]); } }