xref: /6.6.0/sigar/src/os/solaris/kstats.c (revision 42d0b984)
1/*
2 * Copyright (c) 2004-2007 Hyperic, Inc.
3 * Copyright (c) 2009 SpringSource, Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "sigar.h"
19#include "sigar_private.h"
20#include "sigar_util.h"
21#include "sigar_os.h"
22
23int sigar_get_kstats(sigar_t *sigar)
24{
25    kstat_ctl_t *kc = sigar->kc;
26    unsigned int i, id, ncpu = sysconf(_SC_NPROCESSORS_CONF);
27    int is_debug = SIGAR_LOG_IS_DEBUG(sigar);
28
29    if (ncpu != sigar->ncpu) {
30        if (!sigar->ks.lcpu) {
31            /* init */
32            sigar->ks.lcpu = ncpu;
33            sigar->ks.cpu = malloc(sizeof(*(sigar->ks.cpu)) * ncpu);
34            sigar->ks.cpu_info = malloc(sizeof(*(sigar->ks.cpu_info)) * ncpu);
35            sigar->ks.cpuid = malloc(sizeof(*(sigar->ks.cpuid)) * ncpu);
36        }
37        else {
38            sigar_log_printf(sigar, SIGAR_LOG_INFO,
39                             "ncpu changed from %d to %d",
40                             sigar->ncpu, ncpu);
41            if (ncpu > sigar->ks.lcpu) {
42                /* one or more cpus have been added */
43                sigar->ks.cpu = realloc(sigar->ks.cpu,
44                                        sizeof(*(sigar->ks.cpu)) * ncpu);
45                sigar->ks.cpu_info = realloc(sigar->ks.cpu_info,
46                                             sizeof(*(sigar->ks.cpu_info)) * ncpu);
47                sigar->ks.cpuid = realloc(sigar->ks.cpuid,
48                                          sizeof(*(sigar->ks.cpuid)) * ncpu);
49                sigar->ks.lcpu = ncpu;
50            }
51            /* else or more cpus have been removed */
52        }
53
54        sigar->ncpu = ncpu;
55
56        /* from man p_online:
57         * ``Processor numbers are integers,
58         *   greater than or equal to 0,
59         *   and are defined by the hardware platform.
60         *   Processor numbers are not necessarily contiguous,
61         *   but "not too sparse."``
62         * so we maintain our own mapping in ks.cpuid[]
63         */
64
65        /* lookup in order, which kstat chain may not be in */
66        for (i=0, id=0; i<ncpu; id++) {
67            kstat_t *cpu_info, *cpu_stat;
68
69            if (!(cpu_info = kstat_lookup(kc, "cpu_info", id, NULL))) {
70                continue;
71            }
72
73            if (!(cpu_stat = kstat_lookup(kc, "cpu_stat", id, NULL))) {
74                /* XXX warn, faulted cpu? */
75            }
76
77            sigar->ks.cpu_info[i] = cpu_info;
78            sigar->ks.cpu[i] = cpu_stat;
79            sigar->ks.cpuid[i] = id;
80
81            if (is_debug) {
82                sigar_log_printf(sigar, SIGAR_LOG_DEBUG,
83                                 "cpu %d id=%d", i, sigar->ks.cpuid[i]);
84            }
85            i++;
86        }
87    }
88
89    sigar->ks.system   = kstat_lookup(kc, "unix", -1, "system_misc");
90    sigar->ks.syspages = kstat_lookup(kc, "unix", -1, "system_pages");
91    sigar->ks.mempages = kstat_lookup(kc, "bunyip", -1, "mempages");
92
93    return SIGAR_OK;
94}
95
96 kid_t sigar_kstat_update(sigar_t *sigar)
97{
98    kid_t id = kstat_chain_update(sigar->kc);
99
100    switch (id) {
101      case -1:
102        sigar_log_printf(sigar, SIGAR_LOG_ERROR,
103                         "kstat_chain_update error: %s",
104                         sigar_strerror(sigar, errno));
105        break;
106      case 0:
107        /* up-to-date */
108        break;
109      default:
110        sigar_get_kstats(sigar);
111        sigar_log(sigar, SIGAR_LOG_DEBUG,
112                  "kstat chain updated");
113        break;
114    }
115
116    return id;
117}
118
119/*
120 * bincompat is not possible with certain kstat data structures between
121 * solaris 2.6, 2.7, 2.8, etc.  alternative is to use kstat_data_lookup()
122 * which means everytime we want a stat, must do a linear search
123 * of ksp->ks_data.  eek.  so we meet half way and do the search for
124 * each key once per sigar_t instance.  once the initial search has
125 * been done, we have a table of offsets to quickly access the stats via
126 * ksp->ks_data + offset.  this gives us bincompat without the overhead
127 * of many kstat_data_lookup calls.
128 */
129static  int kstat_named_offset(kstat_t *ksp, const char *name)
130{
131    unsigned int i;
132    kstat_named_t *kn;
133
134    for (i=0, kn=ksp->ks_data;
135         i<ksp->ks_ndata;
136         i++, kn++)
137    {
138        if (strEQ(kn->name, name)) {
139            return i;
140        }
141    }
142
143    return -2; /* not found */
144}
145
146static char *kstat_keys_system[] = {
147    "boot_time",
148    "avenrun_1min",
149    "avenrun_5min",
150    "avenrun_15min",
151    NULL
152};
153
154static char *kstat_keys_mempages[] = {
155    "pages_anon",
156    "pages_exec",
157    "pages_vnode",
158    NULL
159};
160
161static char *kstat_keys_syspages[] = {
162    "pagesfree",
163    NULL
164};
165
166static char **kstat_keys[] = {
167    kstat_keys_system,
168    kstat_keys_mempages,
169    kstat_keys_syspages,
170};
171
172void sigar_koffsets_lookup(kstat_t *ksp, int *offsets, int kidx)
173{
174    int i;
175    char **keys = kstat_keys[kidx];
176
177    for (i=0; keys[i]; i++) {
178        offsets[i] = kstat_named_offset(ksp, keys[i]);
179    }
180}
181