xref: /freebsd/sys/sys/stats.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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 #define	DRBKT(lb, ub) { stats_ctor_vsd_numeric(lb), stats_ctor_vsd_numeric(ub) }
561 #define	DVBKT(val) DRBKT(val, val)
562 #define	CRBKT(lb) DRBKT(lb, lb)
563 #define	HBKTS(...) ((struct voistatdata_numeric [][2]){__VA_ARGS__})
564 
565 #define	VSD_HIST_FIELD(hist, cnst, hist_dtype, op, field) \
566     (VSD_DTYPE_CRHIST32 == (hist_dtype) ? \
567     op(_VSD(cnst, crhist32, hist)->field) : \
568     (VSD_DTYPE_DRHIST32 == (hist_dtype) ? \
569     op(_VSD(cnst, drhist32, hist)->field) : \
570     (VSD_DTYPE_DVHIST32 == (hist_dtype) ? \
571     op(_VSD(cnst, dvhist32, hist)->field) : \
572     (VSD_DTYPE_CRHIST64 == (hist_dtype) ? \
573     op(_VSD(cnst, crhist64, hist)->field) : \
574     (VSD_DTYPE_DRHIST64 == (hist_dtype) ? \
575     op(_VSD(cnst, drhist64, hist)->field) : \
576     (op(_VSD(cnst, dvhist64, hist)->field)))))))
577 #define	VSD_HIST_FIELDVAL(hist, hist_dtype, field) \
578     VSD_HIST_FIELD(hist, , hist_dtype, ,field)
579 #define	VSD_CONSTHIST_FIELDVAL(hist, hist_dtype, field) \
580     VSD_HIST_FIELD(hist, const, hist_dtype, ,field)
581 #define	VSD_HIST_FIELDPTR(hist, hist_dtype, field) \
582     VSD_HIST_FIELD(hist, , hist_dtype, (void *)&,field)
583 #define	VSD_CONSTHIST_FIELDPTR(hist, hist_dtype, field) \
584     VSD_HIST_FIELD(hist, const, hist_dtype, (void *)&,field)
585 
586 #define	VSD_CRHIST_FIELD(hist, cnst, hist_dtype, op, field) \
587     (VSD_DTYPE_CRHIST32 == (hist_dtype) ? \
588     op(_VSD(cnst, crhist32, hist)->field) : \
589     op(_VSD(cnst, crhist64, hist)->field))
590 #define	VSD_CRHIST_FIELDVAL(hist, hist_dtype, field) \
591     VSD_CRHIST_FIELD(hist, , hist_dtype, , field)
592 #define	VSD_CONSTCRHIST_FIELDVAL(hist, hist_dtype, field) \
593     VSD_CRHIST_FIELD(hist, const, hist_dtype, , field)
594 #define	VSD_CRHIST_FIELDPTR(hist, hist_dtype, field) \
595     VSD_CRHIST_FIELD(hist, , hist_dtype, &, field)
596 #define	VSD_CONSTCRHIST_FIELDPTR(hist, hist_dtype, field) \
597     VSD_CRHIST_FIELD(hist, const, hist_dtype, &, field)
598 
599 #define	VSD_DRHIST_FIELD(hist, cnst, hist_dtype, op, field) \
600     (VSD_DTYPE_DRHIST32 == (hist_dtype) ? \
601     op(_VSD(cnst, drhist32, hist)->field) : \
602     op(_VSD(cnst, drhist64, hist)->field))
603 #define	VSD_DRHIST_FIELDVAL(hist, hist_dtype, field) \
604     VSD_DRHIST_FIELD(hist, , hist_dtype, , field)
605 #define	VSD_CONSTDRHIST_FIELDVAL(hist, hist_dtype, field) \
606     VSD_DRHIST_FIELD(hist, const, hist_dtype, , field)
607 #define	VSD_DRHIST_FIELDPTR(hist, hist_dtype, field) \
608     VSD_DRHIST_FIELD(hist, , hist_dtype, &, field)
609 #define	VSD_CONSTDRHIST_FIELDPTR(hist, hist_dtype, field) \
610     VSD_DRHIST_FIELD(hist, const, hist_dtype, &, field)
611 
612 #define	VSD_DVHIST_FIELD(hist, cnst, hist_dtype, op, field) \
613     (VSD_DTYPE_DVHIST32 == (hist_dtype) ? \
614     op(_VSD(cnst, dvhist32, hist)->field) : \
615     op(_VSD(cnst, dvhist64, hist)->field))
616 #define	VSD_DVHIST_FIELDVAL(hist, hist_dtype, field) \
617     VSD_DVHIST_FIELD(hist, , hist_dtype, , field)
618 #define	VSD_CONSTDVHIST_FIELDVAL(hist, hist_dtype, field) \
619     VSD_DVHIST_FIELD(hist, const, hist_dtype, , field)
620 #define	VSD_DVHIST_FIELDPTR(hist, hist_dtype, field) \
621     VSD_DVHIST_FIELD(hist, , hist_dtype, &, field)
622 #define	VSD_CONSTDVHIST_FIELDPTR(hist, hist_dtype, field) \
623     VSD_DVHIST_FIELD(hist, const, hist_dtype, &, field)
624 
625 #define	STATS_ABI_V1	1
626 struct statsblobv1;
627 
628 enum sb_endianness {
629 	SB_UE = 0,	/* Unknown endian. */
630 	SB_LE,		/* Little endian. */
631 	SB_BE		/* Big endian. */
632 };
633 
634 struct statsblob {
635 	uint8_t		abi;
636 	uint8_t		endian;
637 	uint16_t	flags;
638 	uint16_t	maxsz;
639 	uint16_t	cursz;
640 	uint8_t		opaque[];
641 } __aligned(sizeof(void *));
642 
643 struct metablob {
644 	char		*tplname;
645 	uint32_t	tplhash;
646 	struct voi_meta {
647 		char *name;
648 		char *desc;
649 	}		*voi_meta;
650 };
651 
652 struct statsblob_tpl {
653 	struct metablob		*mb;	/* Template metadata */
654 	struct statsblob	*sb;	/* Template schema */
655 };
656 
657 struct stats_tpl_sample_rate {
658 	/* XXXLAS: Storing slot_id assumes templates are never removed. */
659 	int32_t		tpl_slot_id;
660 	uint32_t	tpl_sample_pct;
661 };
662 
663 /* Template sample rates list management callback actions. */
664 enum stats_tpl_sr_cb_action {
665 	TPL_SR_UNLOCKED_GET,
666 	TPL_SR_RLOCKED_GET,
667 	TPL_SR_RUNLOCK,
668 	TPL_SR_PUT
669 };
670 
671 /*
672  * Callback function pointer passed as arg1 to stats_tpl_sample_rates(). ctx is
673  * a heap-allocated, zero-initialised blob of contextual memory valid during a
674  * single stats_tpl_sample_rates() call and sized per the value passed as arg2.
675  * Returns 0 on success, an errno on error.
676  * - When called with "action == TPL_SR_*_GET", return the subsystem's rates
677  *   list ptr and count, locked or unlocked as requested.
678  * - When called with "action == TPL_SR_RUNLOCK", unlock the subsystem's rates
679  *   list ptr and count. Pair with a prior "action == TPL_SR_RLOCKED_GET" call.
680  * - When called with "action == TPL_SR_PUT, update the subsystem's rates list
681  *   ptr and count to the sysctl processed values and return the inactive list
682  *   details in rates/nrates for garbage collection by stats_tpl_sample_rates().
683  */
684 typedef int (*stats_tpl_sr_cb_t)(enum stats_tpl_sr_cb_action action,
685     struct stats_tpl_sample_rate **rates, int *nrates, void *ctx);
686 
687 /* Flags related to iterating over a stats blob. */
688 #define	SB_IT_FIRST_CB		0x0001
689 #define	SB_IT_LAST_CB		0x0002
690 #define	SB_IT_FIRST_VOI		0x0004
691 #define	SB_IT_LAST_VOI		0x0008
692 #define	SB_IT_FIRST_VOISTAT	0x0010
693 #define	SB_IT_LAST_VOISTAT	0x0020
694 #define	SB_IT_NULLVOI		0x0040
695 #define	SB_IT_NULLVOISTAT	0x0080
696 
697 struct sb_visit {
698 	struct voistatdata	*vs_data;
699 	uint32_t		tplhash;
700 	uint32_t		flags;
701 	int16_t			voi_id;
702 	int16_t			vs_dsz;
703 	uint16_t		vs_errs;
704 	enum vsd_dtype		voi_dtype : 8;
705 	enum vsd_dtype		vs_dtype : 8;
706 	int8_t			vs_stype;
707 };
708 
709 /* Stats blob iterator callback called for each struct voi. */
710 typedef int (*stats_blob_visitcb_t)(struct sb_visit *sbv, void *usrctx);
711 
712 /* ABI specific functions. */
713 int stats_v1_tpl_alloc(const char *name, uint32_t flags);
714 int stats_v1_tpl_add_voistats(uint32_t tpl_id, int32_t voi_id,
715     const char *voi_name, enum vsd_dtype voi_dtype, uint32_t nvss,
716     struct voistatspec *vss, uint32_t flags);
717 int stats_v1_blob_init(struct statsblobv1 *sb, uint32_t tpl_id, uint32_t flags);
718 struct statsblobv1 * stats_v1_blob_alloc(uint32_t tpl_id, uint32_t flags);
719 int stats_v1_blob_clone(struct statsblobv1 **dst, size_t dstmaxsz,
720     struct statsblobv1 *src, uint32_t flags);
721 void stats_v1_blob_destroy(struct statsblobv1 *sb);
722 #define	SB_CLONE_RSTSRC		0x0001 /* Reset src blob if clone successful. */
723 #define	SB_CLONE_ALLOCDST	0x0002 /* Allocate src->cursz memory for dst. */
724 #define	SB_CLONE_USRDSTNOFAULT	0x0004 /* Clone to wired userspace dst. */
725 #define	SB_CLONE_USRDST		0x0008 /* Clone to unwired userspace dst. */
726 int stats_v1_blob_snapshot(struct statsblobv1 **dst, size_t dstmaxsz,
727     struct statsblobv1 *src, uint32_t flags);
728 #define	SB_TOSTR_OBJDUMP	0x00000001
729 #define	SB_TOSTR_META		0x00000002 /* Lookup metablob and render metadata */
730 int stats_v1_blob_tostr(struct statsblobv1 *sb, struct sbuf *buf,
731     enum sb_str_fmt fmt, uint32_t flags);
732 int stats_v1_blob_visit(struct statsblobv1 *sb, stats_blob_visitcb_t func,
733     void *usrctx);
734 /* VOI related function flags. */
735 #define	SB_VOI_RELUPDATE	0x00000001 /* voival is relative to previous value. */
736 int stats_v1_voi_update(struct statsblobv1 *sb, int32_t voi_id,
737     enum vsd_dtype voi_dtype, struct voistatdata *voival, uint32_t flags);
738 int stats_v1_voistat_fetch_dptr(struct statsblobv1 *sb, int32_t voi_id,
739     enum voi_stype stype, enum vsd_dtype *retdtype, struct voistatdata **retvsd,
740     size_t *retvsdsz);
741 
742 /* End ABI specific functions. */
743 
744 /* ABI agnostic functions. */
745 int stats_vss_hlpr_init(enum vsd_dtype voi_dtype, uint32_t nvss,
746     struct voistatspec *vss);
747 void stats_vss_hlpr_cleanup(uint32_t nvss, struct voistatspec *vss);
748 int stats_vss_hist_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
749     struct vss_hist_hlpr_info *info);
750 int stats_vss_numeric_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
751     struct vss_numeric_hlpr_info *info);
752 int stats_vss_tdgst_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
753     struct vss_tdgst_hlpr_info *info);
754 int stats_tpl_fetch(int tpl_id, struct statsblob_tpl **tpl);
755 int stats_tpl_fetch_allocid(const char *name, uint32_t hash);
756 int stats_tpl_id2name(uint32_t tpl_id, char *buf, size_t len);
757 int stats_tpl_sample_rates(struct sysctl_oid *oidp, void *arg1, intmax_t arg2,
758     struct sysctl_req *req);
759 int stats_tpl_sample_rollthedice(struct stats_tpl_sample_rate *rates,
760     int nrates, void *seed_bytes, size_t seed_len);
761 int stats_voistatdata_tostr(const struct voistatdata *vsd,
762     enum vsd_dtype voi_dtype, enum vsd_dtype vsd_dtype, size_t vsd_sz,
763     enum sb_str_fmt fmt, struct sbuf *buf, int objdump);
764 
765 static inline struct voistatdata_numeric
766 stats_ctor_vsd_numeric(uint64_t val)
767 {
768 	struct voistatdata_numeric tmp;
769 
770 	tmp.int64.u64 = val;
771 
772 	return (tmp);
773 }
774 
775 static inline int
776 stats_tpl_alloc(const char *name, uint32_t flags)
777 {
778 
779 	return (stats_v1_tpl_alloc(name, flags));
780 }
781 
782 static inline int
783 stats_tpl_add_voistats(uint32_t tpl_id, int32_t voi_id, const char *voi_name,
784     enum vsd_dtype voi_dtype, uint32_t nvss, struct voistatspec *vss,
785     uint32_t flags)
786 {
787 	int ret;
788 
789 	if ((ret = stats_vss_hlpr_init(voi_dtype, nvss, vss)) == 0) {
790 		ret = stats_v1_tpl_add_voistats(tpl_id, voi_id, voi_name,
791 		    voi_dtype, nvss, vss, flags);
792 	}
793 	stats_vss_hlpr_cleanup(nvss, vss);
794 
795 	return (ret);
796 }
797 
798 static inline int
799 stats_blob_init(struct statsblob *sb, uint32_t tpl_id, uint32_t flags)
800 {
801 
802 	return (stats_v1_blob_init((struct statsblobv1 *)sb, tpl_id, flags));
803 }
804 
805 static inline struct statsblob *
806 stats_blob_alloc(uint32_t tpl_id, uint32_t flags)
807 {
808 
809 	return ((struct statsblob *)stats_v1_blob_alloc(tpl_id, flags));
810 }
811 
812 static inline int
813 stats_blob_clone(struct statsblob **dst, size_t dstmaxsz, struct statsblob *src,
814     uint32_t flags)
815 {
816 
817 	return (stats_v1_blob_clone((struct statsblobv1 **)dst, dstmaxsz,
818 	    (struct statsblobv1 *)src, flags));
819 }
820 
821 static inline void
822 stats_blob_destroy(struct statsblob *sb)
823 {
824 
825 	stats_v1_blob_destroy((struct statsblobv1 *)sb);
826 }
827 
828 static inline int
829 stats_blob_visit(struct statsblob *sb, stats_blob_visitcb_t func, void *usrctx)
830 {
831 
832 	return (stats_v1_blob_visit((struct statsblobv1 *)sb, func, usrctx));
833 }
834 
835 static inline int
836 stats_blob_tostr(struct statsblob *sb, struct sbuf *buf,
837     enum sb_str_fmt fmt, uint32_t flags)
838 {
839 
840 	return (stats_v1_blob_tostr((struct statsblobv1 *)sb, buf, fmt, flags));
841 }
842 
843 static inline int
844 stats_voistat_fetch_dptr(struct statsblob *sb, int32_t voi_id,
845     enum voi_stype stype, enum vsd_dtype *retdtype, struct voistatdata **retvsd,
846     size_t *retvsdsz)
847 {
848 
849 	return (stats_v1_voistat_fetch_dptr((struct statsblobv1 *)sb,
850 	    voi_id, stype, retdtype, retvsd, retvsdsz));
851 }
852 
853 static inline int
854 stats_voistat_fetch_s64(struct statsblob *sb, int32_t voi_id,
855     enum voi_stype stype, int64_t *ret)
856 {
857 	struct voistatdata *vsd;
858 	enum vsd_dtype vs_dtype;
859 	int error;
860 
861 	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
862 	    NULL)))
863 		return (error);
864 	else if (VSD_DTYPE_INT_S64 != vs_dtype)
865 		return (EFTYPE);
866 
867 	*ret = vsd->int64.s64;
868 	return (0);
869 }
870 
871 static inline int
872 stats_voistat_fetch_u64(struct statsblob *sb, int32_t voi_id,
873     enum voi_stype stype, uint64_t *ret)
874 {
875 	struct voistatdata *vsd;
876 	enum vsd_dtype vs_dtype;
877 	int error;
878 
879 	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
880 	    NULL)))
881 		return (error);
882 	else if (VSD_DTYPE_INT_U64 != vs_dtype)
883 		return (EFTYPE);
884 
885 	*ret = vsd->int64.u64;
886 	return (0);
887 }
888 
889 static inline int
890 stats_voistat_fetch_s32(struct statsblob *sb, int32_t voi_id,
891     enum voi_stype stype, int32_t *ret)
892 {
893 	struct voistatdata *vsd;
894 	enum vsd_dtype vs_dtype;
895 	int error;
896 
897 	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
898 	    NULL)))
899 		return (error);
900 	else if (VSD_DTYPE_INT_S32 != vs_dtype)
901 		return (EFTYPE);
902 
903 	*ret = vsd->int32.s32;
904 	return (0);
905 }
906 
907 static inline int
908 stats_voistat_fetch_u32(struct statsblob *sb, int32_t voi_id,
909     enum voi_stype stype, uint32_t *ret)
910 {
911 	struct voistatdata *vsd;
912 	enum vsd_dtype vs_dtype;
913 	int error;
914 
915 	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
916 	    NULL)))
917 		return (error);
918 	else if (VSD_DTYPE_INT_U32 != vs_dtype)
919 		return (EFTYPE);
920 
921 	*ret = vsd->int32.u32;
922 	return (0);
923 }
924 
925 static inline int
926 stats_voistat_fetch_slong(struct statsblob *sb, int32_t voi_id,
927     enum voi_stype stype, long *ret)
928 {
929 	struct voistatdata *vsd;
930 	enum vsd_dtype vs_dtype;
931 	int error;
932 
933 	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
934 	    NULL)))
935 		return (error);
936 	else if (VSD_DTYPE_INT_SLONG != vs_dtype)
937 		return (EFTYPE);
938 
939 	*ret = vsd->intlong.slong;
940 	return (0);
941 }
942 
943 static inline int
944 stats_voistat_fetch_ulong(struct statsblob *sb, int32_t voi_id,
945     enum voi_stype stype, unsigned long *ret)
946 {
947 	struct voistatdata *vsd;
948 	enum vsd_dtype vs_dtype;
949 	int error;
950 
951 	if ((error = stats_voistat_fetch_dptr(sb, voi_id, stype, &vs_dtype, &vsd,
952 	    NULL)))
953 		return (error);
954 	else if (VSD_DTYPE_INT_ULONG != vs_dtype)
955 		return (EFTYPE);
956 
957 	*ret = vsd->intlong.ulong;
958 	return (0);
959 }
960 
961 static inline int
962 stats_blob_snapshot(struct statsblob **dst, size_t dstmaxsz,
963     struct statsblob *src, uint32_t flags)
964 {
965 
966 	return (stats_v1_blob_snapshot((struct statsblobv1 **)dst, dstmaxsz,
967 	    (struct statsblobv1 *)src, flags));
968 }
969 
970 static inline int
971 stats_voi_update_abs_s32(struct statsblob *sb, int32_t voi_id, int32_t voival)
972 {
973 
974 	if (sb == NULL)
975 		return (0);
976 
977 	struct voistatdata tmp;
978 	tmp.int32.s32 = voival;
979 
980 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
981 	    VSD_DTYPE_INT_S32, &tmp, 0));
982 }
983 
984 static inline int
985 stats_voi_update_rel_s32(struct statsblob *sb, int32_t voi_id, int32_t voival)
986 {
987 
988 	if (sb == NULL)
989 		return (0);
990 
991 	struct voistatdata tmp;
992 	tmp.int32.s32 = voival;
993 
994 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
995 	    VSD_DTYPE_INT_S32, &tmp, SB_VOI_RELUPDATE));
996 }
997 
998 static inline int
999 stats_voi_update_abs_u32(struct statsblob *sb, int32_t voi_id, uint32_t voival)
1000 {
1001 
1002 	if (sb == NULL)
1003 		return (0);
1004 
1005 	struct voistatdata tmp;
1006 	tmp.int32.u32 = voival;
1007 
1008 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1009 	    VSD_DTYPE_INT_U32, &tmp, 0));
1010 }
1011 
1012 static inline int
1013 stats_voi_update_rel_u32(struct statsblob *sb, int32_t voi_id, uint32_t voival)
1014 {
1015 
1016 	if (sb == NULL)
1017 		return (0);
1018 
1019 	struct voistatdata tmp;
1020 	tmp.int32.u32 = voival;
1021 
1022 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1023 	    VSD_DTYPE_INT_U32, &tmp, SB_VOI_RELUPDATE));
1024 }
1025 
1026 static inline int
1027 stats_voi_update_abs_s64(struct statsblob *sb, int32_t voi_id, int64_t voival)
1028 {
1029 
1030 	if (sb == NULL)
1031 		return (0);
1032 
1033 	struct voistatdata tmp;
1034 	tmp.int64.s64 = voival;
1035 
1036 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1037 	    VSD_DTYPE_INT_S64, &tmp, 0));
1038 }
1039 
1040 static inline int
1041 stats_voi_update_rel_s64(struct statsblob *sb, int32_t voi_id, int64_t voival)
1042 {
1043 
1044 	if (sb == NULL)
1045 		return (0);
1046 
1047 	struct voistatdata tmp;
1048 	tmp.int64.s64 = voival;
1049 
1050 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1051 	    VSD_DTYPE_INT_S64, &tmp, SB_VOI_RELUPDATE));
1052 }
1053 
1054 static inline int
1055 stats_voi_update_abs_u64(struct statsblob *sb, int32_t voi_id, uint64_t voival)
1056 {
1057 
1058 	if (sb == NULL)
1059 		return (0);
1060 
1061 	struct voistatdata tmp;
1062 	tmp.int64.u64 = voival;
1063 
1064 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1065 	    VSD_DTYPE_INT_U64, &tmp, 0));
1066 }
1067 
1068 static inline int
1069 stats_voi_update_rel_u64(struct statsblob *sb, int32_t voi_id, uint64_t voival)
1070 {
1071 
1072 	if (sb == NULL)
1073 		return (0);
1074 
1075 	struct voistatdata tmp;
1076 	tmp.int64.u64 = voival;
1077 
1078 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1079 	    VSD_DTYPE_INT_U64, &tmp, SB_VOI_RELUPDATE));
1080 }
1081 
1082 static inline int
1083 stats_voi_update_abs_slong(struct statsblob *sb, int32_t voi_id, long voival)
1084 {
1085 
1086 	if (sb == NULL)
1087 		return (0);
1088 
1089 	struct voistatdata tmp;
1090 	tmp.intlong.slong = voival;
1091 
1092 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1093 	    VSD_DTYPE_INT_SLONG, &tmp, 0));
1094 }
1095 
1096 static inline int
1097 stats_voi_update_rel_slong(struct statsblob *sb, int32_t voi_id, long voival)
1098 {
1099 
1100 	if (sb == NULL)
1101 		return (0);
1102 
1103 	struct voistatdata tmp;
1104 	tmp.intlong.slong = voival;
1105 
1106 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1107 	    VSD_DTYPE_INT_SLONG, &tmp, SB_VOI_RELUPDATE));
1108 }
1109 
1110 static inline int
1111 stats_voi_update_abs_ulong(struct statsblob *sb, int32_t voi_id,
1112     unsigned long voival)
1113 {
1114 
1115 	if (sb == NULL)
1116 		return (0);
1117 
1118 	struct voistatdata tmp;
1119 	tmp.intlong.ulong = voival;
1120 
1121 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1122 	    VSD_DTYPE_INT_ULONG, &tmp, 0));
1123 }
1124 
1125 static inline int
1126 stats_voi_update_rel_ulong(struct statsblob *sb, int32_t voi_id,
1127     unsigned long voival)
1128 {
1129 
1130 	if (sb == NULL)
1131 		return (0);
1132 
1133 	struct voistatdata tmp;
1134 	tmp.intlong.ulong = voival;
1135 
1136 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1137 	    VSD_DTYPE_INT_ULONG, &tmp, SB_VOI_RELUPDATE));
1138 }
1139 
1140 static inline int
1141 stats_voi_update_abs_sq32(struct statsblob *sb, int32_t voi_id, s32q_t voival)
1142 {
1143 
1144 	if (sb == NULL)
1145 		return (0);
1146 
1147 	struct voistatdata tmp;
1148 	tmp.q32.sq32 = voival;
1149 
1150 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1151 	    VSD_DTYPE_Q_S32, &tmp, 0));
1152 }
1153 
1154 static inline int
1155 stats_voi_update_rel_sq32(struct statsblob *sb, int32_t voi_id, s32q_t voival)
1156 {
1157 
1158 	if (sb == NULL)
1159 		return (0);
1160 
1161 	struct voistatdata tmp;
1162 	tmp.q32.sq32 = voival;
1163 
1164 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1165 	    VSD_DTYPE_Q_S32, &tmp, SB_VOI_RELUPDATE));
1166 }
1167 
1168 static inline int
1169 stats_voi_update_abs_uq32(struct statsblob *sb, int32_t voi_id, u32q_t voival)
1170 {
1171 
1172 	if (sb == NULL)
1173 		return (0);
1174 
1175 	struct voistatdata tmp;
1176 	tmp.q32.uq32 = voival;
1177 
1178 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1179 	    VSD_DTYPE_Q_U32, &tmp, 0));
1180 }
1181 
1182 static inline int
1183 stats_voi_update_rel_uq32(struct statsblob *sb, int32_t voi_id, u32q_t voival)
1184 {
1185 
1186 	if (sb == NULL)
1187 		return (0);
1188 
1189 	struct voistatdata tmp;
1190 	tmp.q32.uq32 = voival;
1191 
1192 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1193 	    VSD_DTYPE_Q_U32, &tmp, SB_VOI_RELUPDATE));
1194 }
1195 
1196 static inline int
1197 stats_voi_update_abs_sq64(struct statsblob *sb, int32_t voi_id, s64q_t voival)
1198 {
1199 
1200 	if (sb == NULL)
1201 		return (0);
1202 
1203 	struct voistatdata tmp;
1204 	tmp.q64.sq64 = voival;
1205 
1206 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1207 	    VSD_DTYPE_Q_S64, &tmp, 0));
1208 }
1209 
1210 static inline int
1211 stats_voi_update_rel_sq64(struct statsblob *sb, int32_t voi_id, s64q_t voival)
1212 {
1213 
1214 	if (sb == NULL)
1215 		return (0);
1216 
1217 	struct voistatdata tmp;
1218 	tmp.q64.sq64 = voival;
1219 
1220 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1221 	    VSD_DTYPE_Q_S64, &tmp, SB_VOI_RELUPDATE));
1222 }
1223 
1224 static inline int
1225 stats_voi_update_abs_uq64(struct statsblob *sb, int32_t voi_id, u64q_t voival)
1226 {
1227 
1228 	if (sb == NULL)
1229 		return (0);
1230 
1231 	struct voistatdata tmp;
1232 	tmp.q64.uq64 = voival;
1233 
1234 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1235 	    VSD_DTYPE_Q_U64, &tmp, 0));
1236 }
1237 
1238 static inline int
1239 stats_voi_update_rel_uq64(struct statsblob *sb, int32_t voi_id, u64q_t voival)
1240 {
1241 
1242 	if (sb == NULL)
1243 		return (0);
1244 
1245 	struct voistatdata tmp;
1246 	tmp.q64.uq64 = voival;
1247 
1248 	return (stats_v1_voi_update((struct statsblobv1 *)sb, voi_id,
1249 	    VSD_DTYPE_Q_U64, &tmp, SB_VOI_RELUPDATE));
1250 }
1251 
1252 /* End ABI agnostic functions. */
1253 
1254 #endif /* _SYS_STATS_H_ */
1255