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