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
stats_ctor_vsd_numeric(uint64_t val)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
stats_tpl_alloc(const char * name,uint32_t flags)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
stats_tpl_add_voistats(uint32_t tpl_id,int32_t voi_id,const char * voi_name,enum vsd_dtype voi_dtype,uint32_t nvss,struct voistatspec * vss,uint32_t flags)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
stats_blob_init(struct statsblob * sb,uint32_t tpl_id,uint32_t flags)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 *
stats_blob_alloc(uint32_t tpl_id,uint32_t flags)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
stats_blob_clone(struct statsblob ** dst,size_t dstmaxsz,struct statsblob * src,uint32_t flags)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
stats_blob_destroy(struct statsblob * sb)820 stats_blob_destroy(struct statsblob *sb)
821 {
822
823 stats_v1_blob_destroy((struct statsblobv1 *)sb);
824 }
825
826 static inline int
stats_blob_visit(struct statsblob * sb,stats_blob_visitcb_t func,void * usrctx)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
stats_blob_tostr(struct statsblob * sb,struct sbuf * buf,enum sb_str_fmt fmt,uint32_t flags)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
stats_voistat_fetch_dptr(struct statsblob * sb,int32_t voi_id,enum voi_stype stype,enum vsd_dtype * retdtype,struct voistatdata ** retvsd,size_t * retvsdsz)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
stats_voistat_fetch_s64(struct statsblob * sb,int32_t voi_id,enum voi_stype stype,int64_t * ret)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
stats_voistat_fetch_u64(struct statsblob * sb,int32_t voi_id,enum voi_stype stype,uint64_t * ret)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
stats_voistat_fetch_s32(struct statsblob * sb,int32_t voi_id,enum voi_stype stype,int32_t * ret)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
stats_voistat_fetch_u32(struct statsblob * sb,int32_t voi_id,enum voi_stype stype,uint32_t * ret)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
stats_voistat_fetch_slong(struct statsblob * sb,int32_t voi_id,enum voi_stype stype,long * ret)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
stats_voistat_fetch_ulong(struct statsblob * sb,int32_t voi_id,enum voi_stype stype,unsigned long * ret)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
stats_blob_snapshot(struct statsblob ** dst,size_t dstmaxsz,struct statsblob * src,uint32_t flags)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
stats_voi_update_abs_s32(struct statsblob * sb,int32_t voi_id,int32_t voival)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
stats_voi_update_rel_s32(struct statsblob * sb,int32_t voi_id,int32_t voival)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
stats_voi_update_abs_u32(struct statsblob * sb,int32_t voi_id,uint32_t voival)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
stats_voi_update_rel_u32(struct statsblob * sb,int32_t voi_id,uint32_t voival)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
stats_voi_update_abs_s64(struct statsblob * sb,int32_t voi_id,int64_t voival)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
stats_voi_update_rel_s64(struct statsblob * sb,int32_t voi_id,int64_t voival)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
stats_voi_update_abs_u64(struct statsblob * sb,int32_t voi_id,uint64_t voival)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
stats_voi_update_rel_u64(struct statsblob * sb,int32_t voi_id,uint64_t voival)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
stats_voi_update_abs_slong(struct statsblob * sb,int32_t voi_id,long voival)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
stats_voi_update_rel_slong(struct statsblob * sb,int32_t voi_id,long voival)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
stats_voi_update_abs_ulong(struct statsblob * sb,int32_t voi_id,unsigned long voival)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
stats_voi_update_rel_ulong(struct statsblob * sb,int32_t voi_id,unsigned long voival)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
stats_voi_update_abs_sq32(struct statsblob * sb,int32_t voi_id,s32q_t voival)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
stats_voi_update_rel_sq32(struct statsblob * sb,int32_t voi_id,s32q_t voival)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
stats_voi_update_abs_uq32(struct statsblob * sb,int32_t voi_id,u32q_t voival)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
stats_voi_update_rel_uq32(struct statsblob * sb,int32_t voi_id,u32q_t voival)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
stats_voi_update_abs_sq64(struct statsblob * sb,int32_t voi_id,s64q_t voival)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
stats_voi_update_rel_sq64(struct statsblob * sb,int32_t voi_id,s64q_t voival)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
stats_voi_update_abs_uq64(struct statsblob * sb,int32_t voi_id,u64q_t voival)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
stats_voi_update_rel_uq64(struct statsblob * sb,int32_t voi_id,u64q_t voival)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