1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2014 Racktop Systems.
25 * Copyright 2016 Garrett D'Amore
26 */
27
28 /*
29 * Kstat.xs is a Perl XS (eXStension module) that makes the Solaris
30 * kstat(3KSTAT) facility available to Perl scripts. Kstat is a general-purpose
31 * mechanism for providing kernel statistics to users. The Solaris API is
32 * function-based (see the manpage for details), but for ease of use in Perl
33 * scripts this module presents the information as a nested hash data structure.
34 * It would be too inefficient to read every kstat in the system, so this module
35 * uses the Perl TIEHASH mechanism to implement a read-on-demand semantic, which
36 * only reads and updates kstats as and when they are actually accessed.
37 */
38
39 /*
40 * Ignored raw kstats.
41 *
42 * Some raw kstats are ignored by this module, these are listed below. The
43 * most common reason is that the kstats are stored as arrays and the ks_ndata
44 * and/or ks_data_size fields are invalid. In this case it is impossible to
45 * know how many records are in the array, so they can't be read.
46 *
47 * unix:*:sfmmu_percpu_stat
48 * This is stored as an array with one entry per cpu. Each element is of type
49 * struct sfmmu_percpu_stat. The ks_ndata and ks_data_size fields are bogus.
50 *
51 * ufs directio:*:UFS DirectIO Stats
52 * The structure definition used for these kstats (ufs_directio_kstats) is in a
53 * C file (uts/common/fs/ufs/ufs_directio.c) rather than a header file, so it
54 * isn't accessible.
55 *
56 * qlc:*:statistics
57 * This is a third-party driver for which we don't have source.
58 *
59 * mm:*:phys_installed
60 * This is stored as an array of uint64_t, with each pair of values being the
61 * (address, size) of a memory segment. The ks_ndata and ks_data_size fields
62 * are both zero.
63 *
64 * sockfs:*:sock_unix_list
65 * This is stored as an array with one entry per active socket. Each element
66 * is of type struct k_sockinfo. The ks_ndata and ks_data_size fields are both
67 * zero.
68 *
69 * Note that the ks_ndata and ks_data_size of many non-array raw kstats are
70 * also incorrect. The relevant assertions are therefore commented out in the
71 * appropriate raw kstat read routines.
72 */
73
74 /* Kstat related includes */
75 #include <libgen.h>
76 #include <kstat.h>
77 #include <sys/var.h>
78 #include <sys/utsname.h>
79 #include <sys/sysinfo.h>
80 #include <sys/flock.h>
81 #include <sys/dnlc.h>
82 #include <nfs/nfs.h>
83 #include <nfs/nfs_clnt.h>
84
85 /* Ultra-specific kstat includes */
86 #ifdef __sparc
87 #include <vm/hat_sfmmu.h> /* from /usr/platform/sun4u/include */
88 #include <sys/simmstat.h> /* from /usr/platform/sun4u/include */
89 #include <sys/sysctrl.h> /* from /usr/platform/sun4u/include */
90 #include <sys/fhc.h> /* from /usr/include */
91 #endif
92
93 /*
94 * Solaris #defines SP, which conflicts with the perl definition of SP
95 * We don't need the Solaris one, so get rid of it to avoid warnings
96 */
97 #undef SP
98
99 /* Perl XS includes */
100 #include "EXTERN.h"
101 #include "perl.h"
102 #include "XSUB.h"
103
104 /* Debug macros */
105 #define DEBUG_ID "Sun::Solaris::Kstat"
106 #ifdef KSTAT_DEBUG
107 #define PERL_ASSERT(EXP) \
108 ((void)((EXP) || (croak("%s: assertion failed at %s:%d: %s", \
109 DEBUG_ID, __FILE__, __LINE__, #EXP), 0), 0))
110 #define PERL_ASSERTMSG(EXP, MSG) \
111 ((void)((EXP) || (croak(DEBUG_ID ": " MSG), 0), 0))
112 #else
113 #define PERL_ASSERT(EXP) ((void)0)
114 #define PERL_ASSERTMSG(EXP, MSG) ((void)0)
115 #endif
116
117 /* Macros for saving the contents of KSTAT_RAW structures */
118 #if defined(HAS_QUAD) && defined(USE_64_BIT_INT)
119 #define NEW_IV(V) \
120 (newSViv((IVTYPE) V))
121 #define NEW_UV(V) \
122 (newSVuv((UVTYPE) V))
123 #else
124 #define NEW_IV(V) \
125 (V >= IV_MIN && V <= IV_MAX ? newSViv((IVTYPE) V) : newSVnv((NVTYPE) V))
126 #if defined(UVTYPE)
127 #define NEW_UV(V) \
128 (V <= UV_MAX ? newSVuv((UVTYPE) V) : newSVnv((NVTYPE) V))
129 # else
130 #define NEW_UV(V) \
131 (V <= IV_MAX ? newSViv((IVTYPE) V) : newSVnv((NVTYPE) V))
132 #endif
133 #endif
134 #define NEW_HRTIME(V) \
135 newSVnv((NVTYPE) (V / 1000000000.0))
136
137 #define SAVE_FNP(H, F, K) \
138 hv_store(H, K, sizeof (K) - 1, newSViv((IVTYPE)(uintptr_t)&F), 0)
139 #define SAVE_STRING(H, S, K, SS) \
140 hv_store(H, #K, sizeof (#K) - 1, \
141 newSVpvn(S->K, SS ? strlen(S->K) : sizeof(S->K)), 0)
142 #define SAVE_INT32(H, S, K) \
143 hv_store(H, #K, sizeof (#K) - 1, NEW_IV(S->K), 0)
144 #define SAVE_UINT32(H, S, K) \
145 hv_store(H, #K, sizeof (#K) - 1, NEW_UV(S->K), 0)
146 #define SAVE_INT64(H, S, K) \
147 hv_store(H, #K, sizeof (#K) - 1, NEW_IV(S->K), 0)
148 #define SAVE_UINT64(H, S, K) \
149 hv_store(H, #K, sizeof (#K) - 1, NEW_UV(S->K), 0)
150 #define SAVE_HRTIME(H, S, K) \
151 hv_store(H, #K, sizeof (#K) - 1, NEW_HRTIME(S->K), 0)
152
153 /* Private structure used for saving kstat info in the tied hashes */
154 typedef struct {
155 char read; /* Kstat block has been read before */
156 char valid; /* Kstat still exists in kstat chain */
157 char strip_str; /* Strip KSTAT_DATA_CHAR fields */
158 kstat_ctl_t *kstat_ctl; /* Handle returned by kstat_open */
159 kstat_t *kstat; /* Handle used by kstat_read */
160 } KstatInfo_t;
161
162 /* typedef for apply_to_ties callback functions */
163 typedef int (*ATTCb_t)(HV *, void *);
164
165 /* typedef for raw kstat reader functions */
166 typedef void (*kstat_raw_reader_t)(HV *, kstat_t *, int);
167
168 /* Hash of "module:name" to KSTAT_RAW read functions */
169 static HV *raw_kstat_lookup;
170
171 /*
172 * Kstats come in two flavours, named and raw. Raw kstats are just C structs,
173 * so we need a function per raw kstat to convert the C struct into the
174 * corresponding perl hash. All such conversion functions are in the following
175 * section.
176 */
177
178 /*
179 * Definitions in /usr/include/sys/cpuvar.h and /usr/include/sys/sysinfo.h
180 */
181
182 static void
183 save_cpu_stat(HV *self, kstat_t *kp, int strip_str)
184 {
185 cpu_stat_t *statp;
186 cpu_sysinfo_t *sysinfop;
187 cpu_syswait_t *syswaitp;
188 cpu_vminfo_t *vminfop;
189
190 /* PERL_ASSERT(kp->ks_ndata == 1); */
191 PERL_ASSERT(kp->ks_data_size == sizeof (cpu_stat_t));
192 statp = (cpu_stat_t *)(kp->ks_data);
193 sysinfop = &statp->cpu_sysinfo;
194 syswaitp = &statp->cpu_syswait;
195 vminfop = &statp->cpu_vminfo;
196
197 hv_store(self, "idle", 4, NEW_UV(sysinfop->cpu[CPU_IDLE]), 0);
198 hv_store(self, "user", 4, NEW_UV(sysinfop->cpu[CPU_USER]), 0);
199 hv_store(self, "kernel", 6, NEW_UV(sysinfop->cpu[CPU_KERNEL]), 0);
200 hv_store(self, "wait", 4, NEW_UV(sysinfop->cpu[CPU_WAIT]), 0);
201 hv_store(self, "wait_io", 7, NEW_UV(sysinfop->wait[W_IO]), 0);
202 hv_store(self, "wait_swap", 9, NEW_UV(sysinfop->wait[W_SWAP]), 0);
203 hv_store(self, "wait_pio", 8, NEW_UV(sysinfop->wait[W_PIO]), 0);
204 SAVE_UINT32(self, sysinfop, bread);
205 SAVE_UINT32(self, sysinfop, bwrite);
206 SAVE_UINT32(self, sysinfop, lread);
207 SAVE_UINT32(self, sysinfop, lwrite);
208 SAVE_UINT32(self, sysinfop, phread);
209 SAVE_UINT32(self, sysinfop, phwrite);
210 SAVE_UINT32(self, sysinfop, pswitch);
211 SAVE_UINT32(self, sysinfop, trap);
212 SAVE_UINT32(self, sysinfop, intr);
213 SAVE_UINT32(self, sysinfop, syscall);
214 SAVE_UINT32(self, sysinfop, sysread);
215 SAVE_UINT32(self, sysinfop, syswrite);
216 SAVE_UINT32(self, sysinfop, sysfork);
217 SAVE_UINT32(self, sysinfop, sysvfork);
218 SAVE_UINT32(self, sysinfop, sysexec);
219 SAVE_UINT32(self, sysinfop, readch);
220 SAVE_UINT32(self, sysinfop, writech);
221 SAVE_UINT32(self, sysinfop, rcvint);
222 SAVE_UINT32(self, sysinfop, xmtint);
223 SAVE_UINT32(self, sysinfop, mdmint);
224 SAVE_UINT32(self, sysinfop, rawch);
225 SAVE_UINT32(self, sysinfop, canch);
226 SAVE_UINT32(self, sysinfop, outch);
227 SAVE_UINT32(self, sysinfop, msg);
228 SAVE_UINT32(self, sysinfop, sema);
229 SAVE_UINT32(self, sysinfop, namei);
230 SAVE_UINT32(self, sysinfop, ufsiget);
231 SAVE_UINT32(self, sysinfop, ufsdirblk);
232 SAVE_UINT32(self, sysinfop, ufsipage);
233 SAVE_UINT32(self, sysinfop, ufsinopage);
234 SAVE_UINT32(self, sysinfop, inodeovf);
235 SAVE_UINT32(self, sysinfop, fileovf);
236 SAVE_UINT32(self, sysinfop, procovf);
237 SAVE_UINT32(self, sysinfop, intrthread);
238 SAVE_UINT32(self, sysinfop, intrblk);
239 SAVE_UINT32(self, sysinfop, idlethread);
240 SAVE_UINT32(self, sysinfop, inv_swtch);
241 SAVE_UINT32(self, sysinfop, nthreads);
242 SAVE_UINT32(self, sysinfop, cpumigrate);
243 SAVE_UINT32(self, sysinfop, xcalls);
244 SAVE_UINT32(self, sysinfop, mutex_adenters);
245 SAVE_UINT32(self, sysinfop, rw_rdfails);
246 SAVE_UINT32(self, sysinfop, rw_wrfails);
247 SAVE_UINT32(self, sysinfop, modload);
248 SAVE_UINT32(self, sysinfop, modunload);
249 SAVE_UINT32(self, sysinfop, bawrite);
250 #ifdef STATISTICS /* see header file */
251 SAVE_UINT32(self, sysinfop, rw_enters);
252 SAVE_UINT32(self, sysinfop, win_uo_cnt);
253 SAVE_UINT32(self, sysinfop, win_uu_cnt);
254 SAVE_UINT32(self, sysinfop, win_so_cnt);
255 SAVE_UINT32(self, sysinfop, win_su_cnt);
256 SAVE_UINT32(self, sysinfop, win_suo_cnt);
257 #endif
258
259 SAVE_INT32(self, syswaitp, iowait);
260 SAVE_INT32(self, syswaitp, swap);
261 SAVE_INT32(self, syswaitp, physio);
262
263 SAVE_UINT32(self, vminfop, pgrec);
264 SAVE_UINT32(self, vminfop, pgfrec);
265 SAVE_UINT32(self, vminfop, pgin);
266 SAVE_UINT32(self, vminfop, pgpgin);
267 SAVE_UINT32(self, vminfop, pgout);
268 SAVE_UINT32(self, vminfop, pgpgout);
269 SAVE_UINT32(self, vminfop, swapin);
270 SAVE_UINT32(self, vminfop, pgswapin);
271 SAVE_UINT32(self, vminfop, swapout);
272 SAVE_UINT32(self, vminfop, pgswapout);
273 SAVE_UINT32(self, vminfop, zfod);
274 SAVE_UINT32(self, vminfop, dfree);
275 SAVE_UINT32(self, vminfop, scan);
276 SAVE_UINT32(self, vminfop, rev);
277 SAVE_UINT32(self, vminfop, hat_fault);
278 SAVE_UINT32(self, vminfop, as_fault);
279 SAVE_UINT32(self, vminfop, maj_fault);
280 SAVE_UINT32(self, vminfop, cow_fault);
281 SAVE_UINT32(self, vminfop, prot_fault);
282 SAVE_UINT32(self, vminfop, softlock);
283 SAVE_UINT32(self, vminfop, kernel_asflt);
284 SAVE_UINT32(self, vminfop, pgrrun);
285 SAVE_UINT32(self, vminfop, execpgin);
286 SAVE_UINT32(self, vminfop, execpgout);
287 SAVE_UINT32(self, vminfop, execfree);
288 SAVE_UINT32(self, vminfop, anonpgin);
289 SAVE_UINT32(self, vminfop, anonpgout);
290 SAVE_UINT32(self, vminfop, anonfree);
291 SAVE_UINT32(self, vminfop, fspgin);
292 SAVE_UINT32(self, vminfop, fspgout);
293 SAVE_UINT32(self, vminfop, fsfree);
294 }
295
296 /*
297 * Definitions in /usr/include/sys/var.h
298 */
299
300 static void
301 save_var(HV *self, kstat_t *kp, int strip_str)
302 {
303 struct var *varp;
304
305 /* PERL_ASSERT(kp->ks_ndata == 1); */
306 PERL_ASSERT(kp->ks_data_size == sizeof (struct var));
307 varp = (struct var *)(kp->ks_data);
308
309 SAVE_INT32(self, varp, v_buf);
310 SAVE_INT32(self, varp, v_call);
311 SAVE_INT32(self, varp, v_proc);
312 SAVE_INT32(self, varp, v_maxupttl);
313 SAVE_INT32(self, varp, v_nglobpris);
314 SAVE_INT32(self, varp, v_maxsyspri);
315 SAVE_INT32(self, varp, v_clist);
316 SAVE_INT32(self, varp, v_maxup);
317 SAVE_INT32(self, varp, v_hbuf);
318 SAVE_INT32(self, varp, v_hmask);
319 SAVE_INT32(self, varp, v_pbuf);
320 SAVE_INT32(self, varp, v_sptmap);
321 SAVE_INT32(self, varp, v_maxpmem);
322 SAVE_INT32(self, varp, v_autoup);
323 SAVE_INT32(self, varp, v_bufhwm);
324 }
325
326 /*
327 * Definition in /usr/include/sys/dnlc.h
328 */
329
330 static void
331 save_ncstats(HV *self, kstat_t *kp, int strip_str)
332 {
333 struct ncstats *ncstatsp;
334
335 /* PERL_ASSERT(kp->ks_ndata == 1); */
336 PERL_ASSERT(kp->ks_data_size == sizeof (struct ncstats));
337 ncstatsp = (struct ncstats *)(kp->ks_data);
338
339 SAVE_INT32(self, ncstatsp, hits);
340 SAVE_INT32(self, ncstatsp, misses);
341 SAVE_INT32(self, ncstatsp, enters);
342 SAVE_INT32(self, ncstatsp, dbl_enters);
343 SAVE_INT32(self, ncstatsp, long_enter);
344 SAVE_INT32(self, ncstatsp, long_look);
345 SAVE_INT32(self, ncstatsp, move_to_front);
346 SAVE_INT32(self, ncstatsp, purges);
347 }
348
349 /*
350 * Definition in /usr/include/sys/sysinfo.h
351 */
352
353 static void
354 save_sysinfo(HV *self, kstat_t *kp, int strip_str)
355 {
356 sysinfo_t *sysinfop;
357
358 /* PERL_ASSERT(kp->ks_ndata == 1); */
359 PERL_ASSERT(kp->ks_data_size == sizeof (sysinfo_t));
360 sysinfop = (sysinfo_t *)(kp->ks_data);
361
362 SAVE_UINT32(self, sysinfop, updates);
363 SAVE_UINT32(self, sysinfop, runque);
364 SAVE_UINT32(self, sysinfop, runocc);
365 SAVE_UINT32(self, sysinfop, swpque);
366 SAVE_UINT32(self, sysinfop, swpocc);
367 SAVE_UINT32(self, sysinfop, waiting);
368 }
369
370 /*
371 * Definition in /usr/include/sys/sysinfo.h
372 */
373
374 static void
375 save_vminfo(HV *self, kstat_t *kp, int strip_str)
376 {
377 vminfo_t *vminfop;
378
379 /* PERL_ASSERT(kp->ks_ndata == 1); */
380 PERL_ASSERT(kp->ks_data_size == sizeof (vminfo_t));
381 vminfop = (vminfo_t *)(kp->ks_data);
382
383 SAVE_UINT64(self, vminfop, freemem);
384 SAVE_UINT64(self, vminfop, swap_resv);
385 SAVE_UINT64(self, vminfop, swap_alloc);
386 SAVE_UINT64(self, vminfop, swap_avail);
387 SAVE_UINT64(self, vminfop, swap_free);
388 SAVE_UINT64(self, vminfop, updates);
389 }
390
391 /*
392 * Definition in /usr/include/nfs/nfs_clnt.h
393 */
394
395 static void
396 save_nfs(HV *self, kstat_t *kp, int strip_str)
397 {
398 struct mntinfo_kstat *mntinfop;
399
400 /* PERL_ASSERT(kp->ks_ndata == 1); */
401 PERL_ASSERT(kp->ks_data_size == sizeof (struct mntinfo_kstat));
402 mntinfop = (struct mntinfo_kstat *)(kp->ks_data);
403
404 SAVE_STRING(self, mntinfop, mik_proto, strip_str);
405 SAVE_UINT32(self, mntinfop, mik_vers);
406 SAVE_UINT32(self, mntinfop, mik_flags);
407 SAVE_UINT32(self, mntinfop, mik_secmod);
408 SAVE_UINT32(self, mntinfop, mik_curread);
409 SAVE_UINT32(self, mntinfop, mik_curwrite);
410 SAVE_INT32(self, mntinfop, mik_timeo);
411 SAVE_INT32(self, mntinfop, mik_retrans);
412 SAVE_UINT32(self, mntinfop, mik_acregmin);
413 SAVE_UINT32(self, mntinfop, mik_acregmax);
414 SAVE_UINT32(self, mntinfop, mik_acdirmin);
415 SAVE_UINT32(self, mntinfop, mik_acdirmax);
416 hv_store(self, "lookup_srtt", 11,
417 NEW_UV(mntinfop->mik_timers[0].srtt), 0);
418 hv_store(self, "lookup_deviate", 14,
419 NEW_UV(mntinfop->mik_timers[0].deviate), 0);
420 hv_store(self, "lookup_rtxcur", 13,
421 NEW_UV(mntinfop->mik_timers[0].rtxcur), 0);
422 hv_store(self, "read_srtt", 9,
423 NEW_UV(mntinfop->mik_timers[1].srtt), 0);
424 hv_store(self, "read_deviate", 12,
425 NEW_UV(mntinfop->mik_timers[1].deviate), 0);
426 hv_store(self, "read_rtxcur", 11,
427 NEW_UV(mntinfop->mik_timers[1].rtxcur), 0);
428 hv_store(self, "write_srtt", 10,
429 NEW_UV(mntinfop->mik_timers[2].srtt), 0);
430 hv_store(self, "write_deviate", 13,
431 NEW_UV(mntinfop->mik_timers[2].deviate), 0);
432 hv_store(self, "write_rtxcur", 12,
433 NEW_UV(mntinfop->mik_timers[2].rtxcur), 0);
434 SAVE_UINT32(self, mntinfop, mik_noresponse);
435 SAVE_UINT32(self, mntinfop, mik_failover);
436 SAVE_UINT32(self, mntinfop, mik_remap);
437 SAVE_STRING(self, mntinfop, mik_curserver, strip_str);
438 }
439
440 /*
441 * The following struct => hash functions are all only present on the sparc
442 * platform, so they are all conditionally compiled depending on __sparc
443 */
444
445 /*
446 * Definition in /usr/platform/sun4u/include/vm/hat_sfmmu.h
447 */
448
449 #ifdef __sparc
450 static void
451 save_sfmmu_global_stat(HV *self, kstat_t *kp, int strip_str)
452 {
453 struct sfmmu_global_stat *sfmmugp;
454
455 /* PERL_ASSERT(kp->ks_ndata == 1); */
456 PERL_ASSERT(kp->ks_data_size == sizeof (struct sfmmu_global_stat));
457 sfmmugp = (struct sfmmu_global_stat *)(kp->ks_data);
458
459 SAVE_INT32(self, sfmmugp, sf_tsb_exceptions);
460 SAVE_INT32(self, sfmmugp, sf_tsb_raise_exception);
461 SAVE_INT32(self, sfmmugp, sf_pagefaults);
462 SAVE_INT32(self, sfmmugp, sf_uhash_searches);
463 SAVE_INT32(self, sfmmugp, sf_uhash_links);
464 SAVE_INT32(self, sfmmugp, sf_khash_searches);
465 SAVE_INT32(self, sfmmugp, sf_khash_links);
466 SAVE_INT32(self, sfmmugp, sf_swapout);
467 SAVE_INT32(self, sfmmugp, sf_tsb_alloc);
468 SAVE_INT32(self, sfmmugp, sf_tsb_allocfail);
469 SAVE_INT32(self, sfmmugp, sf_tsb_sectsb_create);
470 SAVE_INT32(self, sfmmugp, sf_scd_1sttsb_alloc);
471 SAVE_INT32(self, sfmmugp, sf_scd_2ndtsb_alloc);
472 SAVE_INT32(self, sfmmugp, sf_scd_1sttsb_allocfail);
473 SAVE_INT32(self, sfmmugp, sf_scd_2ndtsb_allocfail);
474 SAVE_INT32(self, sfmmugp, sf_tteload8k);
475 SAVE_INT32(self, sfmmugp, sf_tteload64k);
476 SAVE_INT32(self, sfmmugp, sf_tteload512k);
477 SAVE_INT32(self, sfmmugp, sf_tteload4m);
478 SAVE_INT32(self, sfmmugp, sf_tteload32m);
479 SAVE_INT32(self, sfmmugp, sf_tteload256m);
480 SAVE_INT32(self, sfmmugp, sf_tsb_load8k);
481 SAVE_INT32(self, sfmmugp, sf_tsb_load4m);
482 SAVE_INT32(self, sfmmugp, sf_hblk_hit);
483 SAVE_INT32(self, sfmmugp, sf_hblk8_ncreate);
484 SAVE_INT32(self, sfmmugp, sf_hblk8_nalloc);
485 SAVE_INT32(self, sfmmugp, sf_hblk1_ncreate);
486 SAVE_INT32(self, sfmmugp, sf_hblk1_nalloc);
487 SAVE_INT32(self, sfmmugp, sf_hblk_slab_cnt);
488 SAVE_INT32(self, sfmmugp, sf_hblk_reserve_cnt);
489 SAVE_INT32(self, sfmmugp, sf_hblk_recurse_cnt);
490 SAVE_INT32(self, sfmmugp, sf_hblk_reserve_hit);
491 SAVE_INT32(self, sfmmugp, sf_get_free_success);
492 SAVE_INT32(self, sfmmugp, sf_get_free_throttle);
493 SAVE_INT32(self, sfmmugp, sf_get_free_fail);
494 SAVE_INT32(self, sfmmugp, sf_put_free_success);
495 SAVE_INT32(self, sfmmugp, sf_put_free_fail);
496 SAVE_INT32(self, sfmmugp, sf_pgcolor_conflict);
497 SAVE_INT32(self, sfmmugp, sf_uncache_conflict);
498 SAVE_INT32(self, sfmmugp, sf_unload_conflict);
499 SAVE_INT32(self, sfmmugp, sf_ism_uncache);
500 SAVE_INT32(self, sfmmugp, sf_ism_recache);
501 SAVE_INT32(self, sfmmugp, sf_recache);
502 SAVE_INT32(self, sfmmugp, sf_steal_count);
503 SAVE_INT32(self, sfmmugp, sf_pagesync);
504 SAVE_INT32(self, sfmmugp, sf_clrwrt);
505 SAVE_INT32(self, sfmmugp, sf_pagesync_invalid);
506 SAVE_INT32(self, sfmmugp, sf_kernel_xcalls);
507 SAVE_INT32(self, sfmmugp, sf_user_xcalls);
508 SAVE_INT32(self, sfmmugp, sf_tsb_grow);
509 SAVE_INT32(self, sfmmugp, sf_tsb_shrink);
510 SAVE_INT32(self, sfmmugp, sf_tsb_resize_failures);
511 SAVE_INT32(self, sfmmugp, sf_tsb_reloc);
512 SAVE_INT32(self, sfmmugp, sf_user_vtop);
513 SAVE_INT32(self, sfmmugp, sf_ctx_inv);
514 SAVE_INT32(self, sfmmugp, sf_tlb_reprog_pgsz);
515 SAVE_INT32(self, sfmmugp, sf_region_remap_demap);
516 SAVE_INT32(self, sfmmugp, sf_create_scd);
517 SAVE_INT32(self, sfmmugp, sf_join_scd);
518 SAVE_INT32(self, sfmmugp, sf_leave_scd);
519 SAVE_INT32(self, sfmmugp, sf_destroy_scd);
520 }
521 #endif
522
523 /*
524 * Definition in /usr/platform/sun4u/include/vm/hat_sfmmu.h
525 */
526
527 #ifdef __sparc
528 static void
529 save_sfmmu_tsbsize_stat(HV *self, kstat_t *kp, int strip_str)
530 {
531 struct sfmmu_tsbsize_stat *sfmmutp;
532
533 /* PERL_ASSERT(kp->ks_ndata == 1); */
534 PERL_ASSERT(kp->ks_data_size == sizeof (struct sfmmu_tsbsize_stat));
535 sfmmutp = (struct sfmmu_tsbsize_stat *)(kp->ks_data);
536
537 SAVE_INT32(self, sfmmutp, sf_tsbsz_8k);
538 SAVE_INT32(self, sfmmutp, sf_tsbsz_16k);
539 SAVE_INT32(self, sfmmutp, sf_tsbsz_32k);
540 SAVE_INT32(self, sfmmutp, sf_tsbsz_64k);
541 SAVE_INT32(self, sfmmutp, sf_tsbsz_128k);
542 SAVE_INT32(self, sfmmutp, sf_tsbsz_256k);
543 SAVE_INT32(self, sfmmutp, sf_tsbsz_512k);
544 SAVE_INT32(self, sfmmutp, sf_tsbsz_1m);
545 SAVE_INT32(self, sfmmutp, sf_tsbsz_2m);
546 SAVE_INT32(self, sfmmutp, sf_tsbsz_4m);
547 }
548 #endif
549
550 /*
551 * Definition in /usr/platform/sun4u/include/sys/simmstat.h
552 */
553
554 #ifdef __sparc
555 static void
556 save_simmstat(HV *self, kstat_t *kp, int strip_str)
557 {
558 uchar_t *simmstatp;
559 SV *list;
560 int i;
561
562 /* PERL_ASSERT(kp->ks_ndata == 1); */
563 PERL_ASSERT(kp->ks_data_size == sizeof (uchar_t) * SIMM_COUNT);
564
565 list = newSVpv("", 0);
566 for (i = 0, simmstatp = (uchar_t *)(kp->ks_data);
567 i < SIMM_COUNT - 1; i++, simmstatp++) {
568 sv_catpvf(list, "%d,", *simmstatp);
569 }
570 sv_catpvf(list, "%d", *simmstatp);
571 hv_store(self, "status", 6, list, 0);
572 }
573 #endif
574
575 /*
576 * Used by save_temperature to make CSV lists from arrays of
577 * short temperature values
578 */
579
580 #ifdef __sparc
581 static SV *
582 short_array_to_SV(short *shortp, int len)
583 {
584 SV *list;
585
586 list = newSVpv("", 0);
587 for (; len > 1; len--, shortp++) {
588 sv_catpvf(list, "%d,", *shortp);
589 }
590 sv_catpvf(list, "%d", *shortp);
591 return (list);
592 }
593
594 /*
595 * Definition in /usr/platform/sun4u/include/sys/fhc.h
596 */
597
598 static void
599 save_temperature(HV *self, kstat_t *kp, int strip_str)
600 {
601 struct temp_stats *tempsp;
602
603 /* PERL_ASSERT(kp->ks_ndata == 1); */
604 PERL_ASSERT(kp->ks_data_size == sizeof (struct temp_stats));
605 tempsp = (struct temp_stats *)(kp->ks_data);
606
607 SAVE_UINT32(self, tempsp, index);
608 hv_store(self, "l1", 2, short_array_to_SV(tempsp->l1, L1_SZ), 0);
609 hv_store(self, "l2", 2, short_array_to_SV(tempsp->l2, L2_SZ), 0);
610 hv_store(self, "l3", 2, short_array_to_SV(tempsp->l3, L3_SZ), 0);
611 hv_store(self, "l4", 2, short_array_to_SV(tempsp->l4, L4_SZ), 0);
612 hv_store(self, "l5", 2, short_array_to_SV(tempsp->l5, L5_SZ), 0);
613 SAVE_INT32(self, tempsp, max);
614 SAVE_INT32(self, tempsp, min);
615 SAVE_INT32(self, tempsp, state);
616 SAVE_INT32(self, tempsp, temp_cnt);
617 SAVE_INT32(self, tempsp, shutdown_cnt);
618 SAVE_INT32(self, tempsp, version);
619 SAVE_INT32(self, tempsp, trend);
620 SAVE_INT32(self, tempsp, override);
621 }
622 #endif
623
624 /*
625 * Not actually defined anywhere - just a short. Yuck.
626 */
627
628 #ifdef __sparc
629 static void
630 save_temp_over(HV *self, kstat_t *kp, int strip_str)
631 {
632 short *shortp;
633
634 /* PERL_ASSERT(kp->ks_ndata == 1); */
635 PERL_ASSERT(kp->ks_data_size == sizeof (short));
636
637 shortp = (short *)(kp->ks_data);
638 hv_store(self, "override", 8, newSViv(*shortp), 0);
639 }
640 #endif
641
642 /*
643 * Defined in /usr/platform/sun4u/include/sys/sysctrl.h
644 * (Well, sort of. Actually there's no structure, just a list of #defines
645 * enumerating *some* of the array indexes.)
646 */
647
648 #ifdef __sparc
649 static void
650 save_ps_shadow(HV *self, kstat_t *kp, int strip_str)
651 {
652 uchar_t *ucharp;
653
654 /* PERL_ASSERT(kp->ks_ndata == 1); */
655 PERL_ASSERT(kp->ks_data_size == SYS_PS_COUNT);
656
657 ucharp = (uchar_t *)(kp->ks_data);
658 hv_store(self, "core_0", 6, newSViv(*ucharp++), 0);
659 hv_store(self, "core_1", 6, newSViv(*ucharp++), 0);
660 hv_store(self, "core_2", 6, newSViv(*ucharp++), 0);
661 hv_store(self, "core_3", 6, newSViv(*ucharp++), 0);
662 hv_store(self, "core_4", 6, newSViv(*ucharp++), 0);
663 hv_store(self, "core_5", 6, newSViv(*ucharp++), 0);
664 hv_store(self, "core_6", 6, newSViv(*ucharp++), 0);
665 hv_store(self, "core_7", 6, newSViv(*ucharp++), 0);
666 hv_store(self, "pps_0", 5, newSViv(*ucharp++), 0);
667 hv_store(self, "clk_33", 6, newSViv(*ucharp++), 0);
668 hv_store(self, "clk_50", 6, newSViv(*ucharp++), 0);
669 hv_store(self, "v5_p", 4, newSViv(*ucharp++), 0);
670 hv_store(self, "v12_p", 5, newSViv(*ucharp++), 0);
671 hv_store(self, "v5_aux", 6, newSViv(*ucharp++), 0);
672 hv_store(self, "v5_p_pch", 8, newSViv(*ucharp++), 0);
673 hv_store(self, "v12_p_pch", 9, newSViv(*ucharp++), 0);
674 hv_store(self, "v3_pch", 6, newSViv(*ucharp++), 0);
675 hv_store(self, "v5_pch", 6, newSViv(*ucharp++), 0);
676 hv_store(self, "p_fan", 5, newSViv(*ucharp++), 0);
677 }
678 #endif
679
680 /*
681 * Definition in /usr/platform/sun4u/include/sys/fhc.h
682 */
683
684 #ifdef __sparc
685 static void
686 save_fault_list(HV *self, kstat_t *kp, int strip_str)
687 {
688 struct ft_list *faultp;
689 int i;
690 char name[KSTAT_STRLEN + 7]; /* room for 999999 faults */
691
692 /* PERL_ASSERT(kp->ks_ndata == 1); */
693 /* PERL_ASSERT(kp->ks_data_size == sizeof (struct ft_list)); */
694
695 for (i = 1, faultp = (struct ft_list *)(kp->ks_data);
696 i <= 999999 && i <= kp->ks_data_size / sizeof (struct ft_list);
697 i++, faultp++) {
698 (void) snprintf(name, sizeof (name), "unit_%d", i);
699 hv_store(self, name, strlen(name), newSViv(faultp->unit), 0);
700 (void) snprintf(name, sizeof (name), "type_%d", i);
701 hv_store(self, name, strlen(name), newSViv(faultp->type), 0);
702 (void) snprintf(name, sizeof (name), "fclass_%d", i);
703 hv_store(self, name, strlen(name), newSViv(faultp->fclass), 0);
704 (void) snprintf(name, sizeof (name), "create_time_%d", i);
705 hv_store(self, name, strlen(name),
706 NEW_UV(faultp->create_time), 0);
707 (void) snprintf(name, sizeof (name), "msg_%d", i);
708 hv_store(self, name, strlen(name), newSVpv(faultp->msg, 0), 0);
709 }
710 }
711 #endif
712
713 /*
714 * We need to be able to find the function corresponding to a particular raw
715 * kstat. To do this we ignore the instance and glue the module and name
716 * together to form a composite key. We can then use the data in the kstat
717 * structure to find the appropriate function. We use a perl hash to manage the
718 * lookup, where the key is "module:name" and the value is a pointer to the
719 * appropriate C function.
720 *
721 * Note that some kstats include the instance number as part of the module
722 * and/or name. This could be construed as a bug. However, to work around this
723 * we omit any digits from the module and name as we build the table in
724 * build_raw_kstat_loopup(), and we remove any digits from the module and name
725 * when we look up the functions in lookup_raw_kstat_fn()
726 */
727
728 /*
729 * This function is called when the XS is first dlopen()ed, and builds the
730 * lookup table as described above.
731 */
732
733 static void
734 build_raw_kstat_lookup()
735 {
736 /* Create new hash */
737 raw_kstat_lookup = newHV();
738
739 SAVE_FNP(raw_kstat_lookup, save_cpu_stat, "cpu_stat:cpu_stat");
740 SAVE_FNP(raw_kstat_lookup, save_var, "unix:var");
741 SAVE_FNP(raw_kstat_lookup, save_ncstats, "unix:ncstats");
742 SAVE_FNP(raw_kstat_lookup, save_sysinfo, "unix:sysinfo");
743 SAVE_FNP(raw_kstat_lookup, save_vminfo, "unix:vminfo");
744 SAVE_FNP(raw_kstat_lookup, save_nfs, "nfs:mntinfo");
745 #ifdef __sparc
746 SAVE_FNP(raw_kstat_lookup, save_sfmmu_global_stat,
747 "unix:sfmmu_global_stat");
748 SAVE_FNP(raw_kstat_lookup, save_sfmmu_tsbsize_stat,
749 "unix:sfmmu_tsbsize_stat");
750 SAVE_FNP(raw_kstat_lookup, save_simmstat, "unix:simm-status");
751 SAVE_FNP(raw_kstat_lookup, save_temperature, "unix:temperature");
752 SAVE_FNP(raw_kstat_lookup, save_temp_over, "unix:temperature override");
753 SAVE_FNP(raw_kstat_lookup, save_ps_shadow, "unix:ps_shadow");
754 SAVE_FNP(raw_kstat_lookup, save_fault_list, "unix:fault_list");
755 #endif
756 }
757
758 /*
759 * This finds and returns the raw kstat reader function corresponding to the
760 * supplied module and name. If no matching function exists, 0 is returned.
761 */
762
763 static kstat_raw_reader_t lookup_raw_kstat_fn(char *module, char *name)
764 {
765 char key[KSTAT_STRLEN * 2];
766 register char *f, *t;
767 SV **entry;
768 kstat_raw_reader_t fnp;
769
770 /* Copy across module & name, removing any digits - see comment above */
771 for (f = module, t = key; *f != '\0'; f++, t++) {
772 while (*f != '\0' && isdigit(*f)) { f++; }
773 *t = *f;
774 }
775 *t++ = ':';
776 for (f = name; *f != '\0'; f++, t++) {
777 while (*f != '\0' && isdigit(*f)) {
778 f++;
779 }
780 *t = *f;
781 }
782 *t = '\0';
783
784 /* look up & return the function, or teturn 0 if not found */
785 if ((entry = hv_fetch(raw_kstat_lookup, key, strlen(key), FALSE)) == 0)
786 {
787 fnp = 0;
788 } else {
789 fnp = (kstat_raw_reader_t)(uintptr_t)SvIV(*entry);
790 }
791 return (fnp);
792 }
793
794 /*
795 * This module converts the flat list returned by kstat_read() into a perl hash
796 * tree keyed on module, instance, name and statistic. The following functions
797 * provide code to create the nested hashes, and to iterate over them.
798 */
799
800 /*
801 * Given module, instance and name keys return a pointer to the hash tied to
802 * the bottommost hash. If the hash already exists, we just return a pointer
803 * to it, otherwise we create the hash and any others also required above it in
804 * the hierarchy. The returned tiehash is blessed into the
805 * Sun::Solaris::Kstat::_Stat class, so that the appropriate TIEHASH methods are
806 * called when the bottommost hash is accessed. If the is_new parameter is
807 * non-null it will be set to TRUE if a new tie has been created, and FALSE if
808 * the tie already existed.
809 */
810
811 static HV *
812 get_tie(SV *self, char *module, int instance, char *name, int *is_new)
813 {
814 char str_inst[11]; /* big enough for up to 10^10 instances */
815 char *key[3]; /* 3 part key: module, instance, name */
816 int k;
817 int new;
818 HV *hash;
819 HV *tie;
820
821 /* Create the keys */
822 (void) snprintf(str_inst, sizeof (str_inst), "%d", instance);
823 key[0] = module;
824 key[1] = str_inst;
825 key[2] = name;
826
827 /* Iteratively descend the tree, creating new hashes as required */
828 hash = (HV *)SvRV(self);
829 for (k = 0; k < 3; k++) {
830 SV **entry;
831
832 SvREADONLY_off(hash);
833 entry = hv_fetch(hash, key[k], strlen(key[k]), TRUE);
834
835 /* If the entry doesn't exist, create it */
836 if (! SvOK(*entry)) {
837 HV *newhash;
838 SV *rv;
839
840 newhash = newHV();
841 rv = newRV_noinc((SV *)newhash);
842 sv_setsv(*entry, rv);
843 SvREFCNT_dec(rv);
844 if (k < 2) {
845 SvREADONLY_on(newhash);
846 }
847 SvREADONLY_on(*entry);
848 SvREADONLY_on(hash);
849 hash = newhash;
850 new = 1;
851
852 /* Otherwise it already existed */
853 } else {
854 SvREADONLY_on(hash);
855 hash = (HV *)SvRV(*entry);
856 new = 0;
857 }
858 }
859
860 /* Create and bless a hash for the tie, if necessary */
861 if (new) {
862 SV *tieref;
863 HV *stash;
864
865 tie = newHV();
866 tieref = newRV_noinc((SV *)tie);
867 stash = gv_stashpv("Sun::Solaris::Kstat::_Stat", TRUE);
868 sv_bless(tieref, stash);
869
870 /* Add TIEHASH magic */
871 hv_magic(hash, (GV *)tieref, 'P');
872 SvREADONLY_on(hash);
873
874 /* Otherwise, just find the existing tied hash */
875 } else {
876 MAGIC *mg;
877
878 mg = mg_find((SV *)hash, 'P');
879 PERL_ASSERTMSG(mg != 0, "get_tie: lost P magic");
880 tie = (HV *)SvRV(mg->mg_obj);
881 }
882 if (is_new) {
883 *is_new = new;
884 }
885 return (tie);
886 }
887
888 /*
889 * This is an iterator function used to traverse the hash hierarchy and apply
890 * the passed function to the tied hashes at the bottom of the hierarchy. If
891 * any of the callback functions return 0, 0 is returned, otherwise 1
892 */
893
894 static int
895 apply_to_ties(SV *self, ATTCb_t cb, void *arg)
896 {
897 HV *hash1;
898 HE *entry1;
899 int ret;
900
901 hash1 = (HV *)SvRV(self);
902 hv_iterinit(hash1);
903 ret = 1;
904
905 /* Iterate over each module */
906 while ((entry1 = hv_iternext(hash1))) {
907 HV *hash2;
908 HE *entry2;
909
910 hash2 = (HV *)SvRV(hv_iterval(hash1, entry1));
911 hv_iterinit(hash2);
912
913 /* Iterate over each module:instance */
914 while ((entry2 = hv_iternext(hash2))) {
915 HV *hash3;
916 HE *entry3;
917
918 hash3 = (HV *)SvRV(hv_iterval(hash2, entry2));
919 hv_iterinit(hash3);
920
921 /* Iterate over each module:instance:name */
922 while ((entry3 = hv_iternext(hash3))) {
923 HV *hash4;
924 MAGIC *mg;
925
926 /* Get the tie */
927 hash4 = (HV *)SvRV(hv_iterval(hash3, entry3));
928 mg = mg_find((SV *)hash4, 'P');
929 PERL_ASSERTMSG(mg != 0,
930 "apply_to_ties: lost P magic");
931
932 /* Apply the callback */
933 if (! cb((HV *)SvRV(mg->mg_obj), arg)) {
934 ret = 0;
935 }
936 }
937 }
938 }
939 return (ret);
940 }
941
942 /*
943 * Mark this HV as valid - used by update() when pruning deleted kstat nodes
944 */
945
946 static int
947 set_valid(HV *self, void *arg)
948 {
949 MAGIC *mg;
950
951 mg = mg_find((SV *)self, '~');
952 PERL_ASSERTMSG(mg != 0, "set_valid: lost ~ magic");
953 ((KstatInfo_t *)SvPVX(mg->mg_obj))->valid = (int)(intptr_t)arg;
954 return (1);
955 }
956
957 /*
958 * Prune invalid kstat nodes. This is called when kstat_chain_update() detects
959 * that the kstat chain has been updated. This removes any hash tree entries
960 * that no longer have a corresponding kstat. If del is non-null it will be
961 * set to the keys of the deleted kstat nodes, if any. If any entries are
962 * deleted 1 will be retured, otherwise 0
963 */
964
965 static int
966 prune_invalid(SV *self, AV *del)
967 {
968 HV *hash1;
969 HE *entry1;
970 STRLEN klen;
971 char *module, *instance, *name, *key;
972 int ret;
973
974 hash1 = (HV *)SvRV(self);
975 hv_iterinit(hash1);
976 ret = 0;
977
978 /* Iterate over each module */
979 while ((entry1 = hv_iternext(hash1))) {
980 HV *hash2;
981 HE *entry2;
982
983 module = HePV(entry1, PL_na);
984 hash2 = (HV *)SvRV(hv_iterval(hash1, entry1));
985 hv_iterinit(hash2);
986
987 /* Iterate over each module:instance */
988 while ((entry2 = hv_iternext(hash2))) {
989 HV *hash3;
990 HE *entry3;
991
992 instance = HePV(entry2, PL_na);
993 hash3 = (HV *)SvRV(hv_iterval(hash2, entry2));
994 hv_iterinit(hash3);
995
996 /* Iterate over each module:instance:name */
997 while ((entry3 = hv_iternext(hash3))) {
998 HV *hash4;
999 MAGIC *mg;
1000 HV *tie;
1001
1002 name = HePV(entry3, PL_na);
1003 hash4 = (HV *)SvRV(hv_iterval(hash3, entry3));
1004 mg = mg_find((SV *)hash4, 'P');
1005 PERL_ASSERTMSG(mg != 0,
1006 "prune_invalid: lost P magic");
1007 tie = (HV *)SvRV(mg->mg_obj);
1008 mg = mg_find((SV *)tie, '~');
1009 PERL_ASSERTMSG(mg != 0,
1010 "prune_invalid: lost ~ magic");
1011
1012 /* If this is marked as invalid, prune it */
1013 if (((KstatInfo_t *)SvPVX(
1014 (SV *)mg->mg_obj))->valid == FALSE) {
1015 SvREADONLY_off(hash3);
1016 key = HePV(entry3, klen);
1017 hv_delete(hash3, key, klen, G_DISCARD);
1018 SvREADONLY_on(hash3);
1019 if (del) {
1020 av_push(del,
1021 newSVpvf("%s:%s:%s",
1022 module, instance, name));
1023 }
1024 ret = 1;
1025 }
1026 }
1027
1028 /* If the module:instance:name hash is empty prune it */
1029 if (HvKEYS(hash3) == 0) {
1030 SvREADONLY_off(hash2);
1031 key = HePV(entry2, klen);
1032 hv_delete(hash2, key, klen, G_DISCARD);
1033 SvREADONLY_on(hash2);
1034 }
1035 }
1036 /* If the module:instance hash is empty prune it */
1037 if (HvKEYS(hash2) == 0) {
1038 SvREADONLY_off(hash1);
1039 key = HePV(entry1, klen);
1040 hv_delete(hash1, key, klen, G_DISCARD);
1041 SvREADONLY_on(hash1);
1042 }
1043 }
1044 return (ret);
1045 }
1046
1047 /*
1048 * Named kstats are returned as a list of key/values. This function converts
1049 * such a list into the equivalent perl datatypes, and stores them in the passed
1050 * hash.
1051 */
1052
1053 static void
1054 save_named(HV *self, kstat_t *kp, int strip_str)
1055 {
1056 kstat_named_t *knp;
1057 int n;
1058 SV* value;
1059
1060 for (n = kp->ks_ndata, knp = KSTAT_NAMED_PTR(kp); n > 0; n--, knp++) {
1061 switch (knp->data_type) {
1062 case KSTAT_DATA_CHAR:
1063 value = newSVpv(knp->value.c, strip_str ?
1064 strlen(knp->value.c) : sizeof (knp->value.c));
1065 break;
1066 case KSTAT_DATA_INT32:
1067 value = newSViv(knp->value.i32);
1068 break;
1069 case KSTAT_DATA_UINT32:
1070 value = NEW_UV(knp->value.ui32);
1071 break;
1072 case KSTAT_DATA_INT64:
1073 value = NEW_UV(knp->value.i64);
1074 break;
1075 case KSTAT_DATA_UINT64:
1076 value = NEW_UV(knp->value.ui64);
1077 break;
1078 case KSTAT_DATA_TIME:
1079 value = NEW_HRTIME(knp->value.ui64);
1080 break;
1081 case KSTAT_DATA_STRING:
1082 if (KSTAT_NAMED_STR_PTR(knp) == NULL)
1083 value = newSVpv("null", sizeof ("null") - 1);
1084 else
1085 value = newSVpv(KSTAT_NAMED_STR_PTR(knp),
1086 KSTAT_NAMED_STR_BUFLEN(knp) -1);
1087 break;
1088 default:
1089 PERL_ASSERTMSG(0, "kstat_read: invalid data type");
1090 continue;
1091 }
1092 hv_store(self, knp->name, strlen(knp->name), value, 0);
1093 }
1094 }
1095
1096 /*
1097 * Save kstat interrupt statistics
1098 */
1099
1100 static void
1101 save_intr(HV *self, kstat_t *kp, int strip_str)
1102 {
1103 kstat_intr_t *kintrp;
1104 int i;
1105 static char *intr_names[] =
1106 { "hard", "soft", "watchdog", "spurious", "multiple_service" };
1107
1108 PERL_ASSERT(kp->ks_ndata == 1);
1109 PERL_ASSERT(kp->ks_data_size == sizeof (kstat_intr_t));
1110 kintrp = KSTAT_INTR_PTR(kp);
1111
1112 for (i = 0; i < KSTAT_NUM_INTRS; i++) {
1113 hv_store(self, intr_names[i], strlen(intr_names[i]),
1114 NEW_UV(kintrp->intrs[i]), 0);
1115 }
1116 }
1117
1118 /*
1119 * Save IO statistics
1120 */
1121
1122 static void
1123 save_io(HV *self, kstat_t *kp, int strip_str)
1124 {
1125 kstat_io_t *kiop;
1126
1127 PERL_ASSERT(kp->ks_ndata == 1);
1128 PERL_ASSERT(kp->ks_data_size == sizeof (kstat_io_t));
1129 kiop = KSTAT_IO_PTR(kp);
1130 SAVE_UINT64(self, kiop, nread);
1131 SAVE_UINT64(self, kiop, nwritten);
1132 SAVE_UINT32(self, kiop, reads);
1133 SAVE_UINT32(self, kiop, writes);
1134 SAVE_HRTIME(self, kiop, wtime);
1135 SAVE_HRTIME(self, kiop, wlentime);
1136 SAVE_HRTIME(self, kiop, wlastupdate);
1137 SAVE_HRTIME(self, kiop, rtime);
1138 SAVE_HRTIME(self, kiop, rlentime);
1139 SAVE_HRTIME(self, kiop, rlastupdate);
1140 SAVE_UINT32(self, kiop, wcnt);
1141 SAVE_UINT32(self, kiop, rcnt);
1142 }
1143
1144 /*
1145 * Save timer statistics
1146 */
1147
1148 static void
1149 save_timer(HV *self, kstat_t *kp, int strip_str)
1150 {
1151 kstat_timer_t *ktimerp;
1152
1153 PERL_ASSERT(kp->ks_ndata == 1);
1154 PERL_ASSERT(kp->ks_data_size == sizeof (kstat_timer_t));
1155 ktimerp = KSTAT_TIMER_PTR(kp);
1156 SAVE_STRING(self, ktimerp, name, strip_str);
1157 SAVE_UINT64(self, ktimerp, num_events);
1158 SAVE_HRTIME(self, ktimerp, elapsed_time);
1159 SAVE_HRTIME(self, ktimerp, min_time);
1160 SAVE_HRTIME(self, ktimerp, max_time);
1161 SAVE_HRTIME(self, ktimerp, start_time);
1162 SAVE_HRTIME(self, ktimerp, stop_time);
1163 }
1164
1165 /*
1166 * Read kstats and copy into the supplied perl hash structure. If refresh is
1167 * true, this function is being called as part of the update() method. In this
1168 * case it is only necessary to read the kstats if they have previously been
1169 * accessed (kip->read == TRUE). If refresh is false, this function is being
1170 * called prior to returning a value to the caller. In this case, it is only
1171 * necessary to read the kstats if they have not previously been read. If the
1172 * kstat_read() fails, 0 is returned, otherwise 1
1173 */
1174
1175 static int
1176 read_kstats(HV *self, int refresh)
1177 {
1178 MAGIC *mg;
1179 KstatInfo_t *kip;
1180 kstat_raw_reader_t fnp;
1181
1182 /* Find the MAGIC KstatInfo_t data structure */
1183 mg = mg_find((SV *)self, '~');
1184 PERL_ASSERTMSG(mg != 0, "read_kstats: lost ~ magic");
1185 kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1186
1187 /* Return early if we don't need to actually read the kstats */
1188 if ((refresh && ! kip->read) || (! refresh && kip->read)) {
1189 return (1);
1190 }
1191
1192 /* Read the kstats and return 0 if this fails */
1193 if (kstat_read(kip->kstat_ctl, kip->kstat, NULL) < 0) {
1194 return (0);
1195 }
1196
1197 /* Save the read data */
1198 hv_store(self, "snaptime", 8, NEW_HRTIME(kip->kstat->ks_snaptime), 0);
1199 switch (kip->kstat->ks_type) {
1200 case KSTAT_TYPE_RAW:
1201 if ((fnp = lookup_raw_kstat_fn(kip->kstat->ks_module,
1202 kip->kstat->ks_name)) != 0) {
1203 fnp(self, kip->kstat, kip->strip_str);
1204 }
1205 break;
1206 case KSTAT_TYPE_NAMED:
1207 save_named(self, kip->kstat, kip->strip_str);
1208 break;
1209 case KSTAT_TYPE_INTR:
1210 save_intr(self, kip->kstat, kip->strip_str);
1211 break;
1212 case KSTAT_TYPE_IO:
1213 save_io(self, kip->kstat, kip->strip_str);
1214 break;
1215 case KSTAT_TYPE_TIMER:
1216 save_timer(self, kip->kstat, kip->strip_str);
1217 break;
1218 default:
1219 PERL_ASSERTMSG(0, "read_kstats: illegal kstat type");
1220 break;
1221 }
1222 kip->read = TRUE;
1223 return (1);
1224 }
1225
1226 /*
1227 * The XS code exported to perl is below here. Note that the XS preprocessor
1228 * has its own commenting syntax, so all comments from this point on are in
1229 * that form.
1230 */
1231
1232 /* The following XS methods are the ABI of the Sun::Solaris::Kstat package */
1233
1234 MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat
1235 PROTOTYPES: ENABLE
1236
1237 # Create the raw kstat to store function lookup table on load
1238 BOOT:
1239 build_raw_kstat_lookup();
1240
1241 #
1242 # The Sun::Solaris::Kstat constructor. This builds the nested
1243 # name::instance::module hash structure, but doesn't actually read the
1244 # underlying kstats. This is done on demand by the TIEHASH methods in
1245 # Sun::Solaris::Kstat::_Stat
1246 #
1247
1248 SV*
1249 new(class, ...)
1250 char *class;
1251 PREINIT:
1252 HV *stash;
1253 kstat_ctl_t *kc;
1254 SV *kcsv;
1255 kstat_t *kp;
1256 KstatInfo_t kstatinfo;
1257 int sp, strip_str;
1258 CODE:
1259 /* Check we have an even number of arguments, excluding the class */
1260 sp = 1;
1261 if (((items - sp) % 2) != 0) {
1262 croak(DEBUG_ID ": new: invalid number of arguments");
1263 }
1264
1265 /* Process any (name => value) arguments */
1266 strip_str = 0;
1267 while (sp < items) {
1268 SV *name, *value;
1269
1270 name = ST(sp);
1271 sp++;
1272 value = ST(sp);
1273 sp++;
1274 if (strcmp(SvPVX(name), "strip_strings") == 0) {
1275 strip_str = SvTRUE(value);
1276 } else {
1277 croak(DEBUG_ID ": new: invalid parameter name '%s'",
1278 SvPVX(name));
1279 }
1280 }
1281
1282 /* Open the kstats handle */
1283 if ((kc = kstat_open()) == 0) {
1284 XSRETURN_UNDEF;
1285 }
1286
1287 /* Create a blessed hash ref */
1288 RETVAL = (SV *)newRV_noinc((SV *)newHV());
1289 stash = gv_stashpv(class, TRUE);
1290 sv_bless(RETVAL, stash);
1291
1292 /* Create a place to save the KstatInfo_t structure */
1293 kcsv = newSVpv((char *)&kc, sizeof (kc));
1294 sv_magic(SvRV(RETVAL), kcsv, '~', 0, 0);
1295 SvREFCNT_dec(kcsv);
1296
1297 /* Initialise the KstatsInfo_t structure */
1298 kstatinfo.read = FALSE;
1299 kstatinfo.valid = TRUE;
1300 kstatinfo.strip_str = strip_str;
1301 kstatinfo.kstat_ctl = kc;
1302
1303 /* Scan the kstat chain, building hash entries for the kstats */
1304 for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) {
1305 HV *tie;
1306 SV *kstatsv;
1307
1308 /* Don't bother storing the kstat headers */
1309 if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
1310 continue;
1311 }
1312
1313 /* Don't bother storing raw stats we don't understand */
1314 if (kp->ks_type == KSTAT_TYPE_RAW &&
1315 lookup_raw_kstat_fn(kp->ks_module, kp->ks_name) == 0) {
1316 #ifdef REPORT_UNKNOWN
1317 (void) fprintf(stderr,
1318 "Unknown kstat type %s:%d:%s - %d of size %d\n",
1319 kp->ks_module, kp->ks_instance, kp->ks_name,
1320 kp->ks_ndata, kp->ks_data_size);
1321 #endif
1322 continue;
1323 }
1324
1325 /* Create a 3-layer hash hierarchy - module.instance.name */
1326 tie = get_tie(RETVAL, kp->ks_module, kp->ks_instance,
1327 kp->ks_name, 0);
1328
1329 /* Save the data necessary to read the kstat info on demand */
1330 hv_store(tie, "class", 5, newSVpv(kp->ks_class, 0), 0);
1331 hv_store(tie, "crtime", 6, NEW_HRTIME(kp->ks_crtime), 0);
1332 kstatinfo.kstat = kp;
1333 kstatsv = newSVpv((char *)&kstatinfo, sizeof (kstatinfo));
1334 sv_magic((SV *)tie, kstatsv, '~', 0, 0);
1335 SvREFCNT_dec(kstatsv);
1336 }
1337 SvREADONLY_on(SvRV(RETVAL));
1338 /* SvREADONLY_on(RETVAL); */
1339 OUTPUT:
1340 RETVAL
1341
1342 #
1343 # Update the perl hash structure so that it is in line with the kernel kstats
1344 # data. Only kstats athat have previously been accessed are read,
1345 #
1346
1347 # Scalar context: true/false
1348 # Array context: (\@added, \@deleted)
1349 void
1350 update(self)
1351 SV* self;
1352 PREINIT:
1353 MAGIC *mg;
1354 kstat_ctl_t *kc;
1355 kstat_t *kp;
1356 int ret;
1357 AV *add, *del;
1358 PPCODE:
1359 /* Find the hidden KstatInfo_t structure */
1360 mg = mg_find(SvRV(self), '~');
1361 PERL_ASSERTMSG(mg != 0, "update: lost ~ magic");
1362 kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj);
1363
1364 /* Update the kstat chain, and return immediately on error. */
1365 if ((ret = kstat_chain_update(kc)) == -1) {
1366 if (GIMME_V == G_ARRAY) {
1367 EXTEND(SP, 2);
1368 PUSHs(sv_newmortal());
1369 PUSHs(sv_newmortal());
1370 } else {
1371 EXTEND(SP, 1);
1372 PUSHs(sv_2mortal(newSViv(ret)));
1373 }
1374 }
1375
1376 /* Create the arrays to be returned if in an array context */
1377 if (GIMME_V == G_ARRAY) {
1378 add = newAV();
1379 del = newAV();
1380 } else {
1381 add = 0;
1382 del = 0;
1383 }
1384
1385 /*
1386 * If the kstat chain hasn't changed we can just reread any stats
1387 * that have already been read
1388 */
1389 if (ret == 0) {
1390 if (! apply_to_ties(self, (ATTCb_t)read_kstats, (void *)TRUE)) {
1391 if (GIMME_V == G_ARRAY) {
1392 EXTEND(SP, 2);
1393 PUSHs(sv_2mortal(newRV_noinc((SV *)add)));
1394 PUSHs(sv_2mortal(newRV_noinc((SV *)del)));
1395 } else {
1396 EXTEND(SP, 1);
1397 PUSHs(sv_2mortal(newSViv(-1)));
1398 }
1399 }
1400
1401 /*
1402 * Otherwise we have to update the Perl structure so that it is in
1403 * agreement with the new kstat chain. We do this in such a way as to
1404 * retain all the existing structures, just adding or deleting the
1405 * bare minimum.
1406 */
1407 } else {
1408 KstatInfo_t kstatinfo;
1409
1410 /*
1411 * Step 1: set the 'invalid' flag on each entry
1412 */
1413 apply_to_ties(self, &set_valid, (void *)FALSE);
1414
1415 /*
1416 * Step 2: Set the 'valid' flag on all entries still in the
1417 * kernel kstat chain
1418 */
1419 kstatinfo.read = FALSE;
1420 kstatinfo.valid = TRUE;
1421 kstatinfo.kstat_ctl = kc;
1422 for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) {
1423 int new;
1424 HV *tie;
1425
1426 /* Don't bother storing the kstat headers or types */
1427 if (strncmp(kp->ks_name, "kstat_", 6) == 0) {
1428 continue;
1429 }
1430
1431 /* Don't bother storing raw stats we don't understand */
1432 if (kp->ks_type == KSTAT_TYPE_RAW &&
1433 lookup_raw_kstat_fn(kp->ks_module, kp->ks_name)
1434 == 0) {
1435 #ifdef REPORT_UNKNOWN
1436 (void) printf("Unknown kstat type %s:%d:%s "
1437 "- %d of size %d\n", kp->ks_module,
1438 kp->ks_instance, kp->ks_name,
1439 kp->ks_ndata, kp->ks_data_size);
1440 #endif
1441 continue;
1442 }
1443
1444 /* Find the tied hash associated with the kstat entry */
1445 tie = get_tie(self, kp->ks_module, kp->ks_instance,
1446 kp->ks_name, &new);
1447
1448 /* If newly created store the associated kstat info */
1449 if (new) {
1450 SV *kstatsv;
1451
1452 /*
1453 * Save the data necessary to read the kstat
1454 * info on demand
1455 */
1456 hv_store(tie, "class", 5,
1457 newSVpv(kp->ks_class, 0), 0);
1458 hv_store(tie, "crtime", 6,
1459 NEW_HRTIME(kp->ks_crtime), 0);
1460 kstatinfo.kstat = kp;
1461 kstatsv = newSVpv((char *)&kstatinfo,
1462 sizeof (kstatinfo));
1463 sv_magic((SV *)tie, kstatsv, '~', 0, 0);
1464 SvREFCNT_dec(kstatsv);
1465
1466 /* Save the key on the add list, if required */
1467 if (GIMME_V == G_ARRAY) {
1468 av_push(add, newSVpvf("%s:%d:%s",
1469 kp->ks_module, kp->ks_instance,
1470 kp->ks_name));
1471 }
1472
1473 /* If the stats already exist, just update them */
1474 } else {
1475 MAGIC *mg;
1476 KstatInfo_t *kip;
1477
1478 /* Find the hidden KstatInfo_t */
1479 mg = mg_find((SV *)tie, '~');
1480 PERL_ASSERTMSG(mg != 0, "update: lost ~ magic");
1481 kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1482
1483 /* Mark the tie as valid */
1484 kip->valid = TRUE;
1485
1486 /* Re-save the kstat_t pointer. If the kstat
1487 * has been deleted and re-added since the last
1488 * update, the address of the kstat structure
1489 * will have changed, even though the kstat will
1490 * still live at the same place in the perl
1491 * hash tree structure.
1492 */
1493 kip->kstat = kp;
1494
1495 /* Reread the stats, if read previously */
1496 read_kstats(tie, TRUE);
1497 }
1498 }
1499
1500 /*
1501 *Step 3: Delete any entries still marked as 'invalid'
1502 */
1503 ret = prune_invalid(self, del);
1504
1505 }
1506 if (GIMME_V == G_ARRAY) {
1507 EXTEND(SP, 2);
1508 PUSHs(sv_2mortal(newRV_noinc((SV *)add)));
1509 PUSHs(sv_2mortal(newRV_noinc((SV *)del)));
1510 } else {
1511 EXTEND(SP, 1);
1512 PUSHs(sv_2mortal(newSViv(ret)));
1513 }
1514
1515
1516 #
1517 # Destructor. Closes the kstat connection
1518 #
1519
1520 void
1521 DESTROY(self)
1522 SV *self;
1523 PREINIT:
1524 MAGIC *mg;
1525 kstat_ctl_t *kc;
1526 CODE:
1527 mg = mg_find(SvRV(self), '~');
1528 PERL_ASSERTMSG(mg != 0, "DESTROY: lost ~ magic");
1529 kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj);
1530 if (kstat_close(kc) != 0) {
1531 croak(DEBUG_ID ": kstat_close: failed");
1532 }
1533
1534 #
1535 # The following XS methods implement the TIEHASH mechanism used to update the
1536 # kstats hash structure. These are blessed into a package that isn't
1537 # visible to callers of the Sun::Solaris::Kstat module
1538 #
1539
1540 MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat::_Stat
1541 PROTOTYPES: ENABLE
1542
1543 #
1544 # If a value has already been read, return it. Otherwise read the appropriate
1545 # kstat and then return the value
1546 #
1547
1548 SV*
1549 FETCH(self, key)
1550 SV* self;
1551 SV* key;
1552 PREINIT:
1553 char *k;
1554 STRLEN klen;
1555 SV **value;
1556 CODE:
1557 self = SvRV(self);
1558 k = SvPV(key, klen);
1559 if (strNE(k, "class") && strNE(k, "crtime")) {
1560 read_kstats((HV *)self, FALSE);
1561 }
1562 value = hv_fetch((HV *)self, k, klen, FALSE);
1563 if (value) {
1564 RETVAL = *value; SvREFCNT_inc(RETVAL);
1565 } else {
1566 RETVAL = &PL_sv_undef;
1567 }
1568 OUTPUT:
1569 RETVAL
1570
1571 #
1572 # Save the passed value into the kstat hash. Read the appropriate kstat first,
1573 # if necessary. Note that this DOES NOT update the underlying kernel kstat
1574 # structure.
1575 #
1576
1577 SV*
1578 STORE(self, key, value)
1579 SV* self;
1580 SV* key;
1581 SV* value;
1582 PREINIT:
1583 char *k;
1584 STRLEN klen;
1585 CODE:
1586 self = SvRV(self);
1587 k = SvPV(key, klen);
1588 if (strNE(k, "class") && strNE(k, "crtime")) {
1589 read_kstats((HV *)self, FALSE);
1590 }
1591 SvREFCNT_inc(value);
1592 RETVAL = *(hv_store((HV *)self, k, klen, value, 0));
1593 SvREFCNT_inc(RETVAL);
1594 OUTPUT:
1595 RETVAL
1596
1597 #
1598 # Check for the existence of the passed key. Read the kstat first if necessary
1599 #
1600
1601 bool
1602 EXISTS(self, key)
1603 SV* self;
1604 SV* key;
1605 PREINIT:
1606 char *k;
1607 CODE:
1608 self = SvRV(self);
1609 k = SvPV(key, PL_na);
1610 if (strNE(k, "class") && strNE(k, "crtime")) {
1611 read_kstats((HV *)self, FALSE);
1612 }
1613 RETVAL = hv_exists_ent((HV *)self, key, 0);
1614 OUTPUT:
1615 RETVAL
1616
1617
1618 #
1619 # Hash iterator initialisation. Read the kstats if necessary.
1620 #
1621
1622 SV*
1623 FIRSTKEY(self)
1624 SV* self;
1625 PREINIT:
1626 HE *he;
1627 PPCODE:
1628 self = SvRV(self);
1629 read_kstats((HV *)self, FALSE);
1630 hv_iterinit((HV *)self);
1631 if ((he = hv_iternext((HV *)self))) {
1632 EXTEND(SP, 1);
1633 PUSHs(hv_iterkeysv(he));
1634 }
1635
1636 #
1637 # Return hash iterator next value. Read the kstats if necessary.
1638 #
1639
1640 SV*
1641 NEXTKEY(self, lastkey)
1642 SV* self;
1643 SV* lastkey;
1644 PREINIT:
1645 HE *he;
1646 PPCODE:
1647 self = SvRV(self);
1648 if ((he = hv_iternext((HV *)self))) {
1649 EXTEND(SP, 1);
1650 PUSHs(hv_iterkeysv(he));
1651 }
1652
1653
1654 #
1655 # Delete the specified hash entry.
1656 #
1657
1658 SV*
1659 DELETE(self, key)
1660 SV *self;
1661 SV *key;
1662 CODE:
1663 self = SvRV(self);
1664 RETVAL = hv_delete_ent((HV *)self, key, 0, 0);
1665 if (RETVAL) {
1666 SvREFCNT_inc(RETVAL);
1667 } else {
1668 RETVAL = &PL_sv_undef;
1669 }
1670 OUTPUT:
1671 RETVAL
1672
1673 #
1674 # Clear the entire hash. This will stop any update() calls rereading this
1675 # kstat until it is accessed again.
1676 #
1677
1678 void
1679 CLEAR(self)
1680 SV* self;
1681 PREINIT:
1682 MAGIC *mg;
1683 KstatInfo_t *kip;
1684 CODE:
1685 self = SvRV(self);
1686 hv_clear((HV *)self);
1687 mg = mg_find(self, '~');
1688 PERL_ASSERTMSG(mg != 0, "CLEAR: lost ~ magic");
1689 kip = (KstatInfo_t *)SvPVX(mg->mg_obj);
1690 kip->read = FALSE;
1691 kip->valid = TRUE;
1692 hv_store((HV *)self, "class", 5, newSVpv(kip->kstat->ks_class, 0), 0);
1693 hv_store((HV *)self, "crtime", 6, NEW_HRTIME(kip->kstat->ks_crtime), 0);