xref: /freebsd/sys/sys/stats.h (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1 /*-
2  * Copyright (c) 2014-2018 Netflix, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * A kernel and user space statistics gathering API + infrastructure.
29  *
30  * Author: Lawrence Stewart <lstewart@netflix.com>
31  *
32  * Things to ponder:
33  *   - Register callbacks for events e.g. counter stat passing a threshold
34  *
35  *   - How could this become SIFTRv2? Perhaps publishing records to a ring
36  *     mapped between userspace and kernel?
37  *
38  *   - Potential stat types:
39  *       RATE: events per unit time
40  *       TIMESERIES: timestamped records. Stored in voistate?
41  *       EWMA: Exponential weighted moving average.
42  *
43  *   - How should second order stats work e.g. stat "A" depends on "B"
44  *
45  *   - How do variable time windows work e.g. give me per-RTT stats
46  *
47  *   - Should the API always require the caller to manage locking? Or should the
48  *     API provide optional functionality to lock a blob during operations.
49  *
50  *   - Should we continue to store unpacked naturally aligned structs in the
51  *     blob or move to packed structs? Relates to inter-host
52  *     serialisation/endian issues.
53  */
54 
55 #ifndef _SYS_STATS_H_
56 #define _SYS_STATS_H_
57 
58 #include <sys/limits.h>
59 #ifdef DIAGNOSTIC
60 #include <sys/tree.h>
61 #endif
62 
63 #ifndef _KERNEL
64 /*
65  * XXXLAS: Hacks to enable sharing template creation code between kernel and
66  * userland e.g. tcp_stats.c
67  */
68 #define	VNET(n) n
69 #define	VNET_DEFINE(t, n) static t n __unused
70 #endif /* ! _KERNEL */
71 
72 #define	TPL_MAX_NAME_LEN 64
73 
74 /*
75  * The longest template string spec format i.e. the normative spec format, is:
76  *
77  *     "<tplname>":<tplhash>
78  *
79  * Therefore, the max string length of a template string spec is:
80  *
81  * - TPL_MAX_NAME_LEN
82  * - 2 chars for ""
83  * - 1 char for : separating name and hash
84  * - 10 chars for 32bit hash
85  */
86 #define	STATS_TPL_MAX_STR_SPEC_LEN (TPL_MAX_NAME_LEN + 13)
87 
88 struct sbuf;
89 struct sysctl_oid;
90 struct sysctl_req;
91 
92 enum sb_str_fmt {
93 	SB_STRFMT_FREEFORM = 0,
94 	SB_STRFMT_JSON,
95 	SB_STRFMT_NUM_FMTS	/* +1 to highest numbered format type. */
96 };
97 
98 /* VOI stat types. */
99 enum voi_stype {
100 	VS_STYPE_VOISTATE = 0,	/* Reserved for internal API use. */
101 	VS_STYPE_SUM,
102 	VS_STYPE_MAX,
103 	VS_STYPE_MIN,
104 	VS_STYPE_HIST,
105 	VS_STYPE_TDGST,
106 	VS_NUM_STYPES		/* +1 to highest numbered stat type. */
107 };
108 
109 /*
110  * VOI stat data types used as storage for certain stat types and to marshall
111  * data through various API calls.
112  */
113 enum vsd_dtype {
114 	VSD_DTYPE_VOISTATE = 0,	/* Reserved for internal API use. */
115 	VSD_DTYPE_INT_S32,	/* int32_t */
116 	VSD_DTYPE_INT_U32,	/* uint32_t */
117 	VSD_DTYPE_INT_S64,	/* int64_t */
118 	VSD_DTYPE_INT_U64,	/* uint64_t */
119 	VSD_DTYPE_INT_SLONG,	/* long */
120 	VSD_DTYPE_INT_ULONG,	/* unsigned long */
121 	VSD_DTYPE_Q_S32,	/* s32q_t */
122 	VSD_DTYPE_Q_U32,	/* u32q_t */
123 	VSD_DTYPE_Q_S64,	/* s64q_t */
124 	VSD_DTYPE_Q_U64,	/* u64q_t */
125 	VSD_DTYPE_CRHIST32,	/* continuous range histogram, 32bit buckets */
126 	VSD_DTYPE_DRHIST32,	/* discrete range histogram, 32bit buckets */
127 	VSD_DTYPE_DVHIST32,	/* discrete value histogram, 32bit buckets */
128 	VSD_DTYPE_CRHIST64,	/* continuous range histogram, 64bit buckets */
129 	VSD_DTYPE_DRHIST64,	/* discrete range histogram, 64bit buckets */
130 	VSD_DTYPE_DVHIST64,	/* discrete value histogram, 64bit buckets */
131 	VSD_DTYPE_TDGSTCLUST32,	/* clustering variant t-digest, 32bit buckets */
132 	VSD_DTYPE_TDGSTCLUST64,	/* clustering variant t-digest, 64bit buckets */
133 	VSD_NUM_DTYPES		/* +1 to highest numbered data type. */
134 };
135 
136 struct voistatdata_int32 {
137 	union {
138 		int32_t		s32;
139 		uint32_t	u32;
140 	};
141 };
142 
143 struct voistatdata_int64 {
144 	union {
145 		int64_t		s64;
146 		uint64_t	u64;
147 		//counter_u64_t	u64pcpu;
148 	};
149 };
150 
151 struct voistatdata_intlong {
152 	union {
153 		long		slong;
154 		unsigned long	ulong;
155 	};
156 };
157 
158 struct voistatdata_q32 {
159 	union {
160 		s32q_t		sq32;
161 		u32q_t		uq32;
162 	};
163 };
164 
165 struct voistatdata_q64 {
166 	union {
167 		s64q_t		sq64;
168 		u64q_t		uq64;
169 	};
170 };
171 
172 struct voistatdata_numeric {
173 	union {
174 		struct {
175 #if BYTE_ORDER == BIG_ENDIAN
176 			uint32_t		pad;
177 #endif
178 			union {
179 				int32_t		s32;
180 				uint32_t	u32;
181 			};
182 #if BYTE_ORDER == LITTLE_ENDIAN
183 			uint32_t		pad;
184 #endif
185 		} int32;
186 
187 		struct {
188 #if BYTE_ORDER == BIG_ENDIAN
189 			uint32_t		pad;
190 #endif
191 			union {
192 				s32q_t		sq32;
193 				u32q_t		uq32;
194 			};
195 #if BYTE_ORDER == LITTLE_ENDIAN
196 			uint32_t		pad;
197 #endif
198 		} q32;
199 
200 		struct {
201 #if BYTE_ORDER == BIG_ENDIAN && LONG_BIT == 32
202 			uint32_t		pad;
203 #endif
204 			union {
205 				long		slong;
206 				unsigned long	ulong;
207 			};
208 #if BYTE_ORDER == LITTLE_ENDIAN && LONG_BIT == 32
209 			uint32_t		pad;
210 #endif
211 		} intlong;
212 
213 		struct voistatdata_int64	int64;
214 		struct voistatdata_q64		q64;
215 	};
216 };
217 
218 /* Continuous range histogram with 32bit buckets. */
219 struct voistatdata_crhist32 {
220 	uint32_t	oob;
221 	struct {
222 		struct voistatdata_numeric lb;
223 		uint32_t cnt;
224 	} bkts[];
225 };
226 
227 /* Continuous range histogram with 64bit buckets. */
228 struct voistatdata_crhist64 {
229 	uint64_t	oob;
230 	struct {
231 		struct voistatdata_numeric lb;
232 		uint64_t cnt;
233 	} bkts[];
234 };
235 
236 /* Discrete range histogram with 32bit buckets. */
237 struct voistatdata_drhist32 {
238 	uint32_t	oob;
239 	struct {
240 		struct voistatdata_numeric lb, ub;
241 		uint32_t cnt;
242 	} bkts[];
243 };
244 
245 /* Discrete range histogram with 64bit buckets. */
246 struct voistatdata_drhist64 {
247 	uint64_t	oob;
248 	struct {
249 		struct voistatdata_numeric lb, ub;
250 		uint64_t cnt;
251 	} bkts[];
252 };
253 
254 /* Discrete value histogram with 32bit buckets. */
255 struct voistatdata_dvhist32 {
256 	uint32_t	oob;
257 	struct {
258 		struct voistatdata_numeric val;
259 		uint32_t cnt;
260 	} bkts[];
261 };
262 
263 /* Discrete value histogram with 64bit buckets. */
264 struct voistatdata_dvhist64 {
265 	uint64_t	oob;
266 	struct {
267 		struct voistatdata_numeric val;
268 		uint64_t cnt;
269 	} bkts[];
270 };
271 
272 struct voistatdata_hist {
273 	union {
274 		struct voistatdata_crhist32	crhist32;
275 		struct voistatdata_crhist64	crhist64;
276 		struct voistatdata_dvhist32	dvhist32;
277 		struct voistatdata_dvhist64	dvhist64;
278 		struct voistatdata_drhist32	drhist32;
279 		struct voistatdata_drhist64	drhist64;
280 	};
281 };
282 
283 struct voistatdata_tdgstctd32 {
284 	ARB16_ENTRY()	ctdlnk;
285 #ifdef DIAGNOSTIC
286 	RB_ENTRY(voistatdata_tdgstctd32) rblnk;
287 #endif
288 	s32q_t		mu;
289 	int32_t		cnt;
290 };
291 
292 struct voistatdata_tdgstctd64 {
293 	ARB16_ENTRY()	ctdlnk;
294 #ifdef DIAGNOSTIC
295 	RB_ENTRY(voistatdata_tdgstctd64) rblnk;
296 #endif
297 	s64q_t		mu;
298 	int64_t		cnt;
299 };
300 
301 struct voistatdata_tdgstctd {
302 	union {
303 		struct voistatdata_tdgstctd32	tdgstctd32;
304 		struct voistatdata_tdgstctd64	tdgstctd64;
305 	};
306 };
307 
308 /* Clustering variant, fixed-point t-digest with 32bit mu/counts. */
309 struct voistatdata_tdgstclust32 {
310 	uint32_t	smplcnt;	/* Count of samples. */
311 	uint32_t	compcnt;	/* Count of digest compressions. */
312 #ifdef DIAGNOSTIC
313 	RB_HEAD(rbctdth32, voistatdata_tdgstctd32) rbctdtree;
314 #endif
315 	/* Array-based red-black tree of centroids. */
316 	ARB16_HEAD(ctdth32, voistatdata_tdgstctd32) ctdtree;
317 };
318 
319 /* Clustering variant, fixed-point t-digest with 64bit mu/counts. */
320 struct voistatdata_tdgstclust64 {
321 	uint64_t	smplcnt;	/* Count of samples. */
322 	uint32_t	compcnt;	/* Count of digest compressions. */
323 #ifdef DIAGNOSTIC
324 	RB_HEAD(rbctdth64, voistatdata_tdgstctd64) rbctdtree;
325 #endif
326 	/* Array-based red-black tree of centroids. */
327 	ARB16_HEAD(ctdth64, voistatdata_tdgstctd64) ctdtree;
328 };
329 
330 struct voistatdata_tdgst {
331 	union {
332 		struct voistatdata_tdgstclust32	tdgstclust32;
333 		struct voistatdata_tdgstclust64	tdgstclust64;
334 	};
335 };
336 
337 struct voistatdata {
338 	union {
339 		struct voistatdata_int32	int32;
340 		struct voistatdata_int64	int64;
341 		struct voistatdata_intlong	intlong;
342 		struct voistatdata_q32		q32;
343 		struct voistatdata_q64		q64;
344 		struct voistatdata_crhist32	crhist32;
345 		struct voistatdata_crhist64	crhist64;
346 		struct voistatdata_dvhist32	dvhist32;
347 		struct voistatdata_dvhist64	dvhist64;
348 		struct voistatdata_drhist32	drhist32;
349 		struct voistatdata_drhist64	drhist64;
350 		struct voistatdata_tdgstclust32	tdgstclust32;
351 		struct voistatdata_tdgstclust64	tdgstclust64;
352 	};
353 };
354 
355 #define	VSD_HIST_LBOUND_INF 0x01
356 #define	VSD_HIST_UBOUND_INF 0x02
357 struct vss_hist_hlpr_info {
358 	enum hist_bkt_alloc {
359 		BKT_LIN,	/* Linear steps. */
360 		BKT_EXP,	/* Exponential steps. */
361 		BKT_LINEXP,	/* Exponential steps, linear sub-steps. */
362 		BKT_USR		/* User specified buckets. */
363 	}				scheme;
364 	enum vsd_dtype			voi_dtype;
365 	enum vsd_dtype			hist_dtype;
366 	uint32_t			flags;
367 	struct voistatdata_numeric	lb;
368 	struct voistatdata_numeric	ub;
369 	union {
370 		struct {
371 			const uint64_t	stepinc;
372 		} lin;
373 		struct {
374 			const uint64_t	stepbase;
375 			const uint64_t	stepexp;
376 		} exp;
377 		struct {
378 			const uint64_t	stepbase;
379 			const uint64_t	linstepdiv;
380 		} linexp;
381 		struct {
382 			const uint16_t nbkts;
383 			const struct {
384 				struct voistatdata_numeric lb, ub;
385 			} *bkts;
386 		} usr;
387 	};
388 };
389 
390 struct vss_tdgst_hlpr_info {
391 	enum vsd_dtype		voi_dtype;
392 	enum vsd_dtype		tdgst_dtype;
393 	uint32_t		nctds;
394 	uint32_t		prec;
395 } __aligned(sizeof(void *));
396 
397 struct vss_numeric_hlpr_info {
398 	uint32_t		prec;
399 };
400 
401 struct vss_hlpr_info {
402 	union {
403 		struct vss_tdgst_hlpr_info	tdgst;
404 		struct vss_hist_hlpr_info	hist;
405 		struct vss_numeric_hlpr_info	numeric;
406 	};
407 };
408 
409 struct voistatspec;
410 typedef int (*vss_hlpr_fn)(enum vsd_dtype, struct voistatspec *,
411     struct vss_hlpr_info *);
412 
413 struct voistatspec {
414 	vss_hlpr_fn		hlpr;		/* iv helper function. */
415 	struct vss_hlpr_info	*hlprinfo;	/* Helper function context. */
416 	struct voistatdata	*iv;		/* Initialisation value. */
417 	size_t			vsdsz;		/* Size of iv. */
418 	uint32_t		flags;		/* Stat flags. */
419 	enum vsd_dtype		vs_dtype : 8;	/* Stat's dtype. */
420 	enum voi_stype		stype : 8;	/* Stat type. */
421 };
422 
423 extern const char *vs_stype2name[VS_NUM_STYPES];
424 extern const char *vs_stype2desc[VS_NUM_STYPES];
425 extern const char *vsd_dtype2name[VSD_NUM_DTYPES];
426 extern const size_t vsd_dtype2size[VSD_NUM_DTYPES];
427 #define	LIM_MIN 0
428 #define	LIM_MAX 1
429 extern const struct voistatdata_numeric numeric_limits[2][VSD_DTYPE_Q_U64 + 1];
430 
431 #define	TYPEOF_MEMBER(type, member) __typeof(((type *)0)->member)
432 #define	TYPEOF_MEMBER_PTR(type, member) __typeof(*(((type *)0)->member))
433 #define	SIZEOF_MEMBER(type, member) sizeof(TYPEOF_MEMBER(type, member))
434 
435 /* Cast a pointer to a voistatdata struct of requested type. */
436 #define	_VSD(cnst, type, ptr) ((cnst struct voistatdata_##type *)(ptr))
437 #define	VSD(type, ptr) _VSD(, type, ptr)
438 #define	CONSTVSD(type, ptr) _VSD(const, type, ptr)
439 
440 #define	NVSS(vss_slots) (sizeof((vss_slots)) / sizeof(struct voistatspec))
441 #define	STATS_VSS(st, vsf, dt, hlp, hlpi) \
442 ((struct voistatspec){ \
443 	.stype = (st), \
444 	.flags = (vsf), \
445 	.vs_dtype = (dt), \
446 	.hlpr = (hlp), \
447 	.hlprinfo = (hlpi), \
448 })
449 
450 #define	STATS_VSS_SUM() STATS_VSS(VS_STYPE_SUM, 0, 0, \
451     (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
452 
453 #define	STATS_VSS_MAX() STATS_VSS(VS_STYPE_MAX, 0, 0, \
454     (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
455 
456 #define	STATS_VSS_MIN() STATS_VSS(VS_STYPE_MIN, 0, 0, \
457     (vss_hlpr_fn)&stats_vss_numeric_hlpr, NULL)
458 
459 #define	STATS_VSS_HIST(htype, hist_hlpr_info) STATS_VSS(VS_STYPE_HIST, 0, \
460     htype, (vss_hlpr_fn)&stats_vss_hist_hlpr, \
461     (struct vss_hlpr_info *)(hist_hlpr_info))
462 
463 #define	STATS_VSS_TDIGEST(tdtype, tdgst_hlpr_info) STATS_VSS(VS_STYPE_TDGST, \
464     0, tdtype, (vss_hlpr_fn)&stats_vss_tdgst_hlpr, \
465     (struct vss_hlpr_info *)(tdgst_hlpr_info))
466 
467 #define	TDGST_NCTRS2VSDSZ(tdtype, nctds) (sizeof(struct voistatdata_##tdtype) + \
468     ((nctds) * sizeof(TYPEOF_MEMBER_PTR(struct voistatdata_##tdtype, \
469     ctdtree.arb_nodes))))
470 
471 #define	TDGST_HLPR_INFO(dt, nc, nf) \
472 (&(struct vss_tdgst_hlpr_info){ \
473     .tdgst_dtype = (dt), \
474     .nctds = (nc), \
475     .prec = (nf) \
476 })
477 
478 #define	STATS_VSS_TDGSTCLUST32(nctds, prec) \
479     STATS_VSS_TDIGEST(VSD_DTYPE_TDGSTCLUST32, \
480     TDGST_HLPR_INFO(VSD_DTYPE_TDGSTCLUST32, nctds, prec))
481 
482 #define	STATS_VSS_TDGSTCLUST64(nctds, prec) \
483     STATS_VSS_TDIGEST(VSD_DTYPE_TDGSTCLUST64, \
484     TDGST_HLPR_INFO(VSD_DTYPE_TDGSTCLUST64, nctds, prec))
485 
486 #define	HIST_VSDSZ2NBKTS(htype, dsz) \
487     ((dsz - sizeof(struct voistatdata_##htype)) / \
488     sizeof(TYPEOF_MEMBER(struct voistatdata_##htype, bkts[0])))
489 
490 #define	HIST_NBKTS2VSDSZ(htype, nbkts) (sizeof(struct voistatdata_##htype) + \
491     ((nbkts) * sizeof(TYPEOF_MEMBER_PTR(struct voistatdata_##htype, bkts))))
492 
493 #define	HIST_HLPR_INFO_LIN_FIELDS(si) .lin.stepinc = (si)
494 
495 #define	HIST_HLPR_INFO_EXP_FIELDS(sb, se) \
496     .exp.stepbase = (sb), .exp.stepexp = (se)
497 
498 #define	HIST_HLPR_INFO_LINEXP_FIELDS(nss, sb) \
499     .linexp.linstepdiv = (nss), .linexp.stepbase = (sb)
500 
501 #define	HIST_HLPR_INFO_USR_FIELDS(bbs) \
502     .usr.bkts = (TYPEOF_MEMBER(struct vss_hist_hlpr_info, usr.bkts))(bbs), \
503     .usr.nbkts = (sizeof(bbs) / sizeof(struct voistatdata_numeric[2]))
504 
505 #define	HIST_HLPR_INFO(dt, sch, f, lbd, ubd, bkthlpr_fields) \
506 (&(struct vss_hist_hlpr_info){ \
507     .scheme = (sch), \
508     .hist_dtype = (dt), \
509     .flags = (f), \
510     .lb = stats_ctor_vsd_numeric(lbd), \
511     .ub = stats_ctor_vsd_numeric(ubd), \
512     bkthlpr_fields \
513 })
514 
515 #define	STATS_VSS_CRHIST32_LIN(lb, ub, stepinc, vsdflags) \
516     STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
517     BKT_LIN, vsdflags, lb, ub, HIST_HLPR_INFO_LIN_FIELDS(stepinc)))
518 #define	STATS_VSS_CRHIST64_LIN(lb, ub, stepinc, vsdflags) \
519     STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
520     BKT_LIN, vsdflags, lb, ub, HIST_HLPR_INFO_LIN_FIELDS(stepinc)))
521 
522 #define	STATS_VSS_CRHIST32_EXP(lb, ub, stepbase, stepexp, vsdflags) \
523     STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
524     BKT_EXP, vsdflags, lb, ub, HIST_HLPR_INFO_EXP_FIELDS(stepbase, stepexp)))
525 #define	STATS_VSS_CRHIST64_EXP(lb, ub, stepbase, stepexp, vsdflags) \
526     STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
527     BKT_EXP, vsdflags, lb, ub, HIST_HLPR_INFO_EXP_FIELDS(stepbase, stepexp)))
528 
529 #define	STATS_VSS_CRHIST32_LINEXP(lb, ub, nlinsteps, stepbase, vsdflags) \
530     STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
531     BKT_LINEXP, vsdflags, lb, ub, HIST_HLPR_INFO_LINEXP_FIELDS(nlinsteps, \
532     stepbase)))
533 #define	STATS_VSS_CRHIST64_LINEXP(lb, ub, nlinsteps, stepbase, vsdflags) \
534     STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
535     BKT_LINEXP, vsdflags, lb, ub, HIST_HLPR_INFO_LINEXP_FIELDS(nlinsteps, \
536     stepbase)))
537 
538 #define	STATS_VSS_CRHIST32_USR(bkts, vsdflags) \
539     STATS_VSS_HIST(VSD_DTYPE_CRHIST32, HIST_HLPR_INFO(VSD_DTYPE_CRHIST32, \
540     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
541 #define	STATS_VSS_CRHIST64_USR(bkts, vsdflags) \
542     STATS_VSS_HIST(VSD_DTYPE_CRHIST64, HIST_HLPR_INFO(VSD_DTYPE_CRHIST64, \
543     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
544 
545 #define	STATS_VSS_DRHIST32_USR(bkts, vsdflags) \
546     STATS_VSS_HIST(VSD_DTYPE_DRHIST32, HIST_HLPR_INFO(VSD_DTYPE_DRHIST32, \
547     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
548 #define	STATS_VSS_DRHIST64_USR(bkts, vsdflags) \
549     STATS_VSS_HIST(VSD_DTYPE_DRHIST64, HIST_HLPR_INFO(VSD_DTYPE_DRHIST64, \
550     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(bkts)))
551 
552 #define	STATS_VSS_DVHIST32_USR(vals, vsdflags) \
553     STATS_VSS_HIST(VSD_DTYPE_DVHIST32, HIST_HLPR_INFO(VSD_DTYPE_DVHIST32, \
554     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(vals)))
555 #define	STATS_VSS_DVHIST64_USR(vals, vsdflags) \
556     STATS_VSS_HIST(VSD_DTYPE_DVHIST64, HIST_HLPR_INFO(VSD_DTYPE_DVHIST64, \
557     BKT_USR, vsdflags, 0, 0, HIST_HLPR_INFO_USR_FIELDS(vals)))
558 #define	DRBKT(lb, ub) { stats_ctor_vsd_numeric(lb), stats_ctor_vsd_numeric(ub) }
559 #define	DVBKT(val) DRBKT(val, val)
560 #define	CRBKT(lb) DRBKT(lb, lb)
561 #define	HBKTS(...) ((struct voistatdata_numeric [][2]){__VA_ARGS__})
562 
563 #define	VSD_HIST_FIELD(hist, cnst, hist_dtype, op, field) \
564     (VSD_DTYPE_CRHIST32 == (hist_dtype) ? \
565     op(_VSD(cnst, crhist32, hist)->field) : \
566     (VSD_DTYPE_DRHIST32 == (hist_dtype) ? \
567     op(_VSD(cnst, drhist32, hist)->field) : \
568     (VSD_DTYPE_DVHIST32 == (hist_dtype) ? \
569     op(_VSD(cnst, dvhist32, hist)->field) : \
570     (VSD_DTYPE_CRHIST64 == (hist_dtype) ? \
571     op(_VSD(cnst, crhist64, hist)->field) : \
572     (VSD_DTYPE_DRHIST64 == (hist_dtype) ? \
573     op(_VSD(cnst, drhist64, hist)->field) : \
574     (op(_VSD(cnst, dvhist64, hist)->field)))))))
575 #define	VSD_HIST_FIELDVAL(hist, hist_dtype, field) \
576     VSD_HIST_FIELD(hist, , hist_dtype, ,field)
577 #define	VSD_CONSTHIST_FIELDVAL(hist, hist_dtype, field) \
578     VSD_HIST_FIELD(hist, const, hist_dtype, ,field)
579 #define	VSD_HIST_FIELDPTR(hist, hist_dtype, field) \
580     VSD_HIST_FIELD(hist, , hist_dtype, (void *)&,field)
581 #define	VSD_CONSTHIST_FIELDPTR(hist, hist_dtype, field) \
582     VSD_HIST_FIELD(hist, const, hist_dtype, (void *)&,field)
583 
584 #define	VSD_CRHIST_FIELD(hist, cnst, hist_dtype, op, field) \
585     (VSD_DTYPE_CRHIST32 == (hist_dtype) ? \
586     op(_VSD(cnst, crhist32, hist)->field) : \
587     op(_VSD(cnst, crhist64, hist)->field))
588 #define	VSD_CRHIST_FIELDVAL(hist, hist_dtype, field) \
589     VSD_CRHIST_FIELD(hist, , hist_dtype, , field)
590 #define	VSD_CONSTCRHIST_FIELDVAL(hist, hist_dtype, field) \
591     VSD_CRHIST_FIELD(hist, const, hist_dtype, , field)
592 #define	VSD_CRHIST_FIELDPTR(hist, hist_dtype, field) \
593     VSD_CRHIST_FIELD(hist, , hist_dtype, &, field)
594 #define	VSD_CONSTCRHIST_FIELDPTR(hist, hist_dtype, field) \
595     VSD_CRHIST_FIELD(hist, const, hist_dtype, &, field)
596 
597 #define	VSD_DRHIST_FIELD(hist, cnst, hist_dtype, op, field) \
598     (VSD_DTYPE_DRHIST32 == (hist_dtype) ? \
599     op(_VSD(cnst, drhist32, hist)->field) : \
600     op(_VSD(cnst, drhist64, hist)->field))
601 #define	VSD_DRHIST_FIELDVAL(hist, hist_dtype, field) \
602     VSD_DRHIST_FIELD(hist, , hist_dtype, , field)
603 #define	VSD_CONSTDRHIST_FIELDVAL(hist, hist_dtype, field) \
604     VSD_DRHIST_FIELD(hist, const, hist_dtype, , field)
605 #define	VSD_DRHIST_FIELDPTR(hist, hist_dtype, field) \
606     VSD_DRHIST_FIELD(hist, , hist_dtype, &, field)
607 #define	VSD_CONSTDRHIST_FIELDPTR(hist, hist_dtype, field) \
608     VSD_DRHIST_FIELD(hist, const, hist_dtype, &, field)
609 
610 #define	VSD_DVHIST_FIELD(hist, cnst, hist_dtype, op, field) \
611     (VSD_DTYPE_DVHIST32 == (hist_dtype) ? \
612     op(_VSD(cnst, dvhist32, hist)->field) : \
613     op(_VSD(cnst, dvhist64, hist)->field))
614 #define	VSD_DVHIST_FIELDVAL(hist, hist_dtype, field) \
615     VSD_DVHIST_FIELD(hist, , hist_dtype, , field)
616 #define	VSD_CONSTDVHIST_FIELDVAL(hist, hist_dtype, field) \
617     VSD_DVHIST_FIELD(hist, const, hist_dtype, , field)
618 #define	VSD_DVHIST_FIELDPTR(hist, hist_dtype, field) \
619     VSD_DVHIST_FIELD(hist, , hist_dtype, &, field)
620 #define	VSD_CONSTDVHIST_FIELDPTR(hist, hist_dtype, field) \
621     VSD_DVHIST_FIELD(hist, const, hist_dtype, &, field)
622 
623 #define	STATS_ABI_V1	1
624 struct statsblobv1;
625 
626 enum sb_endianness {
627 	SB_UE = 0,	/* Unknown endian. */
628 	SB_LE,		/* Little endian. */
629 	SB_BE		/* Big endian. */
630 };
631 
632 struct statsblob {
633 	uint8_t		abi;
634 	uint8_t		endian;
635 	uint16_t	flags;
636 	uint16_t	maxsz;
637 	uint16_t	cursz;
638 	uint8_t		opaque[];
639 } __aligned(sizeof(void *));
640 
641 struct metablob {
642 	char		*tplname;
643 	uint32_t	tplhash;
644 	struct voi_meta {
645 		char *name;
646 		char *desc;
647 	}		*voi_meta;
648 };
649 
650 struct statsblob_tpl {
651 	struct metablob		*mb;	/* Template metadata */
652 	struct statsblob	*sb;	/* Template schema */
653 };
654 
655 struct stats_tpl_sample_rate {
656 	/* XXXLAS: Storing slot_id assumes templates are never removed. */
657 	int32_t		tpl_slot_id;
658 	uint32_t	tpl_sample_pct;
659 };
660 
661 /* Template sample rates list management callback actions. */
662 enum stats_tpl_sr_cb_action {
663 	TPL_SR_UNLOCKED_GET,
664 	TPL_SR_RLOCKED_GET,
665 	TPL_SR_RUNLOCK,
666 	TPL_SR_PUT
667 };
668 
669 /*
670  * Callback function pointer passed as arg1 to stats_tpl_sample_rates(). ctx is
671  * a heap-allocated, zero-initialised blob of contextual memory valid during a
672  * single stats_tpl_sample_rates() call and sized per the value passed as arg2.
673  * Returns 0 on success, an errno on error.
674  * - When called with "action == TPL_SR_*_GET", return the subsystem's rates
675  *   list ptr and count, locked or unlocked as requested.
676  * - When called with "action == TPL_SR_RUNLOCK", unlock the subsystem's rates
677  *   list ptr and count. Pair with a prior "action == TPL_SR_RLOCKED_GET" call.
678  * - When called with "action == TPL_SR_PUT, update the subsystem's rates list
679  *   ptr and count to the sysctl processed values and return the inactive list
680  *   details in rates/nrates for garbage collection by stats_tpl_sample_rates().
681  */
682 typedef int (*stats_tpl_sr_cb_t)(enum stats_tpl_sr_cb_action action,
683     struct stats_tpl_sample_rate **rates, int *nrates, void *ctx);
684 
685 /* Flags related to iterating over a stats blob. */
686 #define	SB_IT_FIRST_CB		0x0001
687 #define	SB_IT_LAST_CB		0x0002
688 #define	SB_IT_FIRST_VOI		0x0004
689 #define	SB_IT_LAST_VOI		0x0008
690 #define	SB_IT_FIRST_VOISTAT	0x0010
691 #define	SB_IT_LAST_VOISTAT	0x0020
692 #define	SB_IT_NULLVOI		0x0040
693 #define	SB_IT_NULLVOISTAT	0x0080
694 
695 struct sb_visit {
696 	struct voistatdata	*vs_data;
697 	uint32_t		tplhash;
698 	uint32_t		flags;
699 	int16_t			voi_id;
700 	int16_t			vs_dsz;
701 	uint16_t		vs_errs;
702 	enum vsd_dtype		voi_dtype : 8;
703 	enum vsd_dtype		vs_dtype : 8;
704 	int8_t			vs_stype;
705 };
706 
707 /* Stats blob iterator callback called for each struct voi. */
708 typedef int (*stats_blob_visitcb_t)(struct sb_visit *sbv, void *usrctx);
709 
710 /* ABI specific functions. */
711 int stats_v1_tpl_alloc(const char *name, uint32_t flags);
712 int stats_v1_tpl_add_voistats(uint32_t tpl_id, int32_t voi_id,
713     const char *voi_name, enum vsd_dtype voi_dtype, uint32_t nvss,
714     struct voistatspec *vss, uint32_t flags);
715 int stats_v1_blob_init(struct statsblobv1 *sb, uint32_t tpl_id, uint32_t flags);
716 struct statsblobv1 * stats_v1_blob_alloc(uint32_t tpl_id, uint32_t flags);
717 int stats_v1_blob_clone(struct statsblobv1 **dst, size_t dstmaxsz,
718     struct statsblobv1 *src, uint32_t flags);
719 void stats_v1_blob_destroy(struct statsblobv1 *sb);
720 #define	SB_CLONE_RSTSRC		0x0001 /* Reset src blob if clone successful. */
721 #define	SB_CLONE_ALLOCDST	0x0002 /* Allocate src->cursz memory for dst. */
722 #define	SB_CLONE_USRDSTNOFAULT	0x0004 /* Clone to wired userspace dst. */
723 #define	SB_CLONE_USRDST		0x0008 /* Clone to unwired userspace dst. */
724 int stats_v1_blob_snapshot(struct statsblobv1 **dst, size_t dstmaxsz,
725     struct statsblobv1 *src, uint32_t flags);
726 #define	SB_TOSTR_OBJDUMP	0x00000001
727 #define	SB_TOSTR_META		0x00000002 /* Lookup metablob and render metadata */
728 int stats_v1_blob_tostr(struct statsblobv1 *sb, struct sbuf *buf,
729     enum sb_str_fmt fmt, uint32_t flags);
730 int stats_v1_blob_visit(struct statsblobv1 *sb, stats_blob_visitcb_t func,
731     void *usrctx);
732 /* VOI related function flags. */
733 #define	SB_VOI_RELUPDATE	0x00000001 /* voival is relative to previous value. */
734 int stats_v1_voi_update(struct statsblobv1 *sb, int32_t voi_id,
735     enum vsd_dtype voi_dtype, struct voistatdata *voival, uint32_t flags);
736 int stats_v1_voistat_fetch_dptr(struct statsblobv1 *sb, int32_t voi_id,
737     enum voi_stype stype, enum vsd_dtype *retdtype, struct voistatdata **retvsd,
738     size_t *retvsdsz);
739 
740 /* End ABI specific functions. */
741 
742 /* ABI agnostic functions. */
743 int stats_vss_hlpr_init(enum vsd_dtype voi_dtype, uint32_t nvss,
744     struct voistatspec *vss);
745 void stats_vss_hlpr_cleanup(uint32_t nvss, struct voistatspec *vss);
746 int stats_vss_hist_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
747     struct vss_hist_hlpr_info *info);
748 int stats_vss_numeric_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
749     struct vss_numeric_hlpr_info *info);
750 int stats_vss_tdgst_hlpr(enum vsd_dtype voi_dtype, struct voistatspec *vss,
751     struct vss_tdgst_hlpr_info *info);
752 int stats_tpl_fetch(int tpl_id, struct statsblob_tpl **tpl);
753 int stats_tpl_fetch_allocid(const char *name, uint32_t hash);
754 int stats_tpl_id2name(uint32_t tpl_id, char *buf, size_t len);
755 int stats_tpl_sample_rates(struct sysctl_oid *oidp, void *arg1, intmax_t arg2,
756     struct sysctl_req *req);
757 int stats_tpl_sample_rollthedice(struct stats_tpl_sample_rate *rates,
758     int nrates, void *seed_bytes, size_t seed_len);
759 int stats_voistatdata_tostr(const struct voistatdata *vsd,
760     enum vsd_dtype voi_dtype, enum vsd_dtype vsd_dtype, size_t vsd_sz,
761     enum sb_str_fmt fmt, struct sbuf *buf, int objdump);
762 
763 static inline struct voistatdata_numeric
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_ */
1253