1 /*- 2 * Copyright (c) 2014-2018 Netflix, Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 /* 28 * A kernel and user space statistics gathering API + infrastructure. 29 * 30 * Author: Lawrence Stewart <lstewart@netflix.com> 31 * 32 * Things to ponder: 33 * - Register callbacks for events e.g. counter stat passing a threshold 34 * 35 * - How could this become SIFTRv2? Perhaps publishing records to a ring 36 * mapped between userspace and kernel? 37 * 38 * - Potential stat types: 39 * RATE: events per unit time 40 * TIMESERIES: timestamped records. Stored in voistate? 41 * EWMA: Exponential weighted moving average. 42 * 43 * - How should second order stats work e.g. stat "A" depends on "B" 44 * 45 * - How do variable time windows work e.g. give me per-RTT stats 46 * 47 * - Should the API always require the caller to manage locking? Or should the 48 * API provide optional functionality to lock a blob during operations. 49 * 50 * - Should we continue to store unpacked naturally aligned structs in the 51 * blob or move to packed structs? Relates to inter-host 52 * serialisation/endian issues. 53 */ 54 55 #ifndef _SYS_STATS_H_ 56 #define _SYS_STATS_H_ 57 58 #include <sys/limits.h> 59 #ifdef DIAGNOSTIC 60 #include <sys/tree.h> 61 #endif 62 63 #ifndef _KERNEL 64 /* 65 * XXXLAS: Hacks to enable sharing template creation code between kernel and 66 * userland e.g. tcp_stats.c 67 */ 68 #define VNET(n) n 69 #define VNET_DEFINE(t, n) static t n __unused 70 #endif /* ! _KERNEL */ 71 72 #define TPL_MAX_NAME_LEN 64 73 74 /* 75 * The longest template string spec format i.e. the normative spec format, is: 76 * 77 * "<tplname>":<tplhash> 78 * 79 * Therefore, the max string length of a template string spec is: 80 * 81 * - TPL_MAX_NAME_LEN 82 * - 2 chars for "" 83 * - 1 char for : separating name and hash 84 * - 10 chars for 32bit hash 85 */ 86 #define STATS_TPL_MAX_STR_SPEC_LEN (TPL_MAX_NAME_LEN + 13) 87 88 struct sbuf; 89 struct sysctl_oid; 90 struct sysctl_req; 91 92 enum sb_str_fmt { 93 SB_STRFMT_FREEFORM = 0, 94 SB_STRFMT_JSON, 95 SB_STRFMT_NUM_FMTS /* +1 to highest numbered format type. */ 96 }; 97 98 /* VOI stat types. */ 99 enum voi_stype { 100 VS_STYPE_VOISTATE = 0, /* Reserved for internal API use. */ 101 VS_STYPE_SUM, 102 VS_STYPE_MAX, 103 VS_STYPE_MIN, 104 VS_STYPE_HIST, 105 VS_STYPE_TDGST, 106 VS_NUM_STYPES /* +1 to highest numbered stat type. */ 107 }; 108 109 /* 110 * VOI stat data types used as storage for certain stat types and to marshall 111 * data through various API calls. 112 */ 113 enum vsd_dtype { 114 VSD_DTYPE_VOISTATE = 0, /* Reserved for internal API use. */ 115 VSD_DTYPE_INT_S32, /* int32_t */ 116 VSD_DTYPE_INT_U32, /* uint32_t */ 117 VSD_DTYPE_INT_S64, /* int64_t */ 118 VSD_DTYPE_INT_U64, /* uint64_t */ 119 VSD_DTYPE_INT_SLONG, /* long */ 120 VSD_DTYPE_INT_ULONG, /* unsigned long */ 121 VSD_DTYPE_Q_S32, /* s32q_t */ 122 VSD_DTYPE_Q_U32, /* u32q_t */ 123 VSD_DTYPE_Q_S64, /* s64q_t */ 124 VSD_DTYPE_Q_U64, /* u64q_t */ 125 VSD_DTYPE_CRHIST32, /* continuous range histogram, 32bit buckets */ 126 VSD_DTYPE_DRHIST32, /* discrete range histogram, 32bit buckets */ 127 VSD_DTYPE_DVHIST32, /* discrete value histogram, 32bit buckets */ 128 VSD_DTYPE_CRHIST64, /* continuous range histogram, 64bit buckets */ 129 VSD_DTYPE_DRHIST64, /* discrete range histogram, 64bit buckets */ 130 VSD_DTYPE_DVHIST64, /* discrete value histogram, 64bit buckets */ 131 VSD_DTYPE_TDGSTCLUST32, /* clustering variant t-digest, 32bit buckets */ 132 VSD_DTYPE_TDGSTCLUST64, /* clustering variant t-digest, 64bit buckets */ 133 VSD_NUM_DTYPES /* +1 to highest numbered data type. */ 134 }; 135 136 struct voistatdata_int32 { 137 union { 138 int32_t s32; 139 uint32_t u32; 140 }; 141 }; 142 143 struct voistatdata_int64 { 144 union { 145 int64_t s64; 146 uint64_t u64; 147 //counter_u64_t u64pcpu; 148 }; 149 }; 150 151 struct voistatdata_intlong { 152 union { 153 long slong; 154 unsigned long ulong; 155 }; 156 }; 157 158 struct voistatdata_q32 { 159 union { 160 s32q_t sq32; 161 u32q_t uq32; 162 }; 163 }; 164 165 struct voistatdata_q64 { 166 union { 167 s64q_t sq64; 168 u64q_t uq64; 169 }; 170 }; 171 172 struct voistatdata_numeric { 173 union { 174 struct { 175 #if BYTE_ORDER == BIG_ENDIAN 176 uint32_t pad; 177 #endif 178 union { 179 int32_t s32; 180 uint32_t u32; 181 }; 182 #if BYTE_ORDER == LITTLE_ENDIAN 183 uint32_t pad; 184 #endif 185 } int32; 186 187 struct { 188 #if BYTE_ORDER == BIG_ENDIAN 189 uint32_t pad; 190 #endif 191 union { 192 s32q_t sq32; 193 u32q_t uq32; 194 }; 195 #if BYTE_ORDER == LITTLE_ENDIAN 196 uint32_t pad; 197 #endif 198 } q32; 199 200 struct { 201 #if BYTE_ORDER == BIG_ENDIAN && LONG_BIT == 32 202 uint32_t pad; 203 #endif 204 union { 205 long slong; 206 unsigned long ulong; 207 }; 208 #if BYTE_ORDER == LITTLE_ENDIAN && LONG_BIT == 32 209 uint32_t pad; 210 #endif 211 } intlong; 212 213 struct voistatdata_int64 int64; 214 struct voistatdata_q64 q64; 215 }; 216 }; 217 218 /* Continuous range histogram with 32bit buckets. */ 219 struct voistatdata_crhist32 { 220 uint32_t oob; 221 struct { 222 struct voistatdata_numeric lb; 223 uint32_t cnt; 224 } bkts[]; 225 }; 226 227 /* Continuous range histogram with 64bit buckets. */ 228 struct voistatdata_crhist64 { 229 uint64_t oob; 230 struct { 231 struct voistatdata_numeric lb; 232 uint64_t cnt; 233 } bkts[]; 234 }; 235 236 /* Discrete range histogram with 32bit buckets. */ 237 struct voistatdata_drhist32 { 238 uint32_t oob; 239 struct { 240 struct voistatdata_numeric lb, ub; 241 uint32_t cnt; 242 } bkts[]; 243 }; 244 245 /* Discrete range histogram with 64bit buckets. */ 246 struct voistatdata_drhist64 { 247 uint64_t oob; 248 struct { 249 struct voistatdata_numeric lb, ub; 250 uint64_t cnt; 251 } bkts[]; 252 }; 253 254 /* Discrete value histogram with 32bit buckets. */ 255 struct voistatdata_dvhist32 { 256 uint32_t oob; 257 struct { 258 struct voistatdata_numeric val; 259 uint32_t cnt; 260 } bkts[]; 261 }; 262 263 /* Discrete value histogram with 64bit buckets. */ 264 struct voistatdata_dvhist64 { 265 uint64_t oob; 266 struct { 267 struct voistatdata_numeric val; 268 uint64_t cnt; 269 } bkts[]; 270 }; 271 272 struct voistatdata_hist { 273 union { 274 struct voistatdata_crhist32 crhist32; 275 struct voistatdata_crhist64 crhist64; 276 struct voistatdata_dvhist32 dvhist32; 277 struct voistatdata_dvhist64 dvhist64; 278 struct voistatdata_drhist32 drhist32; 279 struct voistatdata_drhist64 drhist64; 280 }; 281 }; 282 283 struct voistatdata_tdgstctd32 { 284 ARB16_ENTRY() ctdlnk; 285 #ifdef DIAGNOSTIC 286 RB_ENTRY(voistatdata_tdgstctd32) rblnk; 287 #endif 288 s32q_t mu; 289 int32_t cnt; 290 }; 291 292 struct voistatdata_tdgstctd64 { 293 ARB16_ENTRY() ctdlnk; 294 #ifdef DIAGNOSTIC 295 RB_ENTRY(voistatdata_tdgstctd64) rblnk; 296 #endif 297 s64q_t mu; 298 int64_t cnt; 299 }; 300 301 struct voistatdata_tdgstctd { 302 union { 303 struct voistatdata_tdgstctd32 tdgstctd32; 304 struct voistatdata_tdgstctd64 tdgstctd64; 305 }; 306 }; 307 308 /* Clustering variant, fixed-point t-digest with 32bit mu/counts. */ 309 struct voistatdata_tdgstclust32 { 310 uint32_t smplcnt; /* Count of samples. */ 311 uint32_t compcnt; /* Count of digest compressions. */ 312 #ifdef DIAGNOSTIC 313 RB_HEAD(rbctdth32, voistatdata_tdgstctd32) rbctdtree; 314 #endif 315 /* Array-based red-black tree of centroids. */ 316 ARB16_HEAD(ctdth32, voistatdata_tdgstctd32) ctdtree; 317 }; 318 319 /* Clustering variant, fixed-point t-digest with 64bit mu/counts. */ 320 struct voistatdata_tdgstclust64 { 321 uint64_t smplcnt; /* Count of samples. */ 322 uint32_t compcnt; /* Count of digest compressions. */ 323 #ifdef DIAGNOSTIC 324 RB_HEAD(rbctdth64, voistatdata_tdgstctd64) rbctdtree; 325 #endif 326 /* Array-based red-black tree of centroids. */ 327 ARB16_HEAD(ctdth64, voistatdata_tdgstctd64) ctdtree; 328 }; 329 330 struct voistatdata_tdgst { 331 union { 332 struct voistatdata_tdgstclust32 tdgstclust32; 333 struct voistatdata_tdgstclust64 tdgstclust64; 334 }; 335 }; 336 337 struct voistatdata { 338 union { 339 struct voistatdata_int32 int32; 340 struct voistatdata_int64 int64; 341 struct voistatdata_intlong intlong; 342 struct voistatdata_q32 q32; 343 struct voistatdata_q64 q64; 344 struct voistatdata_crhist32 crhist32; 345 struct voistatdata_crhist64 crhist64; 346 struct voistatdata_dvhist32 dvhist32; 347 struct voistatdata_dvhist64 dvhist64; 348 struct voistatdata_drhist32 drhist32; 349 struct voistatdata_drhist64 drhist64; 350 struct voistatdata_tdgstclust32 tdgstclust32; 351 struct voistatdata_tdgstclust64 tdgstclust64; 352 }; 353 }; 354 355 #define VSD_HIST_LBOUND_INF 0x01 356 #define VSD_HIST_UBOUND_INF 0x02 357 struct vss_hist_hlpr_info { 358 enum hist_bkt_alloc { 359 BKT_LIN, /* Linear steps. */ 360 BKT_EXP, /* Exponential steps. */ 361 BKT_LINEXP, /* Exponential steps, linear sub-steps. */ 362 BKT_USR /* User specified buckets. */ 363 } scheme; 364 enum vsd_dtype voi_dtype; 365 enum vsd_dtype hist_dtype; 366 uint32_t flags; 367 struct voistatdata_numeric lb; 368 struct voistatdata_numeric ub; 369 union { 370 struct { 371 const uint64_t stepinc; 372 } lin; 373 struct { 374 const uint64_t stepbase; 375 const uint64_t stepexp; 376 } exp; 377 struct { 378 const uint64_t stepbase; 379 const uint64_t linstepdiv; 380 } linexp; 381 struct { 382 const uint16_t nbkts; 383 const struct { 384 struct voistatdata_numeric lb, ub; 385 } *bkts; 386 } usr; 387 }; 388 }; 389 390 struct vss_tdgst_hlpr_info { 391 enum vsd_dtype voi_dtype; 392 enum vsd_dtype tdgst_dtype; 393 uint32_t nctds; 394 uint32_t prec; 395 } __aligned(sizeof(void *)); 396 397 struct vss_numeric_hlpr_info { 398 uint32_t prec; 399 }; 400 401 struct vss_hlpr_info { 402 union { 403 struct vss_tdgst_hlpr_info tdgst; 404 struct vss_hist_hlpr_info hist; 405 struct vss_numeric_hlpr_info numeric; 406 }; 407 }; 408 409 struct voistatspec; 410 typedef int (*vss_hlpr_fn)(enum vsd_dtype, struct voistatspec *, 411 struct vss_hlpr_info *); 412 413 struct voistatspec { 414 vss_hlpr_fn hlpr; /* iv helper function. */ 415 struct vss_hlpr_info *hlprinfo; /* Helper function context. */ 416 struct voistatdata *iv; /* Initialisation value. */ 417 size_t vsdsz; /* Size of iv. */ 418 uint32_t flags; /* Stat flags. */ 419 enum vsd_dtype vs_dtype : 8; /* Stat's dtype. */ 420 enum voi_stype stype : 8; /* Stat type. */ 421 }; 422 423 extern const char *vs_stype2name[VS_NUM_STYPES]; 424 extern const char *vs_stype2desc[VS_NUM_STYPES]; 425 extern const char *vsd_dtype2name[VSD_NUM_DTYPES]; 426 extern const size_t vsd_dtype2size[VSD_NUM_DTYPES]; 427 #define LIM_MIN 0 428 #define LIM_MAX 1 429 extern const struct voistatdata_numeric numeric_limits[2][VSD_DTYPE_Q_U64 + 1]; 430 431 #define TYPEOF_MEMBER(type, member) __typeof(((type *)0)->member) 432 #define TYPEOF_MEMBER_PTR(type, member) __typeof(*(((type *)0)->member)) 433 #define SIZEOF_MEMBER(type, member) sizeof(TYPEOF_MEMBER(type, member)) 434 435 /* Cast a pointer to a voistatdata struct of requested type. */ 436 #define _VSD(cnst, type, ptr) ((cnst struct voistatdata_##type *)(ptr)) 437 #define VSD(type, ptr) _VSD(, type, ptr) 438 #define CONSTVSD(type, ptr) _VSD(const, type, ptr) 439 440 #define NVSS(vss_slots) (sizeof((vss_slots)) / sizeof(struct voistatspec)) 441 #define STATS_VSS(st, vsf, dt, hlp, hlpi) \ 442 ((struct voistatspec){ \ 443 .stype = (st), \ 444 .flags = (vsf), \ 445 .vs_dtype = (dt), \ 446 .hlpr = (hlp), \ 447 .hlprinfo = (hlpi), \ 448 }) 449 450 #define STATS_VSS_SUM() STATS_VSS(VS_STYPE_SUM, 0, 0, \ 451 (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL) 452 453 #define STATS_VSS_MAX() STATS_VSS(VS_STYPE_MAX, 0, 0, \ 454 (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL) 455 456 #define STATS_VSS_MIN() STATS_VSS(VS_STYPE_MIN, 0, 0, \ 457 (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL) 458 459 #define STATS_VSS_HIST(htype, hist_hlpr_info) STATS_VSS(VS_STYPE_HIST, 0, \ 460 htype, (vss_hlpr_fn)&stats_vss_hist_hlpr, \ 461 (struct vss_hlpr_info *)(hist_hlpr_info)) 462 463 #define STATS_VSS_TDIGEST(tdtype, tdgst_hlpr_info) STATS_VSS(VS_STYPE_TDGST, \ 464 0, tdtype, (vss_hlpr_fn)&stats_vss_tdgst_hlpr, \ 465 (struct vss_hlpr_info *)(tdgst_hlpr_info)) 466 467 #define TDGST_NCTRS2VSDSZ(tdtype, nctds) (sizeof(struct voistatdata_##tdtype) + \ 468 ((nctds) * sizeof(TYPEOF_MEMBER_PTR(struct voistatdata_##tdtype, \ 469 ctdtree.arb_nodes)))) 470 471 #define TDGST_HLPR_INFO(dt, nc, nf) \ 472 (&(struct vss_tdgst_hlpr_info){ \ 473 .tdgst_dtype = (dt), \ 474 .nctds = (nc), \ 475 .prec = (nf) \ 476 }) 477 478 #define STATS_VSS_TDGSTCLUST32(nctds, prec) \ 479 STATS_VSS_TDIGEST(VSD_DTYPE_TDGSTCLUST32, \ 480 TDGST_HLPR_INFO(VSD_DTYPE_TDGSTCLUST32, nctds, prec)) 481 482 #define STATS_VSS_TDGSTCLUST64(nctds, prec) \ 483 STATS_VSS_TDIGEST(VSD_DTYPE_TDGSTCLUST64, \ 484 TDGST_HLPR_INFO(VSD_DTYPE_TDGSTCLUST64, nctds, prec)) 485 486 #define HIST_VSDSZ2NBKTS(htype, dsz) \ 487 ((dsz - sizeof(struct voistatdata_##htype)) / \ 488 sizeof(TYPEOF_MEMBER(struct voistatdata_##htype, bkts[0]))) 489 490 #define HIST_NBKTS2VSDSZ(htype, nbkts) (sizeof(struct voistatdata_##htype) + \ 491 ((nbkts) * sizeof(TYPEOF_MEMBER_PTR(struct voistatdata_##htype, bkts)))) 492 493 #define HIST_HLPR_INFO_LIN_FIELDS(si) .lin.stepinc = (si) 494 495 #define HIST_HLPR_INFO_EXP_FIELDS(sb, se) \ 496 .exp.stepbase = (sb), .exp.stepexp = (se) 497 498 #define HIST_HLPR_INFO_LINEXP_FIELDS(nss, sb) \ 499 .linexp.linstepdiv = (nss), .linexp.stepbase = (sb) 500 501 #define HIST_HLPR_INFO_USR_FIELDS(bbs) \ 502 .usr.bkts = (TYPEOF_MEMBER(struct vss_hist_hlpr_info, usr.bkts))(bbs), \ 503 .usr.nbkts = (sizeof(bbs) / sizeof(struct voistatdata_numeric[2])) 504 505 #define HIST_HLPR_INFO(dt, sch, f, lbd, ubd, bkthlpr_fields) \ 506 (&(struct vss_hist_hlpr_info){ \ 507 .scheme = (sch), \ 508 .hist_dtype = (dt), \ 509 .flags = (f), \ 510 .lb = stats_ctor_vsd_numeric(lbd), \ 511 .ub = stats_ctor_vsd_numeric(ubd), \ 512 bkthlpr_fields \ 513 }) 514 515 #define STATS_VSS_CRHIST32_LIN(lb, ub, stepinc, vsdflags) \ 516 STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \ 517 BKT_LIN, vsdflags, lb, ub, HIST_HLPR_INFO_LIN_FIELDS(stepinc))) 518 #define STATS_VSS_CRHIST64_LIN(lb, ub, stepinc, vsdflags) \ 519 STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \ 520 BKT_LIN, vsdflags, lb, ub, HIST_HLPR_INFO_LIN_FIELDS(stepinc))) 521 522 #define STATS_VSS_CRHIST32_EXP(lb, ub, stepbase, stepexp, vsdflags) \ 523 STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \ 524 BKT_EXP, vsdflags, lb, ub, HIST_HLPR_INFO_EXP_FIELDS(stepbase, stepexp))) 525 #define STATS_VSS_CRHIST64_EXP(lb, ub, stepbase, stepexp, vsdflags) \ 526 STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \ 527 BKT_EXP, vsdflags, lb, ub, HIST_HLPR_INFO_EXP_FIELDS(stepbase, stepexp))) 528 529 #define STATS_VSS_CRHIST32_LINEXP(lb, ub, nlinsteps, stepbase, vsdflags) \ 530 STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \ 531 BKT_LINEXP, vsdflags, lb, ub, HIST_HLPR_INFO_LINEXP_FIELDS(nlinsteps, \ 532 stepbase))) 533 #define STATS_VSS_CRHIST64_LINEXP(lb, ub, nlinsteps, stepbase, vsdflags) \ 534 STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \ 535 BKT_LINEXP, vsdflags, lb, ub, HIST_HLPR_INFO_LINEXP_FIELDS(nlinsteps, \ 536 stepbase))) 537 538 #define STATS_VSS_CRHIST32_USR(bkts, vsdflags) \ 539 STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \ 540 BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts))) 541 #define STATS_VSS_CRHIST64_USR(bkts, vsdflags) \ 542 STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \ 543 BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts))) 544 545 #define STATS_VSS_DRHIST32_USR(bkts, vsdflags) \ 546 STATS_VSS_HIST(VSD_DTYPE_DRHIST32, HIST_HLPR_INFO(VSD_DTYPE_DRHIST32, \ 547 BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts))) 548 #define STATS_VSS_DRHIST64_USR(bkts, vsdflags) \ 549 STATS_VSS_HIST(VSD_DTYPE_DRHIST64, HIST_HLPR_INFO(VSD_DTYPE_DRHIST64, \ 550 BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts))) 551 552 #define STATS_VSS_DVHIST32_USR(vals, vsdflags) \ 553 STATS_VSS_HIST(VSD_DTYPE_DVHIST32, HIST_HLPR_INFO(VSD_DTYPE_DVHIST32, \ 554 BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(vals))) 555 #define STATS_VSS_DVHIST64_USR(vals, vsdflags) \ 556 STATS_VSS_HIST(VSD_DTYPE_DVHIST64, HIST_HLPR_INFO(VSD_DTYPE_DVHIST64, \ 557 BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(vals))) 558 #define DRBKT(lb, ub) { stats_ctor_vsd_numeric(lb), stats_ctor_vsd_numeric(ub) } 559 #define DVBKT(val) DRBKT(val, val) 560 #define CRBKT(lb) DRBKT(lb, lb) 561 #define HBKTS(...) ((struct voistatdata_numeric [][2]){__VA_ARGS__}) 562 563 #define VSD_HIST_FIELD(hist, cnst, hist_dtype, op, field) \ 564 (VSD_DTYPE_CRHIST32 == (hist_dtype) ? \ 565 op(_VSD(cnst, crhist32, hist)->field) : \ 566 (VSD_DTYPE_DRHIST32 == (hist_dtype) ? \ 567 op(_VSD(cnst, drhist32, hist)->field) : \ 568 (VSD_DTYPE_DVHIST32 == (hist_dtype) ? \ 569 op(_VSD(cnst, dvhist32, hist)->field) : \ 570 (VSD_DTYPE_CRHIST64 == (hist_dtype) ? \ 571 op(_VSD(cnst, crhist64, hist)->field) : \ 572 (VSD_DTYPE_DRHIST64 == (hist_dtype) ? \ 573 op(_VSD(cnst, drhist64, hist)->field) : \ 574 (op(_VSD(cnst, dvhist64, hist)->field))))))) 575 #define VSD_HIST_FIELDVAL(hist, hist_dtype, field) \ 576 VSD_HIST_FIELD(hist, , hist_dtype, ,field) 577 #define VSD_CONSTHIST_FIELDVAL(hist, hist_dtype, field) \ 578 VSD_HIST_FIELD(hist, const, hist_dtype, ,field) 579 #define VSD_HIST_FIELDPTR(hist, hist_dtype, field) \ 580 VSD_HIST_FIELD(hist, , hist_dtype, (void *)&,field) 581 #define VSD_CONSTHIST_FIELDPTR(hist, hist_dtype, field) \ 582 VSD_HIST_FIELD(hist, const, hist_dtype, (void *)&,field) 583 584 #define VSD_CRHIST_FIELD(hist, cnst, hist_dtype, op, field) \ 585 (VSD_DTYPE_CRHIST32 == (hist_dtype) ? \ 586 op(_VSD(cnst, crhist32, hist)->field) : \ 587 op(_VSD(cnst, crhist64, hist)->field)) 588 #define VSD_CRHIST_FIELDVAL(hist, hist_dtype, field) \ 589 VSD_CRHIST_FIELD(hist, , hist_dtype, , field) 590 #define VSD_CONSTCRHIST_FIELDVAL(hist, hist_dtype, field) \ 591 VSD_CRHIST_FIELD(hist, const, hist_dtype, , field) 592 #define VSD_CRHIST_FIELDPTR(hist, hist_dtype, field) \ 593 VSD_CRHIST_FIELD(hist, , hist_dtype, &, field) 594 #define VSD_CONSTCRHIST_FIELDPTR(hist, hist_dtype, field) \ 595 VSD_CRHIST_FIELD(hist, const, hist_dtype, &, field) 596 597 #define VSD_DRHIST_FIELD(hist, cnst, hist_dtype, op, field) \ 598 (VSD_DTYPE_DRHIST32 == (hist_dtype) ? \ 599 op(_VSD(cnst, drhist32, hist)->field) : \ 600 op(_VSD(cnst, drhist64, hist)->field)) 601 #define VSD_DRHIST_FIELDVAL(hist, hist_dtype, field) \ 602 VSD_DRHIST_FIELD(hist, , hist_dtype, , field) 603 #define VSD_CONSTDRHIST_FIELDVAL(hist, hist_dtype, field) \ 604 VSD_DRHIST_FIELD(hist, const, hist_dtype, , field) 605 #define VSD_DRHIST_FIELDPTR(hist, hist_dtype, field) \ 606 VSD_DRHIST_FIELD(hist, , hist_dtype, &, field) 607 #define VSD_CONSTDRHIST_FIELDPTR(hist, hist_dtype, field) \ 608 VSD_DRHIST_FIELD(hist, const, hist_dtype, &, field) 609 610 #define VSD_DVHIST_FIELD(hist, cnst, hist_dtype, op, field) \ 611 (VSD_DTYPE_DVHIST32 == (hist_dtype) ? \ 612 op(_VSD(cnst, dvhist32, hist)->field) : \ 613 op(_VSD(cnst, dvhist64, hist)->field)) 614 #define VSD_DVHIST_FIELDVAL(hist, hist_dtype, field) \ 615 VSD_DVHIST_FIELD(hist, , hist_dtype, , field) 616 #define VSD_CONSTDVHIST_FIELDVAL(hist, hist_dtype, field) \ 617 VSD_DVHIST_FIELD(hist, const, hist_dtype, , field) 618 #define VSD_DVHIST_FIELDPTR(hist, hist_dtype, field) \ 619 VSD_DVHIST_FIELD(hist, , hist_dtype, &, field) 620 #define VSD_CONSTDVHIST_FIELDPTR(hist, hist_dtype, field) \ 621 VSD_DVHIST_FIELD(hist, const, hist_dtype, &, field) 622 623 #define STATS_ABI_V1 1 624 struct statsblobv1; 625 626 enum sb_endianness { 627 SB_UE = 0, /* Unknown endian. */ 628 SB_LE, /* Little endian. */ 629 SB_BE /* Big endian. */ 630 }; 631 632 struct statsblob { 633 uint8_t abi; 634 uint8_t endian; 635 uint16_t flags; 636 uint16_t maxsz; 637 uint16_t cursz; 638 uint8_t opaque[]; 639 } __aligned(sizeof(void *)); 640 641 struct metablob { 642 char *tplname; 643 uint32_t tplhash; 644 struct voi_meta { 645 char *name; 646 char *desc; 647 } *voi_meta; 648 }; 649 650 struct statsblob_tpl { 651 struct metablob *mb; /* Template metadata */ 652 struct statsblob *sb; /* Template schema */ 653 }; 654 655 struct stats_tpl_sample_rate { 656 /* XXXLAS: Storing slot_id assumes templates are never removed. */ 657 int32_t tpl_slot_id; 658 uint32_t tpl_sample_pct; 659 }; 660 661 /* Template sample rates list management callback actions. */ 662 enum stats_tpl_sr_cb_action { 663 TPL_SR_UNLOCKED_GET, 664 TPL_SR_RLOCKED_GET, 665 TPL_SR_RUNLOCK, 666 TPL_SR_PUT 667 }; 668 669 /* 670 * Callback function pointer passed as arg1 to stats_tpl_sample_rates(). ctx is 671 * a heap-allocated, zero-initialised blob of contextual memory valid during a 672 * single stats_tpl_sample_rates() call and sized per the value passed as arg2. 673 * Returns 0 on success, an errno on error. 674 * - When called with "action == TPL_SR_*_GET", return the subsystem's rates 675 * list ptr and count, locked or unlocked as requested. 676 * - When called with "action == TPL_SR_RUNLOCK", unlock the subsystem's rates 677 * list ptr and count. Pair with a prior "action == TPL_SR_RLOCKED_GET" call. 678 * - When called with "action == TPL_SR_PUT, update the subsystem's rates list 679 * ptr and count to the sysctl processed values and return the inactive list 680 * details in rates/nrates for garbage collection by stats_tpl_sample_rates(). 681 */ 682 typedef int (*stats_tpl_sr_cb_t)(enum stats_tpl_sr_cb_action action, 683 struct stats_tpl_sample_rate **rates, int *nrates, void *ctx); 684 685 /* Flags related to iterating over a stats blob. */ 686 #define SB_IT_FIRST_CB 0x0001 687 #define SB_IT_LAST_CB 0x0002 688 #define SB_IT_FIRST_VOI 0x0004 689 #define SB_IT_LAST_VOI 0x0008 690 #define SB_IT_FIRST_VOISTAT 0x0010 691 #define SB_IT_LAST_VOISTAT 0x0020 692 #define SB_IT_NULLVOI 0x0040 693 #define SB_IT_NULLVOISTAT 0x0080 694 695 struct sb_visit { 696 struct voistatdata *vs_data; 697 uint32_t tplhash; 698 uint32_t flags; 699 int16_t voi_id; 700 int16_t vs_dsz; 701 uint16_t vs_errs; 702 enum vsd_dtype voi_dtype : 8; 703 enum vsd_dtype vs_dtype : 8; 704 int8_t vs_stype; 705 }; 706 707 /* Stats blob iterator callback called for each struct voi. */ 708 typedef int (*stats_blob_visitcb_t)(struct sb_visit *sbv, void *usrctx); 709 710 /* ABI specific functions. */ 711 int stats_v1_tpl_alloc(const char *name, uint32_t flags); 712 int stats_v1_tpl_add_voistats(uint32_t tpl_id, int32_t voi_id, 713 const char *voi_name, enum vsd_dtype voi_dtype, uint32_t nvss, 714 struct voistatspec *vss, uint32_t flags); 715 int stats_v1_blob_init(struct statsblobv1 *sb, uint32_t tpl_id, uint32_t flags); 716 struct statsblobv1 * stats_v1_blob_alloc(uint32_t tpl_id, uint32_t flags); 717 int stats_v1_blob_clone(struct statsblobv1 **dst, size_t dstmaxsz, 718 struct statsblobv1 *src, uint32_t flags); 719 void stats_v1_blob_destroy(struct statsblobv1 *sb); 720 #define SB_CLONE_RSTSRC 0x0001 /* Reset src blob if clone successful. */ 721 #define SB_CLONE_ALLOCDST 0x0002 /* Allocate src->cursz memory for dst. */ 722 #define SB_CLONE_USRDSTNOFAULT 0x0004 /* Clone to wired userspace dst. */ 723 #define SB_CLONE_USRDST 0x0008 /* Clone to unwired userspace dst. */ 724 int stats_v1_blob_snapshot(struct statsblobv1 **dst, size_t dstmaxsz, 725 struct statsblobv1 *src, uint32_t flags); 726 #define SB_TOSTR_OBJDUMP 0x00000001 727 #define SB_TOSTR_META 0x00000002 /* Lookup metablob and render metadata */ 728 int stats_v1_blob_tostr(struct statsblobv1 *sb, struct sbuf *buf, 729 enum sb_str_fmt fmt, uint32_t flags); 730 int stats_v1_blob_visit(struct statsblobv1 *sb, stats_blob_visitcb_t func, 731 void *usrctx); 732 /* VOI related function flags. */ 733 #define SB_VOI_RELUPDATE 0x00000001 /* voival is relative to previous value. */ 734 int stats_v1_voi_update(struct statsblobv1 *sb, int32_t voi_id, 735 enum vsd_dtype voi_dtype, struct voistatdata *voival, uint32_t flags); 736 int stats_v1_voistat_fetch_dptr(struct statsblobv1 *sb, int32_t voi_id, 737 enum voi_stype stype, enum vsd_dtype *retdtype, struct voistatdata **retvsd, 738 size_t *retvsdsz); 739 740 /* End ABI specific functions. */ 741 742 /* ABI agnostic functions. */ 743 int stats_vss_hlpr_init(enum vsd_dtype voi_dtype, uint32_t nvss, 744 struct voistatspec *vss); 745 void stats_vss_hlpr_cleanup(uint32_t nvss, struct voistatspec *vss); 746 int stats_vss_hist_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss, 747 struct vss_hist_hlpr_info *info); 748 int stats_vss_numeric_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss, 749 struct vss_numeric_hlpr_info *info); 750 int stats_vss_tdgst_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss, 751 struct vss_tdgst_hlpr_info *info); 752 int stats_tpl_fetch(int tpl_id, struct statsblob_tpl **tpl); 753 int stats_tpl_fetch_allocid(const char *name, uint32_t hash); 754 int stats_tpl_id2name(uint32_t tpl_id, char *buf, size_t len); 755 int stats_tpl_sample_rates(struct sysctl_oid *oidp, void *arg1, intmax_t arg2, 756 struct sysctl_req *req); 757 int stats_tpl_sample_rollthedice(struct stats_tpl_sample_rate *rates, 758 int nrates, void *seed_bytes, size_t seed_len); 759 int stats_voistatdata_tostr(const struct voistatdata *vsd, 760 enum vsd_dtype voi_dtype, enum vsd_dtype vsd_dtype, size_t vsd_sz, 761 enum sb_str_fmt fmt, struct sbuf *buf, int objdump); 762 763 static inline struct voistatdata_numeric 764 stats_ctor_vsd_numeric(uint64_t val) 765 { 766 struct voistatdata_numeric tmp; 767 768 tmp.int64.u64 = val; 769 770 return (tmp); 771 } 772 773 static inline int 774 stats_tpl_alloc(const char *name, uint32_t flags) 775 { 776 777 return (stats_v1_tpl_alloc(name, flags)); 778 } 779 780 static inline int 781 stats_tpl_add_voistats(uint32_t tpl_id, int32_t voi_id, const char *voi_name, 782 enum vsd_dtype voi_dtype, uint32_t nvss, struct voistatspec *vss, 783 uint32_t flags) 784 { 785 int ret; 786 787 if ((ret = stats_vss_hlpr_init(voi_dtype, nvss, vss)) == 0) { 788 ret = stats_v1_tpl_add_voistats(tpl_id, voi_id, voi_name, 789 voi_dtype, nvss, vss, flags); 790 } 791 stats_vss_hlpr_cleanup(nvss, vss); 792 793 return (ret); 794 } 795 796 static inline int 797 stats_blob_init(struct statsblob *sb, uint32_t tpl_id, uint32_t flags) 798 { 799 800 return (stats_v1_blob_init((struct statsblobv1 *)sb, tpl_id, flags)); 801 } 802 803 static inline struct statsblob * 804 stats_blob_alloc(uint32_t tpl_id, uint32_t flags) 805 { 806 807 return ((struct statsblob *)stats_v1_blob_alloc(tpl_id, flags)); 808 } 809 810 static inline int 811 stats_blob_clone(struct statsblob **dst, size_t dstmaxsz, struct statsblob *src, 812 uint32_t flags) 813 { 814 815 return (stats_v1_blob_clone((struct statsblobv1 **)dst, dstmaxsz, 816 (struct statsblobv1 *)src, flags)); 817 } 818 819 static inline void 820 stats_blob_destroy(struct statsblob *sb) 821 { 822 823 stats_v1_blob_destroy((struct statsblobv1 *)sb); 824 } 825 826 static inline int 827 stats_blob_visit(struct statsblob *sb, stats_blob_visitcb_t func, void *usrctx) 828 { 829 830 return (stats_v1_blob_visit((struct statsblobv1 *)sb, func, usrctx)); 831 } 832 833 static inline int 834 stats_blob_tostr(struct statsblob *sb, struct sbuf *buf, 835 enum sb_str_fmt fmt, uint32_t flags) 836 { 837 838 return (stats_v1_blob_tostr((struct statsblobv1 *)sb, buf, fmt, flags)); 839 } 840 841 static inline int 842 stats_voistat_fetch_dptr(struct statsblob *sb, int32_t voi_id, 843 enum voi_stype stype, enum vsd_dtype *retdtype, struct voistatdata **retvsd, 844 size_t *retvsdsz) 845 { 846 847 return (stats_v1_voistat_fetch_dptr((struct statsblobv1 *)sb, 848 voi_id, stype, retdtype, retvsd, retvsdsz)); 849 } 850 851 static inline int 852 stats_voistat_fetch_s64(struct statsblob *sb, int32_t voi_id, 853 enum voi_stype stype, int64_t *ret) 854 { 855 struct voistatdata *vsd; 856 enum vsd_dtype vs_dtype; 857 int error; 858 859 if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd, 860 NULL))) 861 return (error); 862 else if (VSD_DTYPE_INT_S64 != vs_dtype) 863 return (EFTYPE); 864 865 *ret = vsd->int64.s64; 866 return (0); 867 } 868 869 static inline int 870 stats_voistat_fetch_u64(struct statsblob *sb, int32_t voi_id, 871 enum voi_stype stype, uint64_t *ret) 872 { 873 struct voistatdata *vsd; 874 enum vsd_dtype vs_dtype; 875 int error; 876 877 if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd, 878 NULL))) 879 return (error); 880 else if (VSD_DTYPE_INT_U64 != vs_dtype) 881 return (EFTYPE); 882 883 *ret = vsd->int64.u64; 884 return (0); 885 } 886 887 static inline int 888 stats_voistat_fetch_s32(struct statsblob *sb, int32_t voi_id, 889 enum voi_stype stype, int32_t *ret) 890 { 891 struct voistatdata *vsd; 892 enum vsd_dtype vs_dtype; 893 int error; 894 895 if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd, 896 NULL))) 897 return (error); 898 else if (VSD_DTYPE_INT_S32 != vs_dtype) 899 return (EFTYPE); 900 901 *ret = vsd->int32.s32; 902 return (0); 903 } 904 905 static inline int 906 stats_voistat_fetch_u32(struct statsblob *sb, int32_t voi_id, 907 enum voi_stype stype, uint32_t *ret) 908 { 909 struct voistatdata *vsd; 910 enum vsd_dtype vs_dtype; 911 int error; 912 913 if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd, 914 NULL))) 915 return (error); 916 else if (VSD_DTYPE_INT_U32 != vs_dtype) 917 return (EFTYPE); 918 919 *ret = vsd->int32.u32; 920 return (0); 921 } 922 923 static inline int 924 stats_voistat_fetch_slong(struct statsblob *sb, int32_t voi_id, 925 enum voi_stype stype, long *ret) 926 { 927 struct voistatdata *vsd; 928 enum vsd_dtype vs_dtype; 929 int error; 930 931 if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd, 932 NULL))) 933 return (error); 934 else if (VSD_DTYPE_INT_SLONG != vs_dtype) 935 return (EFTYPE); 936 937 *ret = vsd->intlong.slong; 938 return (0); 939 } 940 941 static inline int 942 stats_voistat_fetch_ulong(struct statsblob *sb, int32_t voi_id, 943 enum voi_stype stype, unsigned long *ret) 944 { 945 struct voistatdata *vsd; 946 enum vsd_dtype vs_dtype; 947 int error; 948 949 if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd, 950 NULL))) 951 return (error); 952 else if (VSD_DTYPE_INT_ULONG != vs_dtype) 953 return (EFTYPE); 954 955 *ret = vsd->intlong.ulong; 956 return (0); 957 } 958 959 static inline int 960 stats_blob_snapshot(struct statsblob **dst, size_t dstmaxsz, 961 struct statsblob *src, uint32_t flags) 962 { 963 964 return (stats_v1_blob_snapshot((struct statsblobv1 **)dst, dstmaxsz, 965 (struct statsblobv1 *)src, flags)); 966 } 967 968 static inline int 969 stats_voi_update_abs_s32(struct statsblob *sb, int32_t voi_id, int32_t voival) 970 { 971 972 if (sb == NULL) 973 return (0); 974 975 struct voistatdata tmp; 976 tmp.int32.s32 = voival; 977 978 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 979 VSD_DTYPE_INT_S32, &tmp, 0)); 980 } 981 982 static inline int 983 stats_voi_update_rel_s32(struct statsblob *sb, int32_t voi_id, int32_t voival) 984 { 985 986 if (sb == NULL) 987 return (0); 988 989 struct voistatdata tmp; 990 tmp.int32.s32 = voival; 991 992 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 993 VSD_DTYPE_INT_S32, &tmp, SB_VOI_RELUPDATE)); 994 } 995 996 static inline int 997 stats_voi_update_abs_u32(struct statsblob *sb, int32_t voi_id, uint32_t voival) 998 { 999 1000 if (sb == NULL) 1001 return (0); 1002 1003 struct voistatdata tmp; 1004 tmp.int32.u32 = voival; 1005 1006 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1007 VSD_DTYPE_INT_U32, &tmp, 0)); 1008 } 1009 1010 static inline int 1011 stats_voi_update_rel_u32(struct statsblob *sb, int32_t voi_id, uint32_t voival) 1012 { 1013 1014 if (sb == NULL) 1015 return (0); 1016 1017 struct voistatdata tmp; 1018 tmp.int32.u32 = voival; 1019 1020 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1021 VSD_DTYPE_INT_U32, &tmp, SB_VOI_RELUPDATE)); 1022 } 1023 1024 static inline int 1025 stats_voi_update_abs_s64(struct statsblob *sb, int32_t voi_id, int64_t voival) 1026 { 1027 1028 if (sb == NULL) 1029 return (0); 1030 1031 struct voistatdata tmp; 1032 tmp.int64.s64 = voival; 1033 1034 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1035 VSD_DTYPE_INT_S64, &tmp, 0)); 1036 } 1037 1038 static inline int 1039 stats_voi_update_rel_s64(struct statsblob *sb, int32_t voi_id, int64_t voival) 1040 { 1041 1042 if (sb == NULL) 1043 return (0); 1044 1045 struct voistatdata tmp; 1046 tmp.int64.s64 = voival; 1047 1048 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1049 VSD_DTYPE_INT_S64, &tmp, SB_VOI_RELUPDATE)); 1050 } 1051 1052 static inline int 1053 stats_voi_update_abs_u64(struct statsblob *sb, int32_t voi_id, uint64_t voival) 1054 { 1055 1056 if (sb == NULL) 1057 return (0); 1058 1059 struct voistatdata tmp; 1060 tmp.int64.u64 = voival; 1061 1062 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1063 VSD_DTYPE_INT_U64, &tmp, 0)); 1064 } 1065 1066 static inline int 1067 stats_voi_update_rel_u64(struct statsblob *sb, int32_t voi_id, uint64_t voival) 1068 { 1069 1070 if (sb == NULL) 1071 return (0); 1072 1073 struct voistatdata tmp; 1074 tmp.int64.u64 = voival; 1075 1076 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1077 VSD_DTYPE_INT_U64, &tmp, SB_VOI_RELUPDATE)); 1078 } 1079 1080 static inline int 1081 stats_voi_update_abs_slong(struct statsblob *sb, int32_t voi_id, long voival) 1082 { 1083 1084 if (sb == NULL) 1085 return (0); 1086 1087 struct voistatdata tmp; 1088 tmp.intlong.slong = voival; 1089 1090 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1091 VSD_DTYPE_INT_SLONG, &tmp, 0)); 1092 } 1093 1094 static inline int 1095 stats_voi_update_rel_slong(struct statsblob *sb, int32_t voi_id, long voival) 1096 { 1097 1098 if (sb == NULL) 1099 return (0); 1100 1101 struct voistatdata tmp; 1102 tmp.intlong.slong = voival; 1103 1104 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1105 VSD_DTYPE_INT_SLONG, &tmp, SB_VOI_RELUPDATE)); 1106 } 1107 1108 static inline int 1109 stats_voi_update_abs_ulong(struct statsblob *sb, int32_t voi_id, 1110 unsigned long voival) 1111 { 1112 1113 if (sb == NULL) 1114 return (0); 1115 1116 struct voistatdata tmp; 1117 tmp.intlong.ulong = voival; 1118 1119 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1120 VSD_DTYPE_INT_ULONG, &tmp, 0)); 1121 } 1122 1123 static inline int 1124 stats_voi_update_rel_ulong(struct statsblob *sb, int32_t voi_id, 1125 unsigned long voival) 1126 { 1127 1128 if (sb == NULL) 1129 return (0); 1130 1131 struct voistatdata tmp; 1132 tmp.intlong.ulong = voival; 1133 1134 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1135 VSD_DTYPE_INT_ULONG, &tmp, SB_VOI_RELUPDATE)); 1136 } 1137 1138 static inline int 1139 stats_voi_update_abs_sq32(struct statsblob *sb, int32_t voi_id, s32q_t voival) 1140 { 1141 1142 if (sb == NULL) 1143 return (0); 1144 1145 struct voistatdata tmp; 1146 tmp.q32.sq32 = voival; 1147 1148 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1149 VSD_DTYPE_Q_S32, &tmp, 0)); 1150 } 1151 1152 static inline int 1153 stats_voi_update_rel_sq32(struct statsblob *sb, int32_t voi_id, s32q_t voival) 1154 { 1155 1156 if (sb == NULL) 1157 return (0); 1158 1159 struct voistatdata tmp; 1160 tmp.q32.sq32 = voival; 1161 1162 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1163 VSD_DTYPE_Q_S32, &tmp, SB_VOI_RELUPDATE)); 1164 } 1165 1166 static inline int 1167 stats_voi_update_abs_uq32(struct statsblob *sb, int32_t voi_id, u32q_t voival) 1168 { 1169 1170 if (sb == NULL) 1171 return (0); 1172 1173 struct voistatdata tmp; 1174 tmp.q32.uq32 = voival; 1175 1176 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1177 VSD_DTYPE_Q_U32, &tmp, 0)); 1178 } 1179 1180 static inline int 1181 stats_voi_update_rel_uq32(struct statsblob *sb, int32_t voi_id, u32q_t voival) 1182 { 1183 1184 if (sb == NULL) 1185 return (0); 1186 1187 struct voistatdata tmp; 1188 tmp.q32.uq32 = voival; 1189 1190 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1191 VSD_DTYPE_Q_U32, &tmp, SB_VOI_RELUPDATE)); 1192 } 1193 1194 static inline int 1195 stats_voi_update_abs_sq64(struct statsblob *sb, int32_t voi_id, s64q_t voival) 1196 { 1197 1198 if (sb == NULL) 1199 return (0); 1200 1201 struct voistatdata tmp; 1202 tmp.q64.sq64 = voival; 1203 1204 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1205 VSD_DTYPE_Q_S64, &tmp, 0)); 1206 } 1207 1208 static inline int 1209 stats_voi_update_rel_sq64(struct statsblob *sb, int32_t voi_id, s64q_t voival) 1210 { 1211 1212 if (sb == NULL) 1213 return (0); 1214 1215 struct voistatdata tmp; 1216 tmp.q64.sq64 = voival; 1217 1218 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1219 VSD_DTYPE_Q_S64, &tmp, SB_VOI_RELUPDATE)); 1220 } 1221 1222 static inline int 1223 stats_voi_update_abs_uq64(struct statsblob *sb, int32_t voi_id, u64q_t voival) 1224 { 1225 1226 if (sb == NULL) 1227 return (0); 1228 1229 struct voistatdata tmp; 1230 tmp.q64.uq64 = voival; 1231 1232 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1233 VSD_DTYPE_Q_U64, &tmp, 0)); 1234 } 1235 1236 static inline int 1237 stats_voi_update_rel_uq64(struct statsblob *sb, int32_t voi_id, u64q_t voival) 1238 { 1239 1240 if (sb == NULL) 1241 return (0); 1242 1243 struct voistatdata tmp; 1244 tmp.q64.uq64 = voival; 1245 1246 return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id, 1247 VSD_DTYPE_Q_U64, &tmp, SB_VOI_RELUPDATE)); 1248 } 1249 1250 /* End ABI agnostic functions. */ 1251 1252 #endif /* _SYS_STATS_H_ */ 1253