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