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 2019 OmniOS Community Edition (OmniOSce) Association. 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 sockinfo. ks_ndata is the number of elements of that 67 * array and ks_data_size is the total size of the array. 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_STRING: 1079 if (KSTAT_NAMED_STR_PTR(knp) == NULL) 1080 value = newSVpv("null", sizeof ("null") - 1); 1081 else 1082 value = newSVpv(KSTAT_NAMED_STR_PTR(knp), 1083 KSTAT_NAMED_STR_BUFLEN(knp) -1); 1084 break; 1085 default: 1086 PERL_ASSERTMSG(0, "kstat_read: invalid data type"); 1087 continue; 1088 } 1089 hv_store(self, knp->name, strlen(knp->name), value, 0); 1090 } 1091 } 1092 1093 /* 1094 * Save kstat interrupt statistics 1095 */ 1096 1097 static void 1098 save_intr(HV *self, kstat_t *kp, int strip_str) 1099 { 1100 kstat_intr_t *kintrp; 1101 int i; 1102 static char *intr_names[] = 1103 { "hard", "soft", "watchdog", "spurious", "multiple_service" }; 1104 1105 PERL_ASSERT(kp->ks_ndata == 1); 1106 PERL_ASSERT(kp->ks_data_size == sizeof (kstat_intr_t)); 1107 kintrp = KSTAT_INTR_PTR(kp); 1108 1109 for (i = 0; i < KSTAT_NUM_INTRS; i++) { 1110 hv_store(self, intr_names[i], strlen(intr_names[i]), 1111 NEW_UV(kintrp->intrs[i]), 0); 1112 } 1113 } 1114 1115 /* 1116 * Save IO statistics 1117 */ 1118 1119 static void 1120 save_io(HV *self, kstat_t *kp, int strip_str) 1121 { 1122 kstat_io_t *kiop; 1123 1124 PERL_ASSERT(kp->ks_ndata == 1); 1125 PERL_ASSERT(kp->ks_data_size == sizeof (kstat_io_t)); 1126 kiop = KSTAT_IO_PTR(kp); 1127 SAVE_UINT64(self, kiop, nread); 1128 SAVE_UINT64(self, kiop, nwritten); 1129 SAVE_UINT32(self, kiop, reads); 1130 SAVE_UINT32(self, kiop, writes); 1131 SAVE_HRTIME(self, kiop, wtime); 1132 SAVE_HRTIME(self, kiop, wlentime); 1133 SAVE_HRTIME(self, kiop, wlastupdate); 1134 SAVE_HRTIME(self, kiop, rtime); 1135 SAVE_HRTIME(self, kiop, rlentime); 1136 SAVE_HRTIME(self, kiop, rlastupdate); 1137 SAVE_UINT32(self, kiop, wcnt); 1138 SAVE_UINT32(self, kiop, rcnt); 1139 } 1140 1141 /* 1142 * Save timer statistics 1143 */ 1144 1145 static void 1146 save_timer(HV *self, kstat_t *kp, int strip_str) 1147 { 1148 kstat_timer_t *ktimerp; 1149 1150 PERL_ASSERT(kp->ks_ndata == 1); 1151 PERL_ASSERT(kp->ks_data_size == sizeof (kstat_timer_t)); 1152 ktimerp = KSTAT_TIMER_PTR(kp); 1153 SAVE_STRING(self, ktimerp, name, strip_str); 1154 SAVE_UINT64(self, ktimerp, num_events); 1155 SAVE_HRTIME(self, ktimerp, elapsed_time); 1156 SAVE_HRTIME(self, ktimerp, min_time); 1157 SAVE_HRTIME(self, ktimerp, max_time); 1158 SAVE_HRTIME(self, ktimerp, start_time); 1159 SAVE_HRTIME(self, ktimerp, stop_time); 1160 } 1161 1162 /* 1163 * Read kstats and copy into the supplied perl hash structure. If refresh is 1164 * true, this function is being called as part of the update() method. In this 1165 * case it is only necessary to read the kstats if they have previously been 1166 * accessed (kip->read == TRUE). If refresh is false, this function is being 1167 * called prior to returning a value to the caller. In this case, it is only 1168 * necessary to read the kstats if they have not previously been read. If the 1169 * kstat_read() fails, 0 is returned, otherwise 1 1170 */ 1171 1172 static int 1173 read_kstats(HV *self, int refresh) 1174 { 1175 MAGIC *mg; 1176 KstatInfo_t *kip; 1177 kstat_raw_reader_t fnp; 1178 1179 /* Find the MAGIC KstatInfo_t data structure */ 1180 mg = mg_find((SV *)self, '~'); 1181 PERL_ASSERTMSG(mg != 0, "read_kstats: lost ~ magic"); 1182 kip = (KstatInfo_t *)SvPVX(mg->mg_obj); 1183 1184 /* Return early if we don't need to actually read the kstats */ 1185 if ((refresh && ! kip->read) || (! refresh && kip->read)) { 1186 return (1); 1187 } 1188 1189 /* Read the kstats and return 0 if this fails */ 1190 if (kstat_read(kip->kstat_ctl, kip->kstat, NULL) < 0) { 1191 return (0); 1192 } 1193 1194 /* Save the read data */ 1195 hv_store(self, "snaptime", 8, NEW_HRTIME(kip->kstat->ks_snaptime), 0); 1196 switch (kip->kstat->ks_type) { 1197 case KSTAT_TYPE_RAW: 1198 if ((fnp = lookup_raw_kstat_fn(kip->kstat->ks_module, 1199 kip->kstat->ks_name)) != 0) { 1200 fnp(self, kip->kstat, kip->strip_str); 1201 } 1202 break; 1203 case KSTAT_TYPE_NAMED: 1204 save_named(self, kip->kstat, kip->strip_str); 1205 break; 1206 case KSTAT_TYPE_INTR: 1207 save_intr(self, kip->kstat, kip->strip_str); 1208 break; 1209 case KSTAT_TYPE_IO: 1210 save_io(self, kip->kstat, kip->strip_str); 1211 break; 1212 case KSTAT_TYPE_TIMER: 1213 save_timer(self, kip->kstat, kip->strip_str); 1214 break; 1215 default: 1216 PERL_ASSERTMSG(0, "read_kstats: illegal kstat type"); 1217 break; 1218 } 1219 kip->read = TRUE; 1220 return (1); 1221 } 1222 1223 static int 1224 read_kstats_wrap(HV *self, void *ptr) 1225 { 1226 int refresh = (intptr_t)ptr; 1227 1228 return (read_kstats(self, refresh)); 1229 } 1230 1231 /* 1232 * The XS code exported to perl is below here. Note that the XS preprocessor 1233 * has its own commenting syntax, so all comments from this point on are in 1234 * that form. 1235 */ 1236 1237 /* The following XS methods are the ABI of the Sun::Solaris::Kstat package */ 1238 1239 MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat 1240 PROTOTYPES: ENABLE 1241 1242 # Create the raw kstat to store function lookup table on load 1243 BOOT: 1244 build_raw_kstat_lookup(); 1245 1246 # 1247 # The Sun::Solaris::Kstat constructor. This builds the nested 1248 # name::instance::module hash structure, but doesn't actually read the 1249 # underlying kstats. This is done on demand by the TIEHASH methods in 1250 # Sun::Solaris::Kstat::_Stat 1251 # 1252 1253 SV* 1254 new(class, ...) 1255 char *class; 1256 PREINIT: 1257 HV *stash; 1258 kstat_ctl_t *kc; 1259 SV *kcsv; 1260 kstat_t *kp; 1261 KstatInfo_t kstatinfo; 1262 int sp, strip_str; 1263 CODE: 1264 /* Check we have an even number of arguments, excluding the class */ 1265 sp = 1; 1266 if (((items - sp) % 2) != 0) { 1267 croak(DEBUG_ID ": new: invalid number of arguments"); 1268 } 1269 1270 /* Process any (name => value) arguments */ 1271 strip_str = 0; 1272 while (sp < items) { 1273 SV *name, *value; 1274 1275 name = ST(sp); 1276 sp++; 1277 value = ST(sp); 1278 sp++; 1279 if (strcmp(SvPVX(name), "strip_strings") == 0) { 1280 strip_str = SvTRUE(value); 1281 } else { 1282 croak(DEBUG_ID ": new: invalid parameter name '%s'", 1283 SvPVX(name)); 1284 } 1285 } 1286 1287 /* Open the kstats handle */ 1288 if ((kc = kstat_open()) == 0) { 1289 XSRETURN_UNDEF; 1290 } 1291 1292 /* Create a blessed hash ref */ 1293 RETVAL = (SV *)newRV_noinc((SV *)newHV()); 1294 stash = gv_stashpv(class, TRUE); 1295 sv_bless(RETVAL, stash); 1296 1297 /* Create a place to save the KstatInfo_t structure */ 1298 kcsv = newSVpv((char *)&kc, sizeof (kc)); 1299 sv_magic(SvRV(RETVAL), kcsv, '~', 0, 0); 1300 SvREFCNT_dec(kcsv); 1301 1302 /* Initialise the KstatsInfo_t structure */ 1303 kstatinfo.read = FALSE; 1304 kstatinfo.valid = TRUE; 1305 kstatinfo.strip_str = strip_str; 1306 kstatinfo.kstat_ctl = kc; 1307 1308 /* Scan the kstat chain, building hash entries for the kstats */ 1309 for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) { 1310 HV *tie; 1311 SV *kstatsv; 1312 1313 /* Don't bother storing the kstat headers */ 1314 if (strncmp(kp->ks_name, "kstat_", 6) == 0) { 1315 continue; 1316 } 1317 1318 /* Don't bother storing raw stats we don't understand */ 1319 if (kp->ks_type == KSTAT_TYPE_RAW && 1320 lookup_raw_kstat_fn(kp->ks_module, kp->ks_name) == 0) { 1321 #ifdef REPORT_UNKNOWN 1322 (void) fprintf(stderr, 1323 "Unknown kstat type %s:%d:%s - %d of size %d\n", 1324 kp->ks_module, kp->ks_instance, kp->ks_name, 1325 kp->ks_ndata, kp->ks_data_size); 1326 #endif 1327 continue; 1328 } 1329 1330 /* Create a 3-layer hash hierarchy - module.instance.name */ 1331 tie = get_tie(RETVAL, kp->ks_module, kp->ks_instance, 1332 kp->ks_name, 0); 1333 1334 /* Save the data necessary to read the kstat info on demand */ 1335 hv_store(tie, "class", 5, newSVpv(kp->ks_class, 0), 0); 1336 hv_store(tie, "crtime", 6, NEW_HRTIME(kp->ks_crtime), 0); 1337 kstatinfo.kstat = kp; 1338 kstatsv = newSVpv((char *)&kstatinfo, sizeof (kstatinfo)); 1339 sv_magic((SV *)tie, kstatsv, '~', 0, 0); 1340 SvREFCNT_dec(kstatsv); 1341 } 1342 SvREADONLY_on(SvRV(RETVAL)); 1343 /* SvREADONLY_on(RETVAL); */ 1344 OUTPUT: 1345 RETVAL 1346 1347 # 1348 # Update the perl hash structure so that it is in line with the kernel kstats 1349 # data. Only kstats athat have previously been accessed are read, 1350 # 1351 1352 # Scalar context: true/false 1353 # Array context: (\@added, \@deleted) 1354 void 1355 update(self) 1356 SV* self; 1357 PREINIT: 1358 MAGIC *mg; 1359 kstat_ctl_t *kc; 1360 kstat_t *kp; 1361 int ret; 1362 AV *add, *del; 1363 PPCODE: 1364 /* Find the hidden KstatInfo_t structure */ 1365 mg = mg_find(SvRV(self), '~'); 1366 PERL_ASSERTMSG(mg != 0, "update: lost ~ magic"); 1367 kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj); 1368 1369 /* Update the kstat chain, and return immediately on error. */ 1370 if ((ret = kstat_chain_update(kc)) == -1) { 1371 if (GIMME_V == G_ARRAY) { 1372 EXTEND(SP, 2); 1373 PUSHs(sv_newmortal()); 1374 PUSHs(sv_newmortal()); 1375 } else { 1376 EXTEND(SP, 1); 1377 PUSHs(sv_2mortal(newSViv(ret))); 1378 } 1379 } 1380 1381 /* Create the arrays to be returned if in an array context */ 1382 if (GIMME_V == G_ARRAY) { 1383 add = newAV(); 1384 del = newAV(); 1385 } else { 1386 add = 0; 1387 del = 0; 1388 } 1389 1390 /* 1391 * If the kstat chain hasn't changed we can just reread any stats 1392 * that have already been read 1393 */ 1394 if (ret == 0) { 1395 if (! apply_to_ties(self, read_kstats_wrap, (void *)TRUE)) { 1396 if (GIMME_V == G_ARRAY) { 1397 EXTEND(SP, 2); 1398 PUSHs(sv_2mortal(newRV_noinc((SV *)add))); 1399 PUSHs(sv_2mortal(newRV_noinc((SV *)del))); 1400 } else { 1401 EXTEND(SP, 1); 1402 PUSHs(sv_2mortal(newSViv(-1))); 1403 } 1404 } 1405 1406 /* 1407 * Otherwise we have to update the Perl structure so that it is in 1408 * agreement with the new kstat chain. We do this in such a way as to 1409 * retain all the existing structures, just adding or deleting the 1410 * bare minimum. 1411 */ 1412 } else { 1413 KstatInfo_t kstatinfo; 1414 1415 /* 1416 * Step 1: set the 'invalid' flag on each entry 1417 */ 1418 apply_to_ties(self, &set_valid, (void *)FALSE); 1419 1420 /* 1421 * Step 2: Set the 'valid' flag on all entries still in the 1422 * kernel kstat chain 1423 */ 1424 kstatinfo.read = FALSE; 1425 kstatinfo.valid = TRUE; 1426 kstatinfo.kstat_ctl = kc; 1427 for (kp = kc->kc_chain; kp != 0; kp = kp->ks_next) { 1428 int new; 1429 HV *tie; 1430 1431 /* Don't bother storing the kstat headers or types */ 1432 if (strncmp(kp->ks_name, "kstat_", 6) == 0) { 1433 continue; 1434 } 1435 1436 /* Don't bother storing raw stats we don't understand */ 1437 if (kp->ks_type == KSTAT_TYPE_RAW && 1438 lookup_raw_kstat_fn(kp->ks_module, kp->ks_name) 1439 == 0) { 1440 #ifdef REPORT_UNKNOWN 1441 (void) printf("Unknown kstat type %s:%d:%s " 1442 "- %d of size %d\n", kp->ks_module, 1443 kp->ks_instance, kp->ks_name, 1444 kp->ks_ndata, kp->ks_data_size); 1445 #endif 1446 continue; 1447 } 1448 1449 /* Find the tied hash associated with the kstat entry */ 1450 tie = get_tie(self, kp->ks_module, kp->ks_instance, 1451 kp->ks_name, &new); 1452 1453 /* If newly created store the associated kstat info */ 1454 if (new) { 1455 SV *kstatsv; 1456 1457 /* 1458 * Save the data necessary to read the kstat 1459 * info on demand 1460 */ 1461 hv_store(tie, "class", 5, 1462 newSVpv(kp->ks_class, 0), 0); 1463 hv_store(tie, "crtime", 6, 1464 NEW_HRTIME(kp->ks_crtime), 0); 1465 kstatinfo.kstat = kp; 1466 kstatsv = newSVpv((char *)&kstatinfo, 1467 sizeof (kstatinfo)); 1468 sv_magic((SV *)tie, kstatsv, '~', 0, 0); 1469 SvREFCNT_dec(kstatsv); 1470 1471 /* Save the key on the add list, if required */ 1472 if (GIMME_V == G_ARRAY) { 1473 av_push(add, newSVpvf("%s:%d:%s", 1474 kp->ks_module, kp->ks_instance, 1475 kp->ks_name)); 1476 } 1477 1478 /* If the stats already exist, just update them */ 1479 } else { 1480 MAGIC *mg; 1481 KstatInfo_t *kip; 1482 1483 /* Find the hidden KstatInfo_t */ 1484 mg = mg_find((SV *)tie, '~'); 1485 PERL_ASSERTMSG(mg != 0, "update: lost ~ magic"); 1486 kip = (KstatInfo_t *)SvPVX(mg->mg_obj); 1487 1488 /* Mark the tie as valid */ 1489 kip->valid = TRUE; 1490 1491 /* Re-save the kstat_t pointer. If the kstat 1492 * has been deleted and re-added since the last 1493 * update, the address of the kstat structure 1494 * will have changed, even though the kstat will 1495 * still live at the same place in the perl 1496 * hash tree structure. 1497 */ 1498 kip->kstat = kp; 1499 1500 /* Reread the stats, if read previously */ 1501 read_kstats(tie, TRUE); 1502 } 1503 } 1504 1505 /* 1506 *Step 3: Delete any entries still marked as 'invalid' 1507 */ 1508 ret = prune_invalid(self, del); 1509 1510 } 1511 if (GIMME_V == G_ARRAY) { 1512 EXTEND(SP, 2); 1513 PUSHs(sv_2mortal(newRV_noinc((SV *)add))); 1514 PUSHs(sv_2mortal(newRV_noinc((SV *)del))); 1515 } else { 1516 EXTEND(SP, 1); 1517 PUSHs(sv_2mortal(newSViv(ret))); 1518 } 1519 1520 1521 # 1522 # Destructor. Closes the kstat connection 1523 # 1524 1525 void 1526 DESTROY(self) 1527 SV *self; 1528 PREINIT: 1529 MAGIC *mg; 1530 kstat_ctl_t *kc; 1531 CODE: 1532 mg = mg_find(SvRV(self), '~'); 1533 PERL_ASSERTMSG(mg != 0, "DESTROY: lost ~ magic"); 1534 kc = *(kstat_ctl_t **)SvPVX(mg->mg_obj); 1535 if (kstat_close(kc) != 0) { 1536 croak(DEBUG_ID ": kstat_close: failed"); 1537 } 1538 1539 # 1540 # The following XS methods implement the TIEHASH mechanism used to update the 1541 # kstats hash structure. These are blessed into a package that isn't 1542 # visible to callers of the Sun::Solaris::Kstat module 1543 # 1544 1545 MODULE = Sun::Solaris::Kstat PACKAGE = Sun::Solaris::Kstat::_Stat 1546 PROTOTYPES: ENABLE 1547 1548 # 1549 # If a value has already been read, return it. Otherwise read the appropriate 1550 # kstat and then return the value 1551 # 1552 1553 SV* 1554 FETCH(self, key) 1555 SV* self; 1556 SV* key; 1557 PREINIT: 1558 char *k; 1559 STRLEN klen; 1560 SV **value; 1561 CODE: 1562 self = SvRV(self); 1563 k = SvPV(key, klen); 1564 if (strNE(k, "class") && strNE(k, "crtime")) { 1565 read_kstats((HV *)self, FALSE); 1566 } 1567 value = hv_fetch((HV *)self, k, klen, FALSE); 1568 if (value) { 1569 RETVAL = *value; SvREFCNT_inc(RETVAL); 1570 } else { 1571 RETVAL = &PL_sv_undef; 1572 } 1573 OUTPUT: 1574 RETVAL 1575 1576 # 1577 # Save the passed value into the kstat hash. Read the appropriate kstat first, 1578 # if necessary. Note that this DOES NOT update the underlying kernel kstat 1579 # structure. 1580 # 1581 1582 SV* 1583 STORE(self, key, value) 1584 SV* self; 1585 SV* key; 1586 SV* value; 1587 PREINIT: 1588 char *k; 1589 STRLEN klen; 1590 CODE: 1591 self = SvRV(self); 1592 k = SvPV(key, klen); 1593 if (strNE(k, "class") && strNE(k, "crtime")) { 1594 read_kstats((HV *)self, FALSE); 1595 } 1596 SvREFCNT_inc(value); 1597 RETVAL = *(hv_store((HV *)self, k, klen, value, 0)); 1598 SvREFCNT_inc(RETVAL); 1599 OUTPUT: 1600 RETVAL 1601 1602 # 1603 # Check for the existence of the passed key. Read the kstat first if necessary 1604 # 1605 1606 bool 1607 EXISTS(self, key) 1608 SV* self; 1609 SV* key; 1610 PREINIT: 1611 char *k; 1612 CODE: 1613 self = SvRV(self); 1614 k = SvPV(key, PL_na); 1615 if (strNE(k, "class") && strNE(k, "crtime")) { 1616 read_kstats((HV *)self, FALSE); 1617 } 1618 RETVAL = hv_exists_ent((HV *)self, key, 0); 1619 OUTPUT: 1620 RETVAL 1621 1622 1623 # 1624 # Hash iterator initialisation. Read the kstats if necessary. 1625 # 1626 1627 SV* 1628 FIRSTKEY(self) 1629 SV* self; 1630 PREINIT: 1631 HE *he; 1632 PPCODE: 1633 self = SvRV(self); 1634 read_kstats((HV *)self, FALSE); 1635 hv_iterinit((HV *)self); 1636 if ((he = hv_iternext((HV *)self))) { 1637 EXTEND(SP, 1); 1638 PUSHs(hv_iterkeysv(he)); 1639 } 1640 1641 # 1642 # Return hash iterator next value. Read the kstats if necessary. 1643 # 1644 1645 SV* 1646 NEXTKEY(self, lastkey) 1647 SV* self; 1648 SV* lastkey; 1649 PREINIT: 1650 HE *he; 1651 PPCODE: 1652 self = SvRV(self); 1653 if ((he = hv_iternext((HV *)self))) { 1654 EXTEND(SP, 1); 1655 PUSHs(hv_iterkeysv(he)); 1656 } 1657 1658 1659 # 1660 # Delete the specified hash entry. 1661 # 1662 1663 SV* 1664 DELETE(self, key) 1665 SV *self; 1666 SV *key; 1667 CODE: 1668 self = SvRV(self); 1669 RETVAL = hv_delete_ent((HV *)self, key, 0, 0); 1670 if (RETVAL) { 1671 SvREFCNT_inc(RETVAL); 1672 } else { 1673 RETVAL = &PL_sv_undef; 1674 } 1675 OUTPUT: 1676 RETVAL 1677 1678 # 1679 # Clear the entire hash. This will stop any update() calls rereading this 1680 # kstat until it is accessed again. 1681 # 1682 1683 void 1684 CLEAR(self) 1685 SV* self; 1686 PREINIT: 1687 MAGIC *mg; 1688 KstatInfo_t *kip; 1689 CODE: 1690 self = SvRV(self); 1691 hv_clear((HV *)self); 1692 mg = mg_find(self, '~'); 1693 PERL_ASSERTMSG(mg != 0, "CLEAR: lost ~ magic"); 1694 kip = (KstatInfo_t *)SvPVX(mg->mg_obj); 1695 kip->read = FALSE; 1696 kip->valid = TRUE; 1697 hv_store((HV *)self, "class", 5, newSVpv(kip->kstat->ks_class, 0), 0); 1698 hv_store((HV *)self, "crtime", 6, NEW_HRTIME(kip->kstat->ks_crtime), 0); 1699