xref: /onnv-gate/usr/src/lib/libdtrace/common/dt_aggregate.c (revision 457:d8f2995c64aa)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <strings.h>
310Sstevel@tonic-gate #include <errno.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <dt_impl.h>
340Sstevel@tonic-gate #include <assert.h>
350Sstevel@tonic-gate 
360Sstevel@tonic-gate #define	DTRACE_AHASHSIZE	32779		/* big 'ol prime */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate static void
390Sstevel@tonic-gate dt_aggregate_count(uint64_t *existing, uint64_t *new, size_t size)
400Sstevel@tonic-gate {
410Sstevel@tonic-gate 	int i;
420Sstevel@tonic-gate 
430Sstevel@tonic-gate 	for (i = 0; i < size / sizeof (uint64_t); i++)
440Sstevel@tonic-gate 		existing[i] = existing[i] + new[i];
450Sstevel@tonic-gate }
460Sstevel@tonic-gate 
470Sstevel@tonic-gate static int
480Sstevel@tonic-gate dt_aggregate_countcmp(uint64_t *lhs, uint64_t *rhs)
490Sstevel@tonic-gate {
500Sstevel@tonic-gate 	uint64_t lvar = *lhs;
510Sstevel@tonic-gate 	uint64_t rvar = *rhs;
520Sstevel@tonic-gate 
530Sstevel@tonic-gate 	if (lvar > rvar)
540Sstevel@tonic-gate 		return (1);
550Sstevel@tonic-gate 
560Sstevel@tonic-gate 	if (lvar < rvar)
570Sstevel@tonic-gate 		return (-1);
580Sstevel@tonic-gate 
590Sstevel@tonic-gate 	return (0);
600Sstevel@tonic-gate }
610Sstevel@tonic-gate 
620Sstevel@tonic-gate /*ARGSUSED*/
630Sstevel@tonic-gate static void
640Sstevel@tonic-gate dt_aggregate_min(uint64_t *existing, uint64_t *new, size_t size)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate 	if (*new < *existing)
670Sstevel@tonic-gate 		*existing = *new;
680Sstevel@tonic-gate }
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*ARGSUSED*/
710Sstevel@tonic-gate static void
720Sstevel@tonic-gate dt_aggregate_max(uint64_t *existing, uint64_t *new, size_t size)
730Sstevel@tonic-gate {
740Sstevel@tonic-gate 	if (*new > *existing)
750Sstevel@tonic-gate 		*existing = *new;
760Sstevel@tonic-gate }
770Sstevel@tonic-gate 
780Sstevel@tonic-gate static int
790Sstevel@tonic-gate dt_aggregate_averagecmp(uint64_t *lhs, uint64_t *rhs)
800Sstevel@tonic-gate {
810Sstevel@tonic-gate 	uint64_t lavg = lhs[0] ? (lhs[1] / lhs[0]) : 0;
820Sstevel@tonic-gate 	uint64_t ravg = rhs[0] ? (rhs[1] / rhs[0]) : 0;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	if (lavg > ravg)
850Sstevel@tonic-gate 		return (1);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	if (lavg < ravg)
880Sstevel@tonic-gate 		return (-1);
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	return (0);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate 
930Sstevel@tonic-gate /*ARGSUSED*/
940Sstevel@tonic-gate static void
950Sstevel@tonic-gate dt_aggregate_lquantize(uint64_t *existing, uint64_t *new, size_t size)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate 	uint64_t arg = *existing++;
980Sstevel@tonic-gate 	uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg);
990Sstevel@tonic-gate 	int i;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	for (i = 0; i <= levels + 1; i++)
1020Sstevel@tonic-gate 		existing[i] = existing[i] + new[i + 1];
1030Sstevel@tonic-gate }
1040Sstevel@tonic-gate 
105*457Sbmc static long double
1060Sstevel@tonic-gate dt_aggregate_lquantizedsum(uint64_t *lquanta)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate 	uint64_t arg = *lquanta++;
1090Sstevel@tonic-gate 	int32_t base = DTRACE_LQUANTIZE_BASE(arg);
1100Sstevel@tonic-gate 	uint16_t step = DTRACE_LQUANTIZE_STEP(arg);
1110Sstevel@tonic-gate 	uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg), i;
112*457Sbmc 	long double total = (long double)lquanta[0] * (long double)(base - 1);
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	for (i = 0; i < levels; base += step, i++)
115*457Sbmc 		total += (long double)lquanta[i + 1] * (long double)base;
1160Sstevel@tonic-gate 
117*457Sbmc 	return (total + (long double)lquanta[levels + 1] *
118*457Sbmc 	    (long double)(base + 1));
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate static int
1220Sstevel@tonic-gate dt_aggregate_lquantizedcmp(uint64_t *lhs, uint64_t *rhs)
1230Sstevel@tonic-gate {
124*457Sbmc 	long double lsum = dt_aggregate_lquantizedsum(lhs);
125*457Sbmc 	long double rsum = dt_aggregate_lquantizedsum(rhs);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	if (lsum > rsum)
1280Sstevel@tonic-gate 		return (1);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	if (lsum < rsum)
1310Sstevel@tonic-gate 		return (-1);
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	return (0);
1340Sstevel@tonic-gate }
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate static int
1370Sstevel@tonic-gate dt_aggregate_quantizedcmp(uint64_t *lhs, uint64_t *rhs)
1380Sstevel@tonic-gate {
1390Sstevel@tonic-gate 	int nbuckets = DTRACE_QUANTIZE_NBUCKETS, i;
140*457Sbmc 	long double ltotal = 0, rtotal = 0;
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	for (i = 0; i < nbuckets; i++) {
1430Sstevel@tonic-gate 		int64_t bucketval = DTRACE_QUANTIZE_BUCKETVAL(i);
1440Sstevel@tonic-gate 
145*457Sbmc 		ltotal += (long double)bucketval * (long double)lhs[i];
146*457Sbmc 		rtotal += (long double)bucketval * (long double)rhs[i];
1470Sstevel@tonic-gate 	}
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 	if (ltotal > rtotal)
1500Sstevel@tonic-gate 		return (1);
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	if (ltotal < rtotal)
1530Sstevel@tonic-gate 		return (-1);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	return (0);
1560Sstevel@tonic-gate }
1570Sstevel@tonic-gate 
158*457Sbmc static void
159*457Sbmc dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data)
160*457Sbmc {
161*457Sbmc 	uint64_t pid = data[0];
162*457Sbmc 	uint64_t *pc = &data[1];
163*457Sbmc 	struct ps_prochandle *P;
164*457Sbmc 	GElf_Sym sym;
165*457Sbmc 
166*457Sbmc 	if (dtp->dt_vector != NULL)
167*457Sbmc 		return;
168*457Sbmc 
169*457Sbmc 	if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL)
170*457Sbmc 		return;
171*457Sbmc 
172*457Sbmc 	dt_proc_lock(dtp, P);
173*457Sbmc 
174*457Sbmc 	if (Plookup_by_addr(P, *pc, NULL, 0, &sym) == 0)
175*457Sbmc 		*pc = sym.st_value;
176*457Sbmc 
177*457Sbmc 	dt_proc_unlock(dtp, P);
178*457Sbmc 	dt_proc_release(dtp, P);
179*457Sbmc }
180*457Sbmc 
181*457Sbmc static void
182*457Sbmc dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data)
183*457Sbmc {
184*457Sbmc 	uint64_t pid = data[0];
185*457Sbmc 	uint64_t *pc = &data[1];
186*457Sbmc 	struct ps_prochandle *P;
187*457Sbmc 	const prmap_t *map;
188*457Sbmc 
189*457Sbmc 	if (dtp->dt_vector != NULL)
190*457Sbmc 		return;
191*457Sbmc 
192*457Sbmc 	if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL)
193*457Sbmc 		return;
194*457Sbmc 
195*457Sbmc 	dt_proc_lock(dtp, P);
196*457Sbmc 
197*457Sbmc 	if ((map = Paddr_to_map(P, *pc)) != NULL)
198*457Sbmc 		*pc = map->pr_vaddr;
199*457Sbmc 
200*457Sbmc 	dt_proc_unlock(dtp, P);
201*457Sbmc 	dt_proc_release(dtp, P);
202*457Sbmc }
203*457Sbmc 
204*457Sbmc static void
205*457Sbmc dt_aggregate_sym(dtrace_hdl_t *dtp, uint64_t *data)
206*457Sbmc {
207*457Sbmc 	GElf_Sym sym;
208*457Sbmc 	uint64_t *pc = data;
209*457Sbmc 
210*457Sbmc 	if (dtrace_lookup_by_addr(dtp, *pc, &sym, NULL) == 0)
211*457Sbmc 		*pc = sym.st_value;
212*457Sbmc }
213*457Sbmc 
214*457Sbmc static void
215*457Sbmc dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *data)
216*457Sbmc {
217*457Sbmc 	uint64_t *pc = data;
218*457Sbmc 	dt_module_t *dmp;
219*457Sbmc 
220*457Sbmc 	if (dtp->dt_vector != NULL) {
221*457Sbmc 		/*
222*457Sbmc 		 * We don't have a way of just getting the module for a
223*457Sbmc 		 * vectored open, and it doesn't seem to be worth defining
224*457Sbmc 		 * one.  This means that use of mod() won't get true
225*457Sbmc 		 * aggregation in the postmortem case (some modules may
226*457Sbmc 		 * appear more than once in aggregation output).  It seems
227*457Sbmc 		 * unlikely that anyone will ever notice or care...
228*457Sbmc 		 */
229*457Sbmc 		return;
230*457Sbmc 	}
231*457Sbmc 
232*457Sbmc 	for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
233*457Sbmc 	    dmp = dt_list_next(dmp)) {
234*457Sbmc 		if (*pc - dmp->dm_text_va < dmp->dm_text_size) {
235*457Sbmc 			*pc = dmp->dm_text_va;
236*457Sbmc 			return;
237*457Sbmc 		}
238*457Sbmc 	}
239*457Sbmc }
240*457Sbmc 
2410Sstevel@tonic-gate static int
2420Sstevel@tonic-gate dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	dtrace_epid_t id;
2450Sstevel@tonic-gate 	uint64_t hashval;
2460Sstevel@tonic-gate 	size_t offs, roffs, size, ndx;
2470Sstevel@tonic-gate 	int i, j, rval;
2480Sstevel@tonic-gate 	caddr_t addr, data;
2490Sstevel@tonic-gate 	dtrace_recdesc_t *rec;
2500Sstevel@tonic-gate 	dt_aggregate_t *agp = &dtp->dt_aggregate;
2510Sstevel@tonic-gate 	dtrace_aggdesc_t *agg;
2520Sstevel@tonic-gate 	dt_ahash_t *hash = &agp->dtat_hash;
2530Sstevel@tonic-gate 	dt_ahashent_t *h;
2540Sstevel@tonic-gate 	dtrace_bufdesc_t b = agp->dtat_buf, *buf = &b;
2550Sstevel@tonic-gate 	dtrace_aggdata_t *aggdata;
2560Sstevel@tonic-gate 	int flags = agp->dtat_flags;
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate 	buf->dtbd_cpu = cpu;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, buf) == -1) {
2610Sstevel@tonic-gate 		if (errno == ENOENT) {
2620Sstevel@tonic-gate 			/*
2630Sstevel@tonic-gate 			 * If that failed with ENOENT, it may be because the
2640Sstevel@tonic-gate 			 * CPU was unconfigured.  This is okay; we'll just
2650Sstevel@tonic-gate 			 * do nothing but return success.
2660Sstevel@tonic-gate 			 */
2670Sstevel@tonic-gate 			return (0);
2680Sstevel@tonic-gate 		}
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	if (buf->dtbd_drops != 0) {
2740Sstevel@tonic-gate 		if (dt_handle_cpudrop(dtp, cpu,
2750Sstevel@tonic-gate 		    DTRACEDROP_AGGREGATION, buf->dtbd_drops) == -1)
2760Sstevel@tonic-gate 			return (-1);
2770Sstevel@tonic-gate 	}
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 	if (buf->dtbd_size == 0)
2800Sstevel@tonic-gate 		return (0);
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	if (hash->dtah_hash == NULL) {
2830Sstevel@tonic-gate 		size_t size;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 		hash->dtah_size = DTRACE_AHASHSIZE;
2860Sstevel@tonic-gate 		size = hash->dtah_size * sizeof (dt_ahashent_t *);
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 		if ((hash->dtah_hash = malloc(size)) == NULL)
2890Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_NOMEM));
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 		bzero(hash->dtah_hash, size);
2920Sstevel@tonic-gate 	}
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	for (offs = 0; offs < buf->dtbd_size; ) {
2950Sstevel@tonic-gate 		/*
2960Sstevel@tonic-gate 		 * We're guaranteed to have an ID.
2970Sstevel@tonic-gate 		 */
2980Sstevel@tonic-gate 		id = *((dtrace_epid_t *)((uintptr_t)buf->dtbd_data +
2990Sstevel@tonic-gate 		    (uintptr_t)offs));
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 		if (id == DTRACE_AGGIDNONE) {
3020Sstevel@tonic-gate 			/*
3030Sstevel@tonic-gate 			 * This is filler to assure proper alignment of the
3040Sstevel@tonic-gate 			 * next record; we simply ignore it.
3050Sstevel@tonic-gate 			 */
3060Sstevel@tonic-gate 			offs += sizeof (id);
3070Sstevel@tonic-gate 			continue;
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 		if ((rval = dt_aggid_lookup(dtp, id, &agg)) != 0)
3110Sstevel@tonic-gate 			return (rval);
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate 		addr = buf->dtbd_data + offs;
3140Sstevel@tonic-gate 		size = agg->dtagd_size;
3150Sstevel@tonic-gate 		hashval = 0;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 		for (j = 0; j < agg->dtagd_nrecs - 1; j++) {
3180Sstevel@tonic-gate 			rec = &agg->dtagd_rec[j];
3190Sstevel@tonic-gate 			roffs = rec->dtrd_offset;
3200Sstevel@tonic-gate 
321*457Sbmc 			switch (rec->dtrd_action) {
322*457Sbmc 			case DTRACEACT_USYM:
323*457Sbmc 				dt_aggregate_usym(dtp,
324*457Sbmc 				    /* LINTED - alignment */
325*457Sbmc 				    (uint64_t *)&addr[roffs]);
326*457Sbmc 				break;
327*457Sbmc 
328*457Sbmc 			case DTRACEACT_UMOD:
329*457Sbmc 				dt_aggregate_umod(dtp,
330*457Sbmc 				    /* LINTED - alignment */
331*457Sbmc 				    (uint64_t *)&addr[roffs]);
332*457Sbmc 				break;
333*457Sbmc 
334*457Sbmc 			case DTRACEACT_SYM:
335*457Sbmc 				/* LINTED - alignment */
336*457Sbmc 				dt_aggregate_sym(dtp, (uint64_t *)&addr[roffs]);
337*457Sbmc 				break;
338*457Sbmc 
339*457Sbmc 			case DTRACEACT_MOD:
340*457Sbmc 				/* LINTED - alignment */
341*457Sbmc 				dt_aggregate_mod(dtp, (uint64_t *)&addr[roffs]);
342*457Sbmc 				break;
343*457Sbmc 
344*457Sbmc 			default:
345*457Sbmc 				break;
346*457Sbmc 			}
347*457Sbmc 
3480Sstevel@tonic-gate 			for (i = 0; i < rec->dtrd_size; i++)
3490Sstevel@tonic-gate 				hashval += addr[roffs + i];
3500Sstevel@tonic-gate 		}
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 		ndx = hashval % hash->dtah_size;
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 		for (h = hash->dtah_hash[ndx]; h != NULL; h = h->dtahe_next) {
3550Sstevel@tonic-gate 			if (h->dtahe_hashval != hashval)
3560Sstevel@tonic-gate 				continue;
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 			if (h->dtahe_size != size)
3590Sstevel@tonic-gate 				continue;
3600Sstevel@tonic-gate 
3610Sstevel@tonic-gate 			aggdata = &h->dtahe_data;
3620Sstevel@tonic-gate 			data = aggdata->dtada_data;
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 			for (j = 0; j < agg->dtagd_nrecs - 1; j++) {
3650Sstevel@tonic-gate 				rec = &agg->dtagd_rec[j];
3660Sstevel@tonic-gate 				roffs = rec->dtrd_offset;
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 				for (i = 0; i < rec->dtrd_size; i++)
3690Sstevel@tonic-gate 					if (addr[roffs + i] != data[roffs + i])
3700Sstevel@tonic-gate 						goto hashnext;
3710Sstevel@tonic-gate 			}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 			/*
3740Sstevel@tonic-gate 			 * We found it.  Now we need to apply the aggregating
3750Sstevel@tonic-gate 			 * action on the data here.
3760Sstevel@tonic-gate 			 */
3770Sstevel@tonic-gate 			rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
3780Sstevel@tonic-gate 			roffs = rec->dtrd_offset;
3790Sstevel@tonic-gate 			/* LINTED - alignment */
3800Sstevel@tonic-gate 			h->dtahe_aggregate((uint64_t *)&data[roffs],
3810Sstevel@tonic-gate 			    /* LINTED - alignment */
3820Sstevel@tonic-gate 			    (uint64_t *)&addr[roffs], rec->dtrd_size);
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 			/*
3850Sstevel@tonic-gate 			 * If we're keeping per CPU data, apply the aggregating
3860Sstevel@tonic-gate 			 * action there as well.
3870Sstevel@tonic-gate 			 */
3880Sstevel@tonic-gate 			if (aggdata->dtada_percpu != NULL) {
3890Sstevel@tonic-gate 				data = aggdata->dtada_percpu[cpu];
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 				/* LINTED - alignment */
3920Sstevel@tonic-gate 				h->dtahe_aggregate((uint64_t *)data,
3930Sstevel@tonic-gate 				    /* LINTED - alignment */
3940Sstevel@tonic-gate 				    (uint64_t *)&addr[roffs], rec->dtrd_size);
3950Sstevel@tonic-gate 			}
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 			goto bufnext;
3980Sstevel@tonic-gate hashnext:
3990Sstevel@tonic-gate 			continue;
4000Sstevel@tonic-gate 		}
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate 		/*
4030Sstevel@tonic-gate 		 * If we're here, we couldn't find an entry for this record.
4040Sstevel@tonic-gate 		 */
4050Sstevel@tonic-gate 		if ((h = malloc(sizeof (dt_ahashent_t))) == NULL)
4060Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_NOMEM));
4070Sstevel@tonic-gate 		bzero(h, sizeof (dt_ahashent_t));
4080Sstevel@tonic-gate 		aggdata = &h->dtahe_data;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 		if ((aggdata->dtada_data = malloc(size)) == NULL) {
4110Sstevel@tonic-gate 			free(h);
4120Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_NOMEM));
4130Sstevel@tonic-gate 		}
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 		bcopy(addr, aggdata->dtada_data, size);
4160Sstevel@tonic-gate 		aggdata->dtada_size = size;
4170Sstevel@tonic-gate 		aggdata->dtada_desc = agg;
4180Sstevel@tonic-gate 		aggdata->dtada_handle = dtp;
4190Sstevel@tonic-gate 		(void) dt_epid_lookup(dtp, agg->dtagd_epid,
4200Sstevel@tonic-gate 		    &aggdata->dtada_edesc, &aggdata->dtada_pdesc);
4210Sstevel@tonic-gate 		aggdata->dtada_normal = 1;
4220Sstevel@tonic-gate 
4230Sstevel@tonic-gate 		h->dtahe_hashval = hashval;
4240Sstevel@tonic-gate 		h->dtahe_size = size;
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 		rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate 		if (flags & DTRACE_A_PERCPU) {
4290Sstevel@tonic-gate 			int max_cpus = agp->dtat_maxcpu;
4300Sstevel@tonic-gate 			caddr_t *percpu = malloc(max_cpus * sizeof (caddr_t));
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 			if (percpu == NULL) {
4330Sstevel@tonic-gate 				free(aggdata->dtada_data);
4340Sstevel@tonic-gate 				free(h);
4350Sstevel@tonic-gate 				return (dt_set_errno(dtp, EDT_NOMEM));
4360Sstevel@tonic-gate 			}
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 			for (j = 0; j < max_cpus; j++) {
4390Sstevel@tonic-gate 				percpu[j] = malloc(rec->dtrd_size);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 				if (percpu[j] == NULL) {
4420Sstevel@tonic-gate 					while (--j >= 0)
4430Sstevel@tonic-gate 						free(percpu[j]);
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 					free(aggdata->dtada_data);
4460Sstevel@tonic-gate 					free(h);
4470Sstevel@tonic-gate 					return (dt_set_errno(dtp, EDT_NOMEM));
4480Sstevel@tonic-gate 				}
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate 				if (j == cpu) {
4510Sstevel@tonic-gate 					bcopy(&addr[rec->dtrd_offset],
4520Sstevel@tonic-gate 					    percpu[j], rec->dtrd_size);
4530Sstevel@tonic-gate 				} else {
4540Sstevel@tonic-gate 					bzero(percpu[j], rec->dtrd_size);
4550Sstevel@tonic-gate 				}
4560Sstevel@tonic-gate 			}
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 			aggdata->dtada_percpu = percpu;
4590Sstevel@tonic-gate 		}
4600Sstevel@tonic-gate 
4610Sstevel@tonic-gate 		switch (rec->dtrd_action) {
4620Sstevel@tonic-gate 		case DTRACEAGG_MIN:
4630Sstevel@tonic-gate 			h->dtahe_aggregate = dt_aggregate_min;
4640Sstevel@tonic-gate 			break;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 		case DTRACEAGG_MAX:
4670Sstevel@tonic-gate 			h->dtahe_aggregate = dt_aggregate_max;
4680Sstevel@tonic-gate 			break;
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 		case DTRACEAGG_LQUANTIZE:
4710Sstevel@tonic-gate 			h->dtahe_aggregate = dt_aggregate_lquantize;
4720Sstevel@tonic-gate 			break;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 		case DTRACEAGG_COUNT:
4750Sstevel@tonic-gate 		case DTRACEAGG_SUM:
4760Sstevel@tonic-gate 		case DTRACEAGG_AVG:
4770Sstevel@tonic-gate 		case DTRACEAGG_QUANTIZE:
4780Sstevel@tonic-gate 			h->dtahe_aggregate = dt_aggregate_count;
4790Sstevel@tonic-gate 			break;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 		default:
4820Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_BADAGG));
4830Sstevel@tonic-gate 		}
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 		if (hash->dtah_hash[ndx] != NULL)
4860Sstevel@tonic-gate 			hash->dtah_hash[ndx]->dtahe_prev = h;
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 		h->dtahe_next = hash->dtah_hash[ndx];
4890Sstevel@tonic-gate 		hash->dtah_hash[ndx] = h;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 		if (hash->dtah_all != NULL)
4920Sstevel@tonic-gate 			hash->dtah_all->dtahe_prevall = h;
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		h->dtahe_nextall = hash->dtah_all;
4950Sstevel@tonic-gate 		hash->dtah_all = h;
4960Sstevel@tonic-gate bufnext:
4970Sstevel@tonic-gate 		offs += agg->dtagd_size;
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 
5000Sstevel@tonic-gate 	return (0);
5010Sstevel@tonic-gate }
5020Sstevel@tonic-gate 
5030Sstevel@tonic-gate int
5040Sstevel@tonic-gate dtrace_aggregate_snap(dtrace_hdl_t *dtp)
5050Sstevel@tonic-gate {
5060Sstevel@tonic-gate 	int i, rval;
5070Sstevel@tonic-gate 	dt_aggregate_t *agp = &dtp->dt_aggregate;
5080Sstevel@tonic-gate 	hrtime_t now = gethrtime();
5090Sstevel@tonic-gate 	dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_AGGRATE];
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 	if (dtp->dt_lastagg != 0) {
5120Sstevel@tonic-gate 		if (now - dtp->dt_lastagg < interval)
5130Sstevel@tonic-gate 			return (0);
5140Sstevel@tonic-gate 
5150Sstevel@tonic-gate 		dtp->dt_lastagg += interval;
5160Sstevel@tonic-gate 	} else {
5170Sstevel@tonic-gate 		dtp->dt_lastagg = now;
5180Sstevel@tonic-gate 	}
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 	if (!dtp->dt_active)
5210Sstevel@tonic-gate 		return (dt_set_errno(dtp, EINVAL));
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	if (agp->dtat_buf.dtbd_size == 0)
5240Sstevel@tonic-gate 		return (0);
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	for (i = 0; i < agp->dtat_ncpus; i++) {
5270Sstevel@tonic-gate 		if (rval = dt_aggregate_snap_cpu(dtp, agp->dtat_cpus[i]))
5280Sstevel@tonic-gate 			return (rval);
5290Sstevel@tonic-gate 	}
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 	return (0);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate static int
5350Sstevel@tonic-gate dt_aggregate_hashcmp(const void *lhs, const void *rhs)
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate 	dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
5380Sstevel@tonic-gate 	dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
5390Sstevel@tonic-gate 	dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
5400Sstevel@tonic-gate 	dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	if (lagg->dtagd_nrecs < ragg->dtagd_nrecs)
5430Sstevel@tonic-gate 		return (-1);
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	if (lagg->dtagd_nrecs > ragg->dtagd_nrecs)
5460Sstevel@tonic-gate 		return (1);
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate 	return (0);
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate static int
5520Sstevel@tonic-gate dt_aggregate_varcmp(const void *lhs, const void *rhs)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate 	dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
5550Sstevel@tonic-gate 	dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
5560Sstevel@tonic-gate 	dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
5570Sstevel@tonic-gate 	dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
5580Sstevel@tonic-gate 	caddr_t ldata = lh->dtahe_data.dtada_data;
5590Sstevel@tonic-gate 	caddr_t rdata = rh->dtahe_data.dtada_data;
5600Sstevel@tonic-gate 	dtrace_recdesc_t *lrec, *rrec;
5610Sstevel@tonic-gate 	uint64_t lid, rid;
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	/*
5640Sstevel@tonic-gate 	 * We know that we have a compiler-generated ID as the first record.
5650Sstevel@tonic-gate 	 */
5660Sstevel@tonic-gate 	lrec = lagg->dtagd_rec;
5670Sstevel@tonic-gate 	rrec = ragg->dtagd_rec;
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	lid = *((uint64_t *)(uintptr_t)(ldata + lrec->dtrd_offset));
5700Sstevel@tonic-gate 	rid = *((uint64_t *)(uintptr_t)(rdata + rrec->dtrd_offset));
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	if (lid < rid)
5730Sstevel@tonic-gate 		return (-1);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	if (lid > rid)
5760Sstevel@tonic-gate 		return (1);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	return (0);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate static int
5820Sstevel@tonic-gate dt_aggregate_keycmp(const void *lhs, const void *rhs)
5830Sstevel@tonic-gate {
5840Sstevel@tonic-gate 	dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
5850Sstevel@tonic-gate 	dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
5860Sstevel@tonic-gate 	dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
5870Sstevel@tonic-gate 	dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
5880Sstevel@tonic-gate 	dtrace_recdesc_t *lrec, *rrec;
5890Sstevel@tonic-gate 	char *ldata, *rdata;
590403Sbmc 	int rval, i, j;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0)
5930Sstevel@tonic-gate 		return (rval);
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 	for (i = 1; i < lagg->dtagd_nrecs - 1; i++) {
5960Sstevel@tonic-gate 		uint64_t lval, rval;
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate 		lrec = &lagg->dtagd_rec[i];
5990Sstevel@tonic-gate 		rrec = &ragg->dtagd_rec[i];
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		ldata = lh->dtahe_data.dtada_data + lrec->dtrd_offset;
6020Sstevel@tonic-gate 		rdata = rh->dtahe_data.dtada_data + rrec->dtrd_offset;
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 		if (lrec->dtrd_size < rrec->dtrd_size)
6050Sstevel@tonic-gate 			return (-1);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 		if (lrec->dtrd_size > rrec->dtrd_size)
6080Sstevel@tonic-gate 			return (1);
6090Sstevel@tonic-gate 
6100Sstevel@tonic-gate 		switch (lrec->dtrd_size) {
6110Sstevel@tonic-gate 		case sizeof (uint64_t):
6120Sstevel@tonic-gate 			/* LINTED - alignment */
6130Sstevel@tonic-gate 			lval = *((uint64_t *)ldata);
6140Sstevel@tonic-gate 			/* LINTED - alignment */
6150Sstevel@tonic-gate 			rval = *((uint64_t *)rdata);
6160Sstevel@tonic-gate 			break;
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 		case sizeof (uint32_t):
6190Sstevel@tonic-gate 			/* LINTED - alignment */
6200Sstevel@tonic-gate 			lval = *((uint32_t *)ldata);
6210Sstevel@tonic-gate 			/* LINTED - alignment */
6220Sstevel@tonic-gate 			rval = *((uint32_t *)rdata);
6230Sstevel@tonic-gate 			break;
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 		case sizeof (uint16_t):
6260Sstevel@tonic-gate 			/* LINTED - alignment */
6270Sstevel@tonic-gate 			lval = *((uint16_t *)ldata);
6280Sstevel@tonic-gate 			/* LINTED - alignment */
6290Sstevel@tonic-gate 			rval = *((uint16_t *)rdata);
6300Sstevel@tonic-gate 			break;
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 		case sizeof (uint8_t):
6330Sstevel@tonic-gate 			lval = *((uint8_t *)ldata);
6340Sstevel@tonic-gate 			rval = *((uint8_t *)rdata);
6350Sstevel@tonic-gate 			break;
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 		default:
638403Sbmc 			for (j = 0; j < lrec->dtrd_size; j++) {
639403Sbmc 				lval = ((uint8_t *)ldata)[j];
640403Sbmc 				rval = ((uint8_t *)rdata)[j];
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 				if (lval < rval)
6430Sstevel@tonic-gate 					return (-1);
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 				if (lval > rval)
6460Sstevel@tonic-gate 					return (1);
6470Sstevel@tonic-gate 			}
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 			continue;
6500Sstevel@tonic-gate 		}
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 		if (lval < rval)
6530Sstevel@tonic-gate 			return (-1);
6540Sstevel@tonic-gate 
6550Sstevel@tonic-gate 		if (lval > rval)
6560Sstevel@tonic-gate 			return (1);
6570Sstevel@tonic-gate 	}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	return (0);
6600Sstevel@tonic-gate }
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate static int
6630Sstevel@tonic-gate dt_aggregate_valcmp(const void *lhs, const void *rhs)
6640Sstevel@tonic-gate {
6650Sstevel@tonic-gate 	dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
6660Sstevel@tonic-gate 	dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
6670Sstevel@tonic-gate 	dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
6680Sstevel@tonic-gate 	dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
6690Sstevel@tonic-gate 	caddr_t ldata = lh->dtahe_data.dtada_data;
6700Sstevel@tonic-gate 	caddr_t rdata = rh->dtahe_data.dtada_data;
6710Sstevel@tonic-gate 	dtrace_recdesc_t *lrec, *rrec;
6720Sstevel@tonic-gate 	uint64_t *laddr, *raddr;
6730Sstevel@tonic-gate 	int rval, i;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0)
6760Sstevel@tonic-gate 		return (rval);
6770Sstevel@tonic-gate 
6780Sstevel@tonic-gate 	if (lagg->dtagd_nrecs < ragg->dtagd_nrecs)
6790Sstevel@tonic-gate 		return (-1);
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	if (lagg->dtagd_nrecs > ragg->dtagd_nrecs)
6820Sstevel@tonic-gate 		return (1);
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	for (i = 0; i < lagg->dtagd_nrecs; i++) {
6850Sstevel@tonic-gate 		lrec = &lagg->dtagd_rec[i];
6860Sstevel@tonic-gate 		rrec = &ragg->dtagd_rec[i];
6870Sstevel@tonic-gate 
6880Sstevel@tonic-gate 		if (lrec->dtrd_offset < rrec->dtrd_offset)
6890Sstevel@tonic-gate 			return (-1);
6900Sstevel@tonic-gate 
6910Sstevel@tonic-gate 		if (lrec->dtrd_offset > rrec->dtrd_offset)
6920Sstevel@tonic-gate 			return (1);
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 		if (lrec->dtrd_action < rrec->dtrd_action)
6950Sstevel@tonic-gate 			return (-1);
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 		if (lrec->dtrd_action > rrec->dtrd_action)
6980Sstevel@tonic-gate 			return (1);
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	laddr = (uint64_t *)(uintptr_t)(ldata + lrec->dtrd_offset);
7020Sstevel@tonic-gate 	raddr = (uint64_t *)(uintptr_t)(rdata + rrec->dtrd_offset);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	switch (lrec->dtrd_action) {
7050Sstevel@tonic-gate 	case DTRACEAGG_AVG:
7060Sstevel@tonic-gate 		rval = dt_aggregate_averagecmp(laddr, raddr);
7070Sstevel@tonic-gate 		break;
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	case DTRACEAGG_QUANTIZE:
7100Sstevel@tonic-gate 		rval = dt_aggregate_quantizedcmp(laddr, raddr);
7110Sstevel@tonic-gate 		break;
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	case DTRACEAGG_LQUANTIZE:
7140Sstevel@tonic-gate 		rval = dt_aggregate_lquantizedcmp(laddr, raddr);
7150Sstevel@tonic-gate 		break;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	case DTRACEAGG_COUNT:
7180Sstevel@tonic-gate 	case DTRACEAGG_SUM:
7190Sstevel@tonic-gate 	case DTRACEAGG_MIN:
7200Sstevel@tonic-gate 	case DTRACEAGG_MAX:
7210Sstevel@tonic-gate 		rval = dt_aggregate_countcmp(laddr, raddr);
7220Sstevel@tonic-gate 		break;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 	default:
7250Sstevel@tonic-gate 		assert(0);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	if (rval != 0)
7290Sstevel@tonic-gate 		return (rval);
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	/*
7320Sstevel@tonic-gate 	 * If we're here, the values for the two aggregation elements are
7330Sstevel@tonic-gate 	 * equal.  We already know that the key layout is the same for the two
7340Sstevel@tonic-gate 	 * elements; we must now compare the keys themselves as a tie-breaker.
7350Sstevel@tonic-gate 	 */
7360Sstevel@tonic-gate 	return (dt_aggregate_keycmp(lhs, rhs));
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate static int
7400Sstevel@tonic-gate dt_aggregate_keyvarcmp(const void *lhs, const void *rhs)
7410Sstevel@tonic-gate {
7420Sstevel@tonic-gate 	int rval;
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	if ((rval = dt_aggregate_keycmp(lhs, rhs)) != 0)
7450Sstevel@tonic-gate 		return (rval);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 	return (dt_aggregate_varcmp(lhs, rhs));
7480Sstevel@tonic-gate }
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate static int
7510Sstevel@tonic-gate dt_aggregate_varkeycmp(const void *lhs, const void *rhs)
7520Sstevel@tonic-gate {
7530Sstevel@tonic-gate 	int rval;
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0)
7560Sstevel@tonic-gate 		return (rval);
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	return (dt_aggregate_keycmp(lhs, rhs));
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate static int
7620Sstevel@tonic-gate dt_aggregate_valvarcmp(const void *lhs, const void *rhs)
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate 	int rval;
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 	if ((rval = dt_aggregate_valcmp(lhs, rhs)) != 0)
7670Sstevel@tonic-gate 		return (rval);
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 	return (dt_aggregate_varcmp(lhs, rhs));
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate static int
7730Sstevel@tonic-gate dt_aggregate_varvalcmp(const void *lhs, const void *rhs)
7740Sstevel@tonic-gate {
7750Sstevel@tonic-gate 	int rval;
7760Sstevel@tonic-gate 
7770Sstevel@tonic-gate 	if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0)
7780Sstevel@tonic-gate 		return (rval);
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	return (dt_aggregate_valcmp(lhs, rhs));
7810Sstevel@tonic-gate }
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate static int
7840Sstevel@tonic-gate dt_aggregate_keyvarrevcmp(const void *lhs, const void *rhs)
7850Sstevel@tonic-gate {
7860Sstevel@tonic-gate 	return (dt_aggregate_keyvarcmp(rhs, lhs));
7870Sstevel@tonic-gate }
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate static int
7900Sstevel@tonic-gate dt_aggregate_varkeyrevcmp(const void *lhs, const void *rhs)
7910Sstevel@tonic-gate {
7920Sstevel@tonic-gate 	return (dt_aggregate_varkeycmp(rhs, lhs));
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate static int
7960Sstevel@tonic-gate dt_aggregate_valvarrevcmp(const void *lhs, const void *rhs)
7970Sstevel@tonic-gate {
7980Sstevel@tonic-gate 	return (dt_aggregate_valvarcmp(rhs, lhs));
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate static int
8020Sstevel@tonic-gate dt_aggregate_varvalrevcmp(const void *lhs, const void *rhs)
8030Sstevel@tonic-gate {
8040Sstevel@tonic-gate 	return (dt_aggregate_varvalcmp(rhs, lhs));
8050Sstevel@tonic-gate }
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate int
8080Sstevel@tonic-gate dt_aggregate_go(dtrace_hdl_t *dtp)
8090Sstevel@tonic-gate {
8100Sstevel@tonic-gate 	dt_aggregate_t *agp = &dtp->dt_aggregate;
8110Sstevel@tonic-gate 	dtrace_optval_t size, cpu;
8120Sstevel@tonic-gate 	dtrace_bufdesc_t *buf = &agp->dtat_buf;
8130Sstevel@tonic-gate 	int rval, i;
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	assert(agp->dtat_maxcpu == 0);
8160Sstevel@tonic-gate 	assert(agp->dtat_ncpu == 0);
8170Sstevel@tonic-gate 	assert(agp->dtat_cpus == NULL);
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 	agp->dtat_maxcpu = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
8200Sstevel@tonic-gate 	agp->dtat_ncpu = dt_sysconf(dtp, _SC_NPROCESSORS_MAX);
8210Sstevel@tonic-gate 	agp->dtat_cpus = malloc(agp->dtat_ncpu * sizeof (processorid_t));
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	if (agp->dtat_cpus == NULL)
8240Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_NOMEM));
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	/*
8270Sstevel@tonic-gate 	 * Use the aggregation buffer size as reloaded from the kernel.
8280Sstevel@tonic-gate 	 */
8290Sstevel@tonic-gate 	size = dtp->dt_options[DTRACEOPT_AGGSIZE];
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	rval = dtrace_getopt(dtp, "aggsize", &size);
8320Sstevel@tonic-gate 	assert(rval == 0);
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	if (size == 0 || size == DTRACEOPT_UNSET)
8350Sstevel@tonic-gate 		return (0);
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 	buf = &agp->dtat_buf;
8380Sstevel@tonic-gate 	buf->dtbd_size = size;
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	if ((buf->dtbd_data = malloc(buf->dtbd_size)) == NULL)
8410Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_NOMEM));
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	/*
8440Sstevel@tonic-gate 	 * Now query for the CPUs enabled.
8450Sstevel@tonic-gate 	 */
8460Sstevel@tonic-gate 	rval = dtrace_getopt(dtp, "cpu", &cpu);
8470Sstevel@tonic-gate 	assert(rval == 0 && cpu != DTRACEOPT_UNSET);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	if (cpu != DTRACE_CPUALL) {
8500Sstevel@tonic-gate 		assert(cpu < agp->dtat_ncpu);
8510Sstevel@tonic-gate 		agp->dtat_cpus[agp->dtat_ncpus++] = (processorid_t)cpu;
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 		return (0);
8540Sstevel@tonic-gate 	}
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	agp->dtat_ncpus = 0;
8570Sstevel@tonic-gate 	for (i = 0; i < agp->dtat_maxcpu; i++) {
8580Sstevel@tonic-gate 		if (dt_status(dtp, i) == -1)
8590Sstevel@tonic-gate 			continue;
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 		agp->dtat_cpus[agp->dtat_ncpus++] = i;
8620Sstevel@tonic-gate 	}
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 	return (0);
8650Sstevel@tonic-gate }
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate static int
8680Sstevel@tonic-gate dt_aggwalk_rval(dtrace_hdl_t *dtp, dt_ahashent_t *h, int rval)
8690Sstevel@tonic-gate {
8700Sstevel@tonic-gate 	dt_aggregate_t *agp = &dtp->dt_aggregate;
8710Sstevel@tonic-gate 	dtrace_aggdata_t *data;
8720Sstevel@tonic-gate 	dtrace_aggdesc_t *aggdesc;
8730Sstevel@tonic-gate 	dtrace_recdesc_t *rec;
8740Sstevel@tonic-gate 	int i;
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate 	switch (rval) {
8770Sstevel@tonic-gate 	case DTRACE_AGGWALK_NEXT:
8780Sstevel@tonic-gate 		break;
8790Sstevel@tonic-gate 
8800Sstevel@tonic-gate 	case DTRACE_AGGWALK_CLEAR: {
8810Sstevel@tonic-gate 		uint32_t size, offs = 0;
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 		aggdesc = h->dtahe_data.dtada_desc;
8840Sstevel@tonic-gate 		rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
8850Sstevel@tonic-gate 		size = rec->dtrd_size;
8860Sstevel@tonic-gate 		data = &h->dtahe_data;
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 		if (rec->dtrd_action == DTRACEAGG_LQUANTIZE) {
8890Sstevel@tonic-gate 			offs = sizeof (uint64_t);
8900Sstevel@tonic-gate 			size -= sizeof (uint64_t);
8910Sstevel@tonic-gate 		}
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate 		bzero(&data->dtada_data[rec->dtrd_offset] + offs, size);
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 		if (data->dtada_percpu == NULL)
8960Sstevel@tonic-gate 			break;
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 		for (i = 0; i < dtp->dt_aggregate.dtat_maxcpu; i++)
8990Sstevel@tonic-gate 			bzero(data->dtada_percpu[i] + offs, size);
9000Sstevel@tonic-gate 		break;
9010Sstevel@tonic-gate 	}
9020Sstevel@tonic-gate 
9030Sstevel@tonic-gate 	case DTRACE_AGGWALK_ERROR:
9040Sstevel@tonic-gate 		/*
9050Sstevel@tonic-gate 		 * We assume that errno is already set in this case.
9060Sstevel@tonic-gate 		 */
9070Sstevel@tonic-gate 		return (dt_set_errno(dtp, errno));
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	case DTRACE_AGGWALK_ABORT:
9100Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_DIRABORT));
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	case DTRACE_AGGWALK_DENORMALIZE:
9130Sstevel@tonic-gate 		h->dtahe_data.dtada_normal = 1;
9140Sstevel@tonic-gate 		return (0);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	case DTRACE_AGGWALK_NORMALIZE:
9170Sstevel@tonic-gate 		if (h->dtahe_data.dtada_normal == 0) {
9180Sstevel@tonic-gate 			h->dtahe_data.dtada_normal = 1;
9190Sstevel@tonic-gate 			return (dt_set_errno(dtp, EDT_BADRVAL));
9200Sstevel@tonic-gate 		}
9210Sstevel@tonic-gate 
9220Sstevel@tonic-gate 		return (0);
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate 	case DTRACE_AGGWALK_REMOVE: {
9250Sstevel@tonic-gate 		dtrace_aggdata_t *aggdata = &h->dtahe_data;
9260Sstevel@tonic-gate 		int i, max_cpus = agp->dtat_maxcpu;
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 		/*
9290Sstevel@tonic-gate 		 * First, remove this hash entry from its hash chain.
9300Sstevel@tonic-gate 		 */
9310Sstevel@tonic-gate 		if (h->dtahe_prev != NULL) {
9320Sstevel@tonic-gate 			h->dtahe_prev->dtahe_next = h->dtahe_next;
9330Sstevel@tonic-gate 		} else {
9340Sstevel@tonic-gate 			dt_ahash_t *hash = &agp->dtat_hash;
9350Sstevel@tonic-gate 			size_t ndx = h->dtahe_hashval % hash->dtah_size;
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 			assert(hash->dtah_hash[ndx] == h);
9380Sstevel@tonic-gate 			hash->dtah_hash[ndx] = h->dtahe_next;
9390Sstevel@tonic-gate 		}
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 		if (h->dtahe_next != NULL)
9420Sstevel@tonic-gate 			h->dtahe_next->dtahe_prev = h->dtahe_prev;
9430Sstevel@tonic-gate 
9440Sstevel@tonic-gate 		/*
9450Sstevel@tonic-gate 		 * Now remove it from the list of all hash entries.
9460Sstevel@tonic-gate 		 */
9470Sstevel@tonic-gate 		if (h->dtahe_prevall != NULL) {
9480Sstevel@tonic-gate 			h->dtahe_prevall->dtahe_nextall = h->dtahe_nextall;
9490Sstevel@tonic-gate 		} else {
9500Sstevel@tonic-gate 			dt_ahash_t *hash = &agp->dtat_hash;
9510Sstevel@tonic-gate 
9520Sstevel@tonic-gate 			assert(hash->dtah_all == h);
9530Sstevel@tonic-gate 			hash->dtah_all = h->dtahe_nextall;
9540Sstevel@tonic-gate 		}
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 		if (h->dtahe_nextall != NULL)
9570Sstevel@tonic-gate 			h->dtahe_nextall->dtahe_prevall = h->dtahe_prevall;
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 		/*
9600Sstevel@tonic-gate 		 * We're unlinked.  We can safely destroy the data.
9610Sstevel@tonic-gate 		 */
9620Sstevel@tonic-gate 		if (aggdata->dtada_percpu != NULL) {
9630Sstevel@tonic-gate 			for (i = 0; i < max_cpus; i++)
9640Sstevel@tonic-gate 				free(aggdata->dtada_percpu[i]);
9650Sstevel@tonic-gate 			free(aggdata->dtada_percpu);
9660Sstevel@tonic-gate 		}
9670Sstevel@tonic-gate 
9680Sstevel@tonic-gate 		free(aggdata->dtada_data);
9690Sstevel@tonic-gate 		free(h);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 		return (0);
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	default:
9750Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_BADRVAL));
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	return (0);
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate int
9820Sstevel@tonic-gate dtrace_aggregate_walk(dtrace_hdl_t *dtp, dtrace_aggregate_f *func, void *arg)
9830Sstevel@tonic-gate {
9840Sstevel@tonic-gate 	dt_ahashent_t *h, *next;
9850Sstevel@tonic-gate 	dt_ahash_t *hash = &dtp->dt_aggregate.dtat_hash;
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	for (h = hash->dtah_all; h != NULL; h = next) {
9880Sstevel@tonic-gate 		/*
9890Sstevel@tonic-gate 		 * dt_aggwalk_rval() can potentially remove the current hash
9900Sstevel@tonic-gate 		 * entry; we need to load the next hash entry before calling
9910Sstevel@tonic-gate 		 * into it.
9920Sstevel@tonic-gate 		 */
9930Sstevel@tonic-gate 		next = h->dtahe_nextall;
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 		if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
9960Sstevel@tonic-gate 			return (-1);
9970Sstevel@tonic-gate 	}
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	return (0);
10000Sstevel@tonic-gate }
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate static int
10030Sstevel@tonic-gate dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
10040Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg,
10050Sstevel@tonic-gate     int (*sfunc)(const void *, const void *))
10060Sstevel@tonic-gate {
10070Sstevel@tonic-gate 	dt_aggregate_t *agp = &dtp->dt_aggregate;
10080Sstevel@tonic-gate 	dt_ahashent_t *h, **sorted;
10090Sstevel@tonic-gate 	dt_ahash_t *hash = &agp->dtat_hash;
10100Sstevel@tonic-gate 	size_t i, nentries = 0;
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall)
10130Sstevel@tonic-gate 		nentries++;
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	sorted = malloc(nentries * sizeof (dt_ahashent_t *));
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 	if (sorted == NULL)
10180Sstevel@tonic-gate 		return (dt_set_errno(dtp, EDT_NOMEM));
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate 	for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall)
10210Sstevel@tonic-gate 		sorted[i++] = h;
10220Sstevel@tonic-gate 
10230Sstevel@tonic-gate 	qsort(sorted, nentries, sizeof (dt_ahashent_t *), sfunc);
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 	for (i = 0; i < nentries; i++) {
10260Sstevel@tonic-gate 		h = sorted[i];
10270Sstevel@tonic-gate 
10280Sstevel@tonic-gate 		if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
10290Sstevel@tonic-gate 			return (-1);
10300Sstevel@tonic-gate 	}
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	free(sorted);
10330Sstevel@tonic-gate 	return (0);
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate int
10370Sstevel@tonic-gate dtrace_aggregate_walk_keysorted(dtrace_hdl_t *dtp,
10380Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg)
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate 	return (dt_aggregate_walk_sorted(dtp, func,
10410Sstevel@tonic-gate 	    arg, dt_aggregate_varkeycmp));
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate int
10450Sstevel@tonic-gate dtrace_aggregate_walk_valsorted(dtrace_hdl_t *dtp,
10460Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg)
10470Sstevel@tonic-gate {
10480Sstevel@tonic-gate 	return (dt_aggregate_walk_sorted(dtp, func,
10490Sstevel@tonic-gate 	    arg, dt_aggregate_varvalcmp));
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate int
10530Sstevel@tonic-gate dtrace_aggregate_walk_keyvarsorted(dtrace_hdl_t *dtp,
10540Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg)
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate 	return (dt_aggregate_walk_sorted(dtp, func,
10570Sstevel@tonic-gate 	    arg, dt_aggregate_keyvarcmp));
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate int
10610Sstevel@tonic-gate dtrace_aggregate_walk_valvarsorted(dtrace_hdl_t *dtp,
10620Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg)
10630Sstevel@tonic-gate {
10640Sstevel@tonic-gate 	return (dt_aggregate_walk_sorted(dtp, func,
10650Sstevel@tonic-gate 	    arg, dt_aggregate_valvarcmp));
10660Sstevel@tonic-gate }
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate int
10690Sstevel@tonic-gate dtrace_aggregate_walk_keyrevsorted(dtrace_hdl_t *dtp,
10700Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg)
10710Sstevel@tonic-gate {
10720Sstevel@tonic-gate 	return (dt_aggregate_walk_sorted(dtp, func,
10730Sstevel@tonic-gate 	    arg, dt_aggregate_varkeyrevcmp));
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate int
10770Sstevel@tonic-gate dtrace_aggregate_walk_valrevsorted(dtrace_hdl_t *dtp,
10780Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg)
10790Sstevel@tonic-gate {
10800Sstevel@tonic-gate 	return (dt_aggregate_walk_sorted(dtp, func,
10810Sstevel@tonic-gate 	    arg, dt_aggregate_varvalrevcmp));
10820Sstevel@tonic-gate }
10830Sstevel@tonic-gate 
10840Sstevel@tonic-gate int
10850Sstevel@tonic-gate dtrace_aggregate_walk_keyvarrevsorted(dtrace_hdl_t *dtp,
10860Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg)
10870Sstevel@tonic-gate {
10880Sstevel@tonic-gate 	return (dt_aggregate_walk_sorted(dtp, func,
10890Sstevel@tonic-gate 	    arg, dt_aggregate_keyvarrevcmp));
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate int
10930Sstevel@tonic-gate dtrace_aggregate_walk_valvarrevsorted(dtrace_hdl_t *dtp,
10940Sstevel@tonic-gate     dtrace_aggregate_f *func, void *arg)
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate 	return (dt_aggregate_walk_sorted(dtp, func,
10970Sstevel@tonic-gate 	    arg, dt_aggregate_valvarrevcmp));
10980Sstevel@tonic-gate }
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate int
11010Sstevel@tonic-gate dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp,
11020Sstevel@tonic-gate     dtrace_aggregate_walk_f *func)
11030Sstevel@tonic-gate {
11040Sstevel@tonic-gate 	dt_print_aggdata_t pd;
11050Sstevel@tonic-gate 
11060Sstevel@tonic-gate 	pd.dtpa_dtp = dtp;
11070Sstevel@tonic-gate 	pd.dtpa_fp = fp;
11080Sstevel@tonic-gate 	pd.dtpa_allunprint = 1;
11090Sstevel@tonic-gate 
11100Sstevel@tonic-gate 	if (func == NULL)
11110Sstevel@tonic-gate 		func = dtrace_aggregate_walk_valsorted;
11120Sstevel@tonic-gate 
11130Sstevel@tonic-gate 	if ((*func)(dtp, dt_print_agg, &pd) == -1)
11140Sstevel@tonic-gate 		return (dt_set_errno(dtp, dtp->dt_errno));
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	return (0);
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate 
11190Sstevel@tonic-gate void
11200Sstevel@tonic-gate dtrace_aggregate_clear(dtrace_hdl_t *dtp)
11210Sstevel@tonic-gate {
11220Sstevel@tonic-gate 	dt_aggregate_t *agp = &dtp->dt_aggregate;
11230Sstevel@tonic-gate 	dt_ahash_t *hash = &agp->dtat_hash;
11240Sstevel@tonic-gate 	dt_ahashent_t *h;
11250Sstevel@tonic-gate 	dtrace_aggdata_t *data;
11260Sstevel@tonic-gate 	dtrace_aggdesc_t *aggdesc;
11270Sstevel@tonic-gate 	dtrace_recdesc_t *rec;
11280Sstevel@tonic-gate 	int i, max_cpus = agp->dtat_maxcpu;
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
11310Sstevel@tonic-gate 		aggdesc = h->dtahe_data.dtada_desc;
11320Sstevel@tonic-gate 		rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
11330Sstevel@tonic-gate 		data = &h->dtahe_data;
11340Sstevel@tonic-gate 
11350Sstevel@tonic-gate 		bzero(&data->dtada_data[rec->dtrd_offset], rec->dtrd_size);
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 		if (data->dtada_percpu == NULL)
11380Sstevel@tonic-gate 			continue;
11390Sstevel@tonic-gate 
11400Sstevel@tonic-gate 		for (i = 0; i < max_cpus; i++)
11410Sstevel@tonic-gate 			bzero(data->dtada_percpu[i], rec->dtrd_size);
11420Sstevel@tonic-gate 	}
11430Sstevel@tonic-gate }
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate void
11460Sstevel@tonic-gate dt_aggregate_destroy(dtrace_hdl_t *dtp)
11470Sstevel@tonic-gate {
11480Sstevel@tonic-gate 	dt_aggregate_t *agp = &dtp->dt_aggregate;
11490Sstevel@tonic-gate 	dt_ahash_t *hash = &agp->dtat_hash;
11500Sstevel@tonic-gate 	dt_ahashent_t *h, *next;
11510Sstevel@tonic-gate 	dtrace_aggdata_t *aggdata;
11520Sstevel@tonic-gate 	int i, max_cpus = agp->dtat_maxcpu;
11530Sstevel@tonic-gate 
11540Sstevel@tonic-gate 	if (hash->dtah_hash == NULL) {
11550Sstevel@tonic-gate 		assert(hash->dtah_all == NULL);
11560Sstevel@tonic-gate 	} else {
11570Sstevel@tonic-gate 		free(hash->dtah_hash);
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 		for (h = hash->dtah_all; h != NULL; h = next) {
11600Sstevel@tonic-gate 			next = h->dtahe_nextall;
11610Sstevel@tonic-gate 
11620Sstevel@tonic-gate 			aggdata = &h->dtahe_data;
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 			if (aggdata->dtada_percpu != NULL) {
11650Sstevel@tonic-gate 				for (i = 0; i < max_cpus; i++)
11660Sstevel@tonic-gate 					free(aggdata->dtada_percpu[i]);
11670Sstevel@tonic-gate 				free(aggdata->dtada_percpu);
11680Sstevel@tonic-gate 			}
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 			free(aggdata->dtada_data);
11710Sstevel@tonic-gate 			free(h);
11720Sstevel@tonic-gate 		}
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 		hash->dtah_hash = NULL;
11750Sstevel@tonic-gate 		hash->dtah_all = NULL;
11760Sstevel@tonic-gate 		hash->dtah_size = 0;
11770Sstevel@tonic-gate 	}
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	free(agp->dtat_buf.dtbd_data);
11800Sstevel@tonic-gate 	free(agp->dtat_cpus);
11810Sstevel@tonic-gate }
1182