]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/sys/stats.h
Update to Zstandard 1.4.5
[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 #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_ */