]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/sys/stats.h
Merge ^/head r352764 through r353315.
[FreeBSD/FreeBSD.git] / sys / sys / stats.h
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
62 #ifndef _KERNEL
63 /*
64  * XXXLAS: Hacks to enable sharing template creation code between kernel and
65  * userland e.g. tcp_stats.c
66  */
67 #define VNET(n) n
68 #define VNET_DEFINE(t, n) static t n __unused
69 #endif /* ! _KERNEL */
70
71 #define TPL_MAX_NAME_LEN 64
72
73 /*
74  * The longest template string spec format i.e. the normative spec format, is:
75  *
76  *     "<tplname>":<tplhash>
77  *
78  * Therefore, the max string length of a template string spec is:
79  *
80  * - TPL_MAX_NAME_LEN
81  * - 2 chars for ""
82  * - 1 char for : separating name and hash
83  * - 10 chars for 32bit hash
84  */
85 #define STATS_TPL_MAX_STR_SPEC_LEN (TPL_MAX_NAME_LEN + 13)
86
87 struct sbuf;
88 struct sysctl_oid;
89 struct sysctl_req;
90
91 enum sb_str_fmt {
92         SB_STRFMT_FREEFORM = 0,
93         SB_STRFMT_JSON,
94         SB_STRFMT_NUM_FMTS      /* +1 to highest numbered format type. */
95 };
96
97 /* VOI stat types. */
98 enum voi_stype {
99         VS_STYPE_VOISTATE = 0,  /* Reserved for internal API use. */
100         VS_STYPE_SUM,
101         VS_STYPE_MAX,
102         VS_STYPE_MIN,
103         VS_STYPE_HIST,
104         VS_STYPE_TDGST,
105         VS_NUM_STYPES           /* +1 to highest numbered stat type. */
106 };
107
108 /*
109  * VOI stat data types used as storage for certain stat types and to marshall
110  * data through various API calls.
111  */
112 enum vsd_dtype {
113         VSD_DTYPE_VOISTATE = 0, /* Reserved for internal API use. */
114         VSD_DTYPE_INT_S32,      /* int32_t */
115         VSD_DTYPE_INT_U32,      /* uint32_t */
116         VSD_DTYPE_INT_S64,      /* int64_t */
117         VSD_DTYPE_INT_U64,      /* uint64_t */
118         VSD_DTYPE_INT_SLONG,    /* long */
119         VSD_DTYPE_INT_ULONG,    /* unsigned long */
120         VSD_DTYPE_Q_S32,        /* s32q_t */
121         VSD_DTYPE_Q_U32,        /* u32q_t */
122         VSD_DTYPE_Q_S64,        /* s64q_t */
123         VSD_DTYPE_Q_U64,        /* u64q_t */
124         VSD_DTYPE_CRHIST32,     /* continuous range histogram, 32bit buckets */
125         VSD_DTYPE_DRHIST32,     /* discrete range histogram, 32bit buckets */
126         VSD_DTYPE_DVHIST32,     /* discrete value histogram, 32bit buckets */
127         VSD_DTYPE_CRHIST64,     /* continuous range histogram, 64bit buckets */
128         VSD_DTYPE_DRHIST64,     /* discrete range histogram, 64bit buckets */
129         VSD_DTYPE_DVHIST64,     /* discrete value histogram, 64bit buckets */
130         VSD_DTYPE_TDGSTCLUST32, /* clustering variant t-digest, 32bit buckets */
131         VSD_DTYPE_TDGSTCLUST64, /* clustering variant t-digest, 64bit buckets */
132         VSD_NUM_DTYPES          /* +1 to highest numbered data type. */
133 };
134
135 struct voistatdata_int32 {
136         union {
137                 int32_t         s32;
138                 uint32_t        u32;
139         };
140 };
141
142 struct voistatdata_int64 {
143         union {
144                 int64_t         s64;
145                 uint64_t        u64;
146                 //counter_u64_t u64pcpu;
147         };
148 };
149
150 struct voistatdata_intlong {
151         union {
152                 long            slong;
153                 unsigned long   ulong;
154         };
155 };
156
157 struct voistatdata_q32 {
158         union {
159                 s32q_t          sq32;
160                 u32q_t          uq32;
161         };
162 };
163
164 struct voistatdata_q64 {
165         union {
166                 s64q_t          sq64;
167                 u64q_t          uq64;
168         };
169 };
170
171 struct voistatdata_numeric {
172         union {
173                 struct {
174 #if BYTE_ORDER == BIG_ENDIAN
175                         uint32_t                pad;
176 #endif
177                         union {
178                                 int32_t         s32;
179                                 uint32_t        u32;
180                         };
181 #if BYTE_ORDER == LITTLE_ENDIAN
182                         uint32_t                pad;
183 #endif
184                 } int32;
185
186                 struct {
187 #if BYTE_ORDER == BIG_ENDIAN
188                         uint32_t                pad;
189 #endif
190                         union {
191                                 s32q_t          sq32;
192                                 u32q_t          uq32;
193                         };
194 #if BYTE_ORDER == LITTLE_ENDIAN
195                         uint32_t                pad;
196 #endif
197                 } q32;
198
199                 struct {
200 #if BYTE_ORDER == BIG_ENDIAN && LONG_BIT == 32
201                         uint32_t                pad;
202 #endif
203                         union {
204                                 long            slong;
205                                 unsigned long   ulong;
206                         };
207 #if BYTE_ORDER == LITTLE_ENDIAN && LONG_BIT == 32
208                         uint32_t                pad;
209 #endif
210                 } intlong;
211
212                 struct voistatdata_int64        int64;
213                 struct voistatdata_q64          q64;
214         };
215 };
216
217 /* Continuous range histogram with 32bit buckets. */
218 struct voistatdata_crhist32 {
219         uint32_t        oob;
220         struct {
221                 struct voistatdata_numeric lb;
222                 uint32_t cnt;
223         } bkts[];
224 };
225
226 /* Continuous range histogram with 64bit buckets. */
227 struct voistatdata_crhist64 {
228         uint64_t        oob;
229         struct {
230                 struct voistatdata_numeric lb;
231                 uint64_t cnt;
232         } bkts[];
233 };
234
235 /* Discrete range histogram with 32bit buckets. */
236 struct voistatdata_drhist32 {
237         uint32_t        oob;
238         struct {
239                 struct voistatdata_numeric lb, ub;
240                 uint32_t cnt;
241         } bkts[];
242 };
243
244 /* Discrete range histogram with 64bit buckets. */
245 struct voistatdata_drhist64 {
246         uint64_t        oob;
247         struct {
248                 struct voistatdata_numeric lb, ub;
249                 uint64_t cnt;
250         } bkts[];
251 };
252
253 /* Discrete value histogram with 32bit buckets. */
254 struct voistatdata_dvhist32 {
255         uint32_t        oob;
256         struct {
257                 struct voistatdata_numeric val;
258                 uint32_t cnt;
259         } bkts[];
260 };
261
262 /* Discrete value histogram with 64bit buckets. */
263 struct voistatdata_dvhist64 {
264         uint64_t        oob;
265         struct {
266                 struct voistatdata_numeric val;
267                 uint64_t cnt;
268         } bkts[];
269 };
270
271 struct voistatdata_hist {
272         union {
273                 struct voistatdata_crhist32     crhist32;
274                 struct voistatdata_crhist64     crhist64;
275                 struct voistatdata_dvhist32     dvhist32;
276                 struct voistatdata_dvhist64     dvhist64;
277                 struct voistatdata_drhist32     drhist32;
278                 struct voistatdata_drhist64     drhist64;
279         };
280 };
281
282 struct voistatdata_tdgstctd32 {
283         ARB16_ENTRY()   ctdlnk;
284 #ifdef DIAGNOSTIC
285         RB_ENTRY(voistatdata_tdgstctd32) rblnk;
286 #endif
287         s32q_t          mu;
288         int32_t         cnt;
289 };
290
291 struct voistatdata_tdgstctd64 {
292         ARB16_ENTRY()   ctdlnk;
293 #ifdef DIAGNOSTIC
294         RB_ENTRY(voistatdata_tdgstctd64) rblnk;
295 #endif
296         s64q_t          mu;
297         int64_t         cnt;
298 };
299
300 struct voistatdata_tdgstctd {
301         union {
302                 struct voistatdata_tdgstctd32   tdgstctd32;
303                 struct voistatdata_tdgstctd64   tdgstctd64;
304         };
305 };
306
307 /* Clustering variant, fixed-point t-digest with 32bit mu/counts. */
308 struct voistatdata_tdgstclust32 {
309         uint32_t        smplcnt;        /* Count of samples. */
310         uint32_t        compcnt;        /* Count of digest compressions. */
311 #ifdef DIAGNOSTIC
312         RB_HEAD(rbctdth32, voistatdata_tdgstctd32) rbctdtree;
313 #endif
314         /* Array-based red-black tree of centroids. */
315         ARB16_HEAD(ctdth32, voistatdata_tdgstctd32) ctdtree;
316 };
317
318 /* Clustering variant, fixed-point t-digest with 64bit mu/counts. */
319 struct voistatdata_tdgstclust64 {
320         uint64_t        smplcnt;        /* Count of samples. */
321         uint32_t        compcnt;        /* Count of digest compressions. */
322 #ifdef DIAGNOSTIC
323         RB_HEAD(rbctdth64, voistatdata_tdgstctd64) rbctdtree;
324 #endif
325         /* Array-based red-black tree of centroids. */
326         ARB16_HEAD(ctdth64, voistatdata_tdgstctd64) ctdtree;
327 };
328
329 struct voistatdata_tdgst {
330         union {
331                 struct voistatdata_tdgstclust32 tdgstclust32;
332                 struct voistatdata_tdgstclust64 tdgstclust64;
333         };
334 };
335
336 struct voistatdata {
337         union {
338                 struct voistatdata_int32        int32;
339                 struct voistatdata_int64        int64;
340                 struct voistatdata_intlong      intlong;
341                 struct voistatdata_q32          q32;
342                 struct voistatdata_q64          q64;
343                 struct voistatdata_crhist32     crhist32;
344                 struct voistatdata_crhist64     crhist64;
345                 struct voistatdata_dvhist32     dvhist32;
346                 struct voistatdata_dvhist64     dvhist64;
347                 struct voistatdata_drhist32     drhist32;
348                 struct voistatdata_drhist64     drhist64;
349                 struct voistatdata_tdgstclust32 tdgstclust32;
350                 struct voistatdata_tdgstclust64 tdgstclust64;
351         };
352 };
353
354 #define VSD_HIST_LBOUND_INF 0x01
355 #define VSD_HIST_UBOUND_INF 0x02
356 struct vss_hist_hlpr_info {
357         enum hist_bkt_alloc {
358                 BKT_LIN,        /* Linear steps. */
359                 BKT_EXP,        /* Exponential steps. */
360                 BKT_LINEXP,     /* Exponential steps, linear sub-steps. */
361                 BKT_USR         /* User specified buckets. */
362         }                               scheme;
363         enum vsd_dtype                  voi_dtype;
364         enum vsd_dtype                  hist_dtype;
365         uint32_t                        flags;
366         struct voistatdata_numeric      lb;
367         struct voistatdata_numeric      ub;
368         union {
369                 struct {
370                         const uint64_t  stepinc;
371                 } lin;
372                 struct {
373                         const uint64_t  stepbase;
374                         const uint64_t  stepexp;
375                 } exp;
376                 struct {
377                         const uint64_t  stepbase;
378                         const uint64_t  linstepdiv;
379                 } linexp;
380                 struct {
381                         const uint16_t nbkts;
382                         const struct {
383                                 struct voistatdata_numeric lb, ub;
384                         } *bkts;
385                 } usr;
386         };
387 };
388
389 struct vss_tdgst_hlpr_info {
390         enum vsd_dtype          voi_dtype;
391         enum vsd_dtype          tdgst_dtype;
392         uint32_t                nctds;
393         uint32_t                prec;
394 } __aligned(sizeof(void *));
395
396 struct vss_numeric_hlpr_info {
397         uint32_t                prec;
398 };
399
400 struct vss_hlpr_info {
401         union {
402                 struct vss_tdgst_hlpr_info      tdgst;
403                 struct vss_hist_hlpr_info       hist;
404                 struct vss_numeric_hlpr_info    numeric;
405         };
406 };
407
408 struct voistatspec;
409 typedef int (*vss_hlpr_fn)(enum vsd_dtype, struct voistatspec *,
410     struct vss_hlpr_info *);
411
412 struct voistatspec {
413         vss_hlpr_fn             hlpr;           /* iv helper function. */
414         struct vss_hlpr_info    *hlprinfo;      /* Helper function context. */
415         struct voistatdata      *iv;            /* Initialisation value. */
416         size_t                  vsdsz;          /* Size of iv. */
417         uint32_t                flags;          /* Stat flags. */
418         enum vsd_dtype          vs_dtype : 8;   /* Stat's dtype. */
419         enum voi_stype          stype : 8;      /* Stat type. */
420 };
421
422 extern const char *vs_stype2name[VS_NUM_STYPES];
423 extern const char *vs_stype2desc[VS_NUM_STYPES];
424 extern const char *vsd_dtype2name[VSD_NUM_DTYPES];
425 extern const size_t vsd_dtype2size[VSD_NUM_DTYPES];
426 #define LIM_MIN 0
427 #define LIM_MAX 1
428 extern const struct voistatdata_numeric numeric_limits[2][VSD_DTYPE_Q_U64 + 1];
429
430 #define TYPEOF_MEMBER(type, member) __typeof(((type *)0)->member)
431 #define TYPEOF_MEMBER_PTR(type, member) __typeof(*(((type *)0)->member))
432 #define SIZEOF_MEMBER(type, member) sizeof(TYPEOF_MEMBER(type, member))
433
434 /* Cast a pointer to a voistatdata struct of requested type. */
435 #define _VSD(cnst, type, ptr) ((cnst struct voistatdata_##type *)(ptr))
436 #define VSD(type, ptr) _VSD(, type, ptr)
437 #define CONSTVSD(type, ptr) _VSD(const, type, ptr)
438
439 #define NVSS(vss_slots) (sizeof((vss_slots)) / sizeof(struct voistatspec))
440 #define STATS_VSS(st, vsf, dt, hlp, hlpi) \
441 ((struct voistatspec){ \
442         .stype = (st), \
443         .flags = (vsf), \
444         .vs_dtype = (dt), \
445         .hlpr = (hlp), \
446         .hlprinfo = (hlpi), \
447 })
448
449 #define STATS_VSS_SUM() STATS_VSS(VS_STYPE_SUM, 0, 0, \
450     (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
451
452 #define STATS_VSS_MAX() STATS_VSS(VS_STYPE_MAX, 0, 0, \
453     (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
454
455 #define STATS_VSS_MIN() STATS_VSS(VS_STYPE_MIN, 0, 0, \
456     (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
457
458 #define STATS_VSS_HIST(htype, hist_hlpr_info) STATS_VSS(VS_STYPE_HIST, 0, \
459     htype, (vss_hlpr_fn)&stats_vss_hist_hlpr, \
460     (struct vss_hlpr_info *)(hist_hlpr_info))
461
462 #define STATS_VSS_TDIGEST(tdtype, tdgst_hlpr_info) STATS_VSS(VS_STYPE_TDGST, \
463     0, tdtype, (vss_hlpr_fn)&stats_vss_tdgst_hlpr, \
464     (struct vss_hlpr_info *)(tdgst_hlpr_info))
465
466 #define TDGST_NCTRS2VSDSZ(tdtype, nctds) (sizeof(struct voistatdata_##tdtype) + \
467     ((nctds) * sizeof(TYPEOF_MEMBER_PTR(struct voistatdata_##tdtype, \
468     ctdtree.arb_nodes))))
469
470 #define TDGST_HLPR_INFO(dt, nc, nf) \
471 (&(struct vss_tdgst_hlpr_info){ \
472     .tdgst_dtype = (dt), \
473     .nctds = (nc), \
474     .prec = (nf) \
475 })
476
477 #define STATS_VSS_TDGSTCLUST32(nctds, prec) \
478     STATS_VSS_TDIGEST(VSD_DTYPE_TDGSTCLUST32, \
479     TDGST_HLPR_INFO(VSD_DTYPE_TDGSTCLUST32, nctds, prec))
480
481 #define STATS_VSS_TDGSTCLUST64(nctds, prec) \
482     STATS_VSS_TDIGEST(VSD_DTYPE_TDGSTCLUST64, \
483     TDGST_HLPR_INFO(VSD_DTYPE_TDGSTCLUST64, nctds, prec))
484
485 #define HIST_VSDSZ2NBKTS(htype, dsz) \
486     ((dsz - sizeof(struct voistatdata_##htype)) / \
487     sizeof(TYPEOF_MEMBER(struct voistatdata_##htype, bkts[0])))
488
489 #define HIST_NBKTS2VSDSZ(htype, nbkts) (sizeof(struct voistatdata_##htype) + \
490     ((nbkts) * sizeof(TYPEOF_MEMBER_PTR(struct voistatdata_##htype, bkts))))
491
492 #define HIST_HLPR_INFO_LIN_FIELDS(si) .lin.stepinc = (si)
493
494 #define HIST_HLPR_INFO_EXP_FIELDS(sb, se) \
495     .exp.stepbase = (sb), .exp.stepexp = (se)
496
497 #define HIST_HLPR_INFO_LINEXP_FIELDS(nss, sb) \
498     .linexp.linstepdiv = (nss), .linexp.stepbase = (sb)
499
500 #define HIST_HLPR_INFO_USR_FIELDS(bbs) \
501     .usr.bkts = (TYPEOF_MEMBER(struct vss_hist_hlpr_info, usr.bkts))(bbs), \
502     .usr.nbkts = (sizeof(bbs) / sizeof(struct voistatdata_numeric[2]))
503
504 #define HIST_HLPR_INFO(dt, sch, f, lbd, ubd, bkthlpr_fields) \
505 (&(struct vss_hist_hlpr_info){ \
506     .scheme = (sch), \
507     .hist_dtype = (dt), \
508     .flags = (f), \
509     .lb = stats_ctor_vsd_numeric(lbd), \
510     .ub = stats_ctor_vsd_numeric(ubd), \
511     bkthlpr_fields \
512 })
513
514 #define STATS_VSS_CRHIST32_LIN(lb, ub, stepinc, vsdflags) \
515     STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
516     BKT_LIN, vsdflags, lb, ub, HIST_HLPR_INFO_LIN_FIELDS(stepinc)))
517 #define STATS_VSS_CRHIST64_LIN(lb, ub, stepinc, vsdflags) \
518     STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
519     BKT_LIN, vsdflags, lb, ub, HIST_HLPR_INFO_LIN_FIELDS(stepinc)))
520
521 #define STATS_VSS_CRHIST32_EXP(lb, ub, stepbase, stepexp, vsdflags) \
522     STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
523     BKT_EXP, vsdflags, lb, ub, HIST_HLPR_INFO_EXP_FIELDS(stepbase, stepexp)))
524 #define STATS_VSS_CRHIST64_EXP(lb, ub, stepbase, stepexp, vsdflags) \
525     STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
526     BKT_EXP, vsdflags, lb, ub, HIST_HLPR_INFO_EXP_FIELDS(stepbase, stepexp)))
527
528 #define STATS_VSS_CRHIST32_LINEXP(lb, ub, nlinsteps, stepbase, vsdflags) \
529     STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
530     BKT_LINEXP, vsdflags, lb, ub, HIST_HLPR_INFO_LINEXP_FIELDS(nlinsteps, \
531     stepbase)))
532 #define STATS_VSS_CRHIST64_LINEXP(lb, ub, nlinsteps, stepbase, vsdflags) \
533     STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
534     BKT_LINEXP, vsdflags, lb, ub, HIST_HLPR_INFO_LINEXP_FIELDS(nlinsteps, \
535     stepbase)))
536
537 #define STATS_VSS_CRHIST32_USR(bkts, vsdflags) \
538     STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
539     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
540 #define STATS_VSS_CRHIST64_USR(bkts, vsdflags) \
541     STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
542     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
543
544 #define STATS_VSS_DRHIST32_USR(bkts, vsdflags) \
545     STATS_VSS_HIST(VSD_DTYPE_DRHIST32, HIST_HLPR_INFO(VSD_DTYPE_DRHIST32, \
546     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
547 #define STATS_VSS_DRHIST64_USR(bkts, vsdflags) \
548     STATS_VSS_HIST(VSD_DTYPE_DRHIST64, HIST_HLPR_INFO(VSD_DTYPE_DRHIST64, \
549     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
550
551 #define STATS_VSS_DVHIST32_USR(vals, vsdflags) \
552     STATS_VSS_HIST(VSD_DTYPE_DVHIST32, HIST_HLPR_INFO(VSD_DTYPE_DVHIST32, \
553     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(vals)))
554 #define STATS_VSS_DVHIST64_USR(vals, vsdflags) \
555     STATS_VSS_HIST(VSD_DTYPE_DVHIST64, HIST_HLPR_INFO(VSD_DTYPE_DVHIST64, \
556     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(vals)))
557
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_ */