Home | History | Annotate | Download | only in common
      1     0   stevel /*
      2     0   stevel  * CDDL HEADER START
      3     0   stevel  *
      4     0   stevel  * The contents of this file are subject to the terms of the
      5  2777    tomee  * Common Development and Distribution License (the "License").
      6  2777    tomee  * You may not use this file except in compliance with the License.
      7     0   stevel  *
      8     0   stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0   stevel  * or http://www.opensolaris.org/os/licensing.
     10     0   stevel  * See the License for the specific language governing permissions
     11     0   stevel  * and limitations under the License.
     12     0   stevel  *
     13     0   stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0   stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0   stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0   stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0   stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0   stevel  *
     19     0   stevel  * CDDL HEADER END
     20     0   stevel  */
     21  2777    tomee 
     22     0   stevel /*
     23  5984  jhaslam  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24     0   stevel  * Use is subject to license terms.
     25     0   stevel  */
     26     0   stevel 
     27     0   stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28     0   stevel 
     29     0   stevel #include <stdlib.h>
     30     0   stevel #include <strings.h>
     31     0   stevel #include <errno.h>
     32     0   stevel #include <unistd.h>
     33     0   stevel #include <dt_impl.h>
     34     0   stevel #include <assert.h>
     35  1017      bmc #include <alloca.h>
     36  1017      bmc #include <limits.h>
     37     0   stevel 
     38     0   stevel #define	DTRACE_AHASHSIZE	32779		/* big 'ol prime */
     39  1017      bmc 
     40  1017      bmc /*
     41  1017      bmc  * Because qsort(3C) does not allow an argument to be passed to a comparison
     42  1017      bmc  * function, the variables that affect comparison must regrettably be global;
     43  1017      bmc  * they are protected by a global static lock, dt_qsort_lock.
     44  1017      bmc  */
     45  1017      bmc static pthread_mutex_t dt_qsort_lock = PTHREAD_MUTEX_INITIALIZER;
     46  1017      bmc 
     47  1017      bmc static int dt_revsort;
     48  1017      bmc static int dt_keysort;
     49  1017      bmc static int dt_keypos;
     50  1017      bmc 
     51  1017      bmc #define	DT_LESSTHAN	(dt_revsort == 0 ? -1 : 1)
     52  1017      bmc #define	DT_GREATERTHAN	(dt_revsort == 0 ? 1 : -1)
     53     0   stevel 
     54     0   stevel static void
     55   491      bmc dt_aggregate_count(int64_t *existing, int64_t *new, size_t size)
     56     0   stevel {
     57     0   stevel 	int i;
     58     0   stevel 
     59   491      bmc 	for (i = 0; i < size / sizeof (int64_t); i++)
     60     0   stevel 		existing[i] = existing[i] + new[i];
     61     0   stevel }
     62     0   stevel 
     63     0   stevel static int
     64   491      bmc dt_aggregate_countcmp(int64_t *lhs, int64_t *rhs)
     65     0   stevel {
     66   491      bmc 	int64_t lvar = *lhs;
     67   491      bmc 	int64_t rvar = *rhs;
     68     0   stevel 
     69  1017      bmc 	if (lvar < rvar)
     70  1017      bmc 		return (DT_LESSTHAN);
     71  1017      bmc 
     72     0   stevel 	if (lvar > rvar)
     73  1017      bmc 		return (DT_GREATERTHAN);
     74     0   stevel 
     75     0   stevel 	return (0);
     76     0   stevel }
     77     0   stevel 
     78     0   stevel /*ARGSUSED*/
     79     0   stevel static void
     80   491      bmc dt_aggregate_min(int64_t *existing, int64_t *new, size_t size)
     81     0   stevel {
     82     0   stevel 	if (*new < *existing)
     83     0   stevel 		*existing = *new;
     84     0   stevel }
     85     0   stevel 
     86     0   stevel /*ARGSUSED*/
     87     0   stevel static void
     88   491      bmc dt_aggregate_max(int64_t *existing, int64_t *new, size_t size)
     89     0   stevel {
     90     0   stevel 	if (*new > *existing)
     91     0   stevel 		*existing = *new;
     92     0   stevel }
     93     0   stevel 
     94     0   stevel static int
     95   491      bmc dt_aggregate_averagecmp(int64_t *lhs, int64_t *rhs)
     96     0   stevel {
     97   491      bmc 	int64_t lavg = lhs[0] ? (lhs[1] / lhs[0]) : 0;
     98   491      bmc 	int64_t ravg = rhs[0] ? (rhs[1] / rhs[0]) : 0;
     99     0   stevel 
    100  1017      bmc 	if (lavg < ravg)
    101  1017      bmc 		return (DT_LESSTHAN);
    102  1017      bmc 
    103     0   stevel 	if (lavg > ravg)
    104  5984  jhaslam 		return (DT_GREATERTHAN);
    105  5984  jhaslam 
    106  5984  jhaslam 	return (0);
    107  5984  jhaslam }
    108  5984  jhaslam 
    109  5984  jhaslam static int
    110  5984  jhaslam dt_aggregate_stddevcmp(int64_t *lhs, int64_t *rhs)
    111  5984  jhaslam {
    112  5984  jhaslam 	uint64_t lsd = dt_stddev((uint64_t *)lhs, 1);
    113  5984  jhaslam 	uint64_t rsd = dt_stddev((uint64_t *)rhs, 1);
    114  5984  jhaslam 
    115  5984  jhaslam 	if (lsd < rsd)
    116  5984  jhaslam 		return (DT_LESSTHAN);
    117  5984  jhaslam 
    118  5984  jhaslam 	if (lsd > rsd)
    119  1017      bmc 		return (DT_GREATERTHAN);
    120     0   stevel 
    121     0   stevel 	return (0);
    122     0   stevel }
    123     0   stevel 
    124     0   stevel /*ARGSUSED*/
    125     0   stevel static void
    126   491      bmc dt_aggregate_lquantize(int64_t *existing, int64_t *new, size_t size)
    127     0   stevel {
    128   491      bmc 	int64_t arg = *existing++;
    129     0   stevel 	uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg);
    130     0   stevel 	int i;
    131     0   stevel 
    132     0   stevel 	for (i = 0; i <= levels + 1; i++)
    133     0   stevel 		existing[i] = existing[i] + new[i + 1];
    134     0   stevel }
    135     0   stevel 
    136   457      bmc static long double
    137   491      bmc dt_aggregate_lquantizedsum(int64_t *lquanta)
    138     0   stevel {
    139   491      bmc 	int64_t arg = *lquanta++;
    140     0   stevel 	int32_t base = DTRACE_LQUANTIZE_BASE(arg);
    141     0   stevel 	uint16_t step = DTRACE_LQUANTIZE_STEP(arg);
    142     0   stevel 	uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg), i;
    143   457      bmc 	long double total = (long double)lquanta[0] * (long double)(base - 1);
    144     0   stevel 
    145     0   stevel 	for (i = 0; i < levels; base += step, i++)
    146   457      bmc 		total += (long double)lquanta[i + 1] * (long double)base;
    147     0   stevel 
    148   457      bmc 	return (total + (long double)lquanta[levels + 1] *
    149   457      bmc 	    (long double)(base + 1));
    150     0   stevel }
    151     0   stevel 
    152   491      bmc static int64_t
    153   491      bmc dt_aggregate_lquantizedzero(int64_t *lquanta)
    154   491      bmc {
    155   491      bmc 	int64_t arg = *lquanta++;
    156   491      bmc 	int32_t base = DTRACE_LQUANTIZE_BASE(arg);
    157   491      bmc 	uint16_t step = DTRACE_LQUANTIZE_STEP(arg);
    158   491      bmc 	uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg), i;
    159   491      bmc 
    160   491      bmc 	if (base - 1 == 0)
    161   491      bmc 		return (lquanta[0]);
    162   491      bmc 
    163   491      bmc 	for (i = 0; i < levels; base += step, i++) {
    164   491      bmc 		if (base != 0)
    165   491      bmc 			continue;
    166   491      bmc 
    167   491      bmc 		return (lquanta[i + 1]);
    168   491      bmc 	}
    169   491      bmc 
    170   491      bmc 	if (base + 1 == 0)
    171   491      bmc 		return (lquanta[levels + 1]);
    172   491      bmc 
    173   491      bmc 	return (0);
    174   491      bmc }
    175   491      bmc 
    176     0   stevel static int
    177   491      bmc dt_aggregate_lquantizedcmp(int64_t *lhs, int64_t *rhs)
    178     0   stevel {
    179   457      bmc 	long double lsum = dt_aggregate_lquantizedsum(lhs);
    180   457      bmc 	long double rsum = dt_aggregate_lquantizedsum(rhs);
    181   491      bmc 	int64_t lzero, rzero;
    182     0   stevel 
    183  1017      bmc 	if (lsum < rsum)
    184  1017      bmc 		return (DT_LESSTHAN);
    185  1017      bmc 
    186     0   stevel 	if (lsum > rsum)
    187  1017      bmc 		return (DT_GREATERTHAN);
    188     0   stevel 
    189   491      bmc 	/*
    190   491      bmc 	 * If they're both equal, then we will compare based on the weights at
    191   491      bmc 	 * zero.  If the weights at zero are equal (or if zero is not within
    192   491      bmc 	 * the range of the linear quantization), then this will be judged a
    193   491      bmc 	 * tie and will be resolved based on the key comparison.
    194   491      bmc 	 */
    195   491      bmc 	lzero = dt_aggregate_lquantizedzero(lhs);
    196   491      bmc 	rzero = dt_aggregate_lquantizedzero(rhs);
    197   491      bmc 
    198  1017      bmc 	if (lzero < rzero)
    199  1017      bmc 		return (DT_LESSTHAN);
    200  1017      bmc 
    201   491      bmc 	if (lzero > rzero)
    202  1017      bmc 		return (DT_GREATERTHAN);
    203   491      bmc 
    204     0   stevel 	return (0);
    205     0   stevel }
    206     0   stevel 
    207     0   stevel static int
    208   491      bmc dt_aggregate_quantizedcmp(int64_t *lhs, int64_t *rhs)
    209     0   stevel {
    210     0   stevel 	int nbuckets = DTRACE_QUANTIZE_NBUCKETS, i;
    211   457      bmc 	long double ltotal = 0, rtotal = 0;
    212   491      bmc 	int64_t lzero, rzero;
    213     0   stevel 
    214     0   stevel 	for (i = 0; i < nbuckets; i++) {
    215     0   stevel 		int64_t bucketval = DTRACE_QUANTIZE_BUCKETVAL(i);
    216   491      bmc 
    217   491      bmc 		if (bucketval == 0) {
    218   491      bmc 			lzero = lhs[i];
    219   491      bmc 			rzero = rhs[i];
    220   491      bmc 		}
    221     0   stevel 
    222   457      bmc 		ltotal += (long double)bucketval * (long double)lhs[i];
    223   457      bmc 		rtotal += (long double)bucketval * (long double)rhs[i];
    224     0   stevel 	}
    225     0   stevel 
    226  1017      bmc 	if (ltotal < rtotal)
    227  1017      bmc 		return (DT_LESSTHAN);
    228  1017      bmc 
    229     0   stevel 	if (ltotal > rtotal)
    230  1017      bmc 		return (DT_GREATERTHAN);
    231   491      bmc 
    232   491      bmc 	/*
    233   491      bmc 	 * If they're both equal, then we will compare based on the weights at
    234   491      bmc 	 * zero.  If the weights at zero are equal, then this will be judged a
    235   491      bmc 	 * tie and will be resolved based on the key comparison.
    236   491      bmc 	 */
    237  1017      bmc 	if (lzero < rzero)
    238  1017      bmc 		return (DT_LESSTHAN);
    239  1017      bmc 
    240   491      bmc 	if (lzero > rzero)
    241  1017      bmc 		return (DT_GREATERTHAN);
    242     0   stevel 
    243     0   stevel 	return (0);
    244   457      bmc }
    245   457      bmc 
    246   457      bmc static void
    247   457      bmc dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data)
    248   457      bmc {
    249   457      bmc 	uint64_t pid = data[0];
    250   457      bmc 	uint64_t *pc = &data[1];
    251   457      bmc 	struct ps_prochandle *P;
    252   457      bmc 	GElf_Sym sym;
    253   457      bmc 
    254   457      bmc 	if (dtp->dt_vector != NULL)
    255   457      bmc 		return;
    256   457      bmc 
    257   457      bmc 	if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL)
    258   457      bmc 		return;
    259   457      bmc 
    260   457      bmc 	dt_proc_lock(dtp, P);
    261   457      bmc 
    262   457      bmc 	if (Plookup_by_addr(P, *pc, NULL, 0, &sym) == 0)
    263   457      bmc 		*pc = sym.st_value;
    264   457      bmc 
    265   457      bmc 	dt_proc_unlock(dtp, P);
    266   457      bmc 	dt_proc_release(dtp, P);
    267   457      bmc }
    268   457      bmc 
    269   457      bmc static void
    270   457      bmc dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data)
    271   457      bmc {
    272   457      bmc 	uint64_t pid = data[0];
    273   457      bmc 	uint64_t *pc = &data[1];
    274   457      bmc 	struct ps_prochandle *P;
    275   457      bmc 	const prmap_t *map;
    276   457      bmc 
    277   457      bmc 	if (dtp->dt_vector != NULL)
    278   457      bmc 		return;
    279   457      bmc 
    280   457      bmc 	if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL)
    281   457      bmc 		return;
    282   457      bmc 
    283   457      bmc 	dt_proc_lock(dtp, P);
    284   457      bmc 
    285   457      bmc 	if ((map = Paddr_to_map(P, *pc)) != NULL)
    286   457      bmc 		*pc = map->pr_vaddr;
    287   457      bmc 
    288   457      bmc 	dt_proc_unlock(dtp, P);
    289   457      bmc 	dt_proc_release(dtp, P);
    290   457      bmc }
    291   457      bmc 
    292   457      bmc static void
    293   457      bmc dt_aggregate_sym(dtrace_hdl_t *dtp, uint64_t *data)
    294   457      bmc {
    295   457      bmc 	GElf_Sym sym;
    296   457      bmc 	uint64_t *pc = data;
    297   457      bmc 
    298   457      bmc 	if (dtrace_lookup_by_addr(dtp, *pc, &sym, NULL) == 0)
    299   457      bmc 		*pc = sym.st_value;
    300   457      bmc }
    301   457      bmc 
    302   457      bmc static void
    303   457      bmc dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *data)
    304   457      bmc {
    305   457      bmc 	uint64_t *pc = data;
    306   457      bmc 	dt_module_t *dmp;
    307   457      bmc 
    308   457      bmc 	if (dtp->dt_vector != NULL) {
    309   457      bmc 		/*
    310   457      bmc 		 * We don't have a way of just getting the module for a
    311   457      bmc 		 * vectored open, and it doesn't seem to be worth defining
    312   457      bmc 		 * one.  This means that use of mod() won't get true
    313   457      bmc 		 * aggregation in the postmortem case (some modules may
    314   457      bmc 		 * appear more than once in aggregation output).  It seems
    315   457      bmc 		 * unlikely that anyone will ever notice or care...
    316   457      bmc 		 */
    317   457      bmc 		return;
    318   457      bmc 	}
    319   457      bmc 
    320   457      bmc 	for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL;
    321   457      bmc 	    dmp = dt_list_next(dmp)) {
    322   457      bmc 		if (*pc - dmp->dm_text_va < dmp->dm_text_size) {
    323   457      bmc 			*pc = dmp->dm_text_va;
    324   457      bmc 			return;
    325   457      bmc 		}
    326   457      bmc 	}
    327     0   stevel }
    328  1017      bmc 
    329  1017      bmc static dtrace_aggvarid_t
    330  1017      bmc dt_aggregate_aggvarid(dt_ahashent_t *ent)
    331  1017      bmc {
    332  1017      bmc 	dtrace_aggdesc_t *agg = ent->dtahe_data.dtada_desc;
    333  1017      bmc 	caddr_t data = ent->dtahe_data.dtada_data;
    334  1017      bmc 	dtrace_recdesc_t *rec = agg->dtagd_rec;
    335  1017      bmc 
    336  1017      bmc 	/*
    337  1017      bmc 	 * First, we'll check the variable ID in the aggdesc.  If it's valid,
    338  1017      bmc 	 * we'll return it.  If not, we'll use the compiler-generated ID
    339  1017      bmc 	 * present as the first record.
    340  1017      bmc 	 */
    341  1017      bmc 	if (agg->dtagd_varid != DTRACE_AGGVARIDNONE)
    342  1017      bmc 		return (agg->dtagd_varid);
    343  1017      bmc 
    344  1017      bmc 	agg->dtagd_varid = *((dtrace_aggvarid_t *)(uintptr_t)(data +
    345  1017      bmc 	    rec->dtrd_offset));
    346  1017      bmc 
    347  1017      bmc 	return (agg->dtagd_varid);
    348  1017      bmc }
    349  1017      bmc 
    350     0   stevel 
    351     0   stevel static int
    352     0   stevel dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu)
    353     0   stevel {
    354     0   stevel 	dtrace_epid_t id;
    355     0   stevel 	uint64_t hashval;
    356     0   stevel 	size_t offs, roffs, size, ndx;
    357     0   stevel 	int i, j, rval;
    358     0   stevel 	caddr_t addr, data;
    359     0   stevel 	dtrace_recdesc_t *rec;
    360     0   stevel 	dt_aggregate_t *agp = &dtp->dt_aggregate;
    361     0   stevel 	dtrace_aggdesc_t *agg;
    362     0   stevel 	dt_ahash_t *hash = &agp->dtat_hash;
    363     0   stevel 	dt_ahashent_t *h;
    364     0   stevel 	dtrace_bufdesc_t b = agp->dtat_buf, *buf = &b;
    365     0   stevel 	dtrace_aggdata_t *aggdata;
    366     0   stevel 	int flags = agp->dtat_flags;
    367     0   stevel 
    368     0   stevel 	buf->dtbd_cpu = cpu;
    369     0   stevel 
    370     0   stevel 	if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, buf) == -1) {
    371     0   stevel 		if (errno == ENOENT) {
    372     0   stevel 			/*
    373     0   stevel 			 * If that failed with ENOENT, it may be because the
    374     0   stevel 			 * CPU was unconfigured.  This is okay; we'll just
    375     0   stevel 			 * do nothing but return success.
    376     0   stevel 			 */
    377     0   stevel 			return (0);
    378     0   stevel 		}
    379     0   stevel 
    380     0   stevel 		return (dt_set_errno(dtp, errno));
    381     0   stevel 	}
    382     0   stevel 
    383     0   stevel 	if (buf->dtbd_drops != 0) {
    384     0   stevel 		if (dt_handle_cpudrop(dtp, cpu,
    385     0   stevel 		    DTRACEDROP_AGGREGATION, buf->dtbd_drops) == -1)
    386     0   stevel 			return (-1);
    387     0   stevel 	}
    388     0   stevel 
    389     0   stevel 	if (buf->dtbd_size == 0)
    390     0   stevel 		return (0);
    391     0   stevel 
    392     0   stevel 	if (hash->dtah_hash == NULL) {
    393     0   stevel 		size_t size;
    394     0   stevel 
    395     0   stevel 		hash->dtah_size = DTRACE_AHASHSIZE;
    396     0   stevel 		size = hash->dtah_size * sizeof (dt_ahashent_t *);
    397     0   stevel 
    398     0   stevel 		if ((hash->dtah_hash = malloc(size)) == NULL)
    399     0   stevel 			return (dt_set_errno(dtp, EDT_NOMEM));
    400     0   stevel 
    401     0   stevel 		bzero(hash->dtah_hash, size);
    402     0   stevel 	}
    403     0   stevel 
    404     0   stevel 	for (offs = 0; offs < buf->dtbd_size; ) {
    405     0   stevel 		/*
    406     0   stevel 		 * We're guaranteed to have an ID.
    407     0   stevel 		 */
    408     0   stevel 		id = *((dtrace_epid_t *)((uintptr_t)buf->dtbd_data +
    409     0   stevel 		    (uintptr_t)offs));
    410     0   stevel 
    411     0   stevel 		if (id == DTRACE_AGGIDNONE) {
    412     0   stevel 			/*
    413     0   stevel 			 * This is filler to assure proper alignment of the
    414     0   stevel 			 * next record; we simply ignore it.
    415     0   stevel 			 */
    416     0   stevel 			offs += sizeof (id);
    417     0   stevel 			continue;
    418     0   stevel 		}
    419     0   stevel 
    420     0   stevel 		if ((rval = dt_aggid_lookup(dtp, id, &agg)) != 0)
    421     0   stevel 			return (rval);
    422     0   stevel 
    423     0   stevel 		addr = buf->dtbd_data + offs;
    424     0   stevel 		size = agg->dtagd_size;
    425     0   stevel 		hashval = 0;
    426     0   stevel 
    427     0   stevel 		for (j = 0; j < agg->dtagd_nrecs - 1; j++) {
    428     0   stevel 			rec = &agg->dtagd_rec[j];
    429     0   stevel 			roffs = rec->dtrd_offset;
    430   457      bmc 
    431   457      bmc 			switch (rec->dtrd_action) {
    432   457      bmc 			case DTRACEACT_USYM:
    433   457      bmc 				dt_aggregate_usym(dtp,
    434   457      bmc 				    /* LINTED - alignment */
    435   457      bmc 				    (uint64_t *)&addr[roffs]);
    436   457      bmc 				break;
    437   457      bmc 
    438   457      bmc 			case DTRACEACT_UMOD:
    439   457      bmc 				dt_aggregate_umod(dtp,
    440   457      bmc 				    /* LINTED - alignment */
    441   457      bmc 				    (uint64_t *)&addr[roffs]);
    442   457      bmc 				break;
    443   457      bmc 
    444   457      bmc 			case DTRACEACT_SYM:
    445   457      bmc 				/* LINTED - alignment */
    446   457      bmc 				dt_aggregate_sym(dtp, (uint64_t *)&addr[roffs]);
    447   457      bmc 				break;
    448   457      bmc 
    449   457      bmc 			case DTRACEACT_MOD:
    450   457      bmc 				/* LINTED - alignment */
    451   457      bmc 				dt_aggregate_mod(dtp, (uint64_t *)&addr[roffs]);
    452   457      bmc 				break;
    453   457      bmc 
    454   457      bmc 			default:
    455   457      bmc 				break;
    456   457      bmc 			}
    457     0   stevel 
    458     0   stevel 			for (i = 0; i < rec->dtrd_size; i++)
    459     0   stevel 				hashval += addr[roffs + i];
    460     0   stevel 		}
    461     0   stevel 
    462     0   stevel 		ndx = hashval % hash->dtah_size;
    463     0   stevel 
    464     0   stevel 		for (h = hash->dtah_hash[ndx]; h != NULL; h = h->dtahe_next) {
    465     0   stevel 			if (h->dtahe_hashval != hashval)
    466     0   stevel 				continue;
    467     0   stevel 
    468     0   stevel 			if (h->dtahe_size != size)
    469     0   stevel 				continue;
    470     0   stevel 
    471     0   stevel 			aggdata = &h->dtahe_data;
    472     0   stevel 			data = aggdata->dtada_data;
    473     0   stevel 
    474     0   stevel 			for (j = 0; j < agg->dtagd_nrecs - 1; j++) {
    475     0   stevel 				rec = &agg->dtagd_rec[j];
    476     0   stevel 				roffs = rec->dtrd_offset;
    477     0   stevel 
    478     0   stevel 				for (i = 0; i < rec->dtrd_size; i++)
    479     0   stevel 					if (addr[roffs + i] != data[roffs + i])
    480     0   stevel 						goto hashnext;
    481     0   stevel 			}
    482     0   stevel 
    483     0   stevel 			/*
    484     0   stevel 			 * We found it.  Now we need to apply the aggregating
    485     0   stevel 			 * action on the data here.
    486     0   stevel 			 */
    487     0   stevel 			rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
    488     0   stevel 			roffs = rec->dtrd_offset;
    489     0   stevel 			/* LINTED - alignment */
    490   491      bmc 			h->dtahe_aggregate((int64_t *)&data[roffs],
    491     0   stevel 			    /* LINTED - alignment */
    492   491      bmc 			    (int64_t *)&addr[roffs], rec->dtrd_size);
    493     0   stevel 
    494     0   stevel 			/*
    495     0   stevel 			 * If we're keeping per CPU data, apply the aggregating
    496     0   stevel 			 * action there as well.
    497     0   stevel 			 */
    498     0   stevel 			if (aggdata->dtada_percpu != NULL) {
    499     0   stevel 				data = aggdata->dtada_percpu[cpu];
    500     0   stevel 
    501     0   stevel 				/* LINTED - alignment */
    502   491      bmc 				h->dtahe_aggregate((int64_t *)data,
    503     0   stevel 				    /* LINTED - alignment */
    504   491      bmc 				    (int64_t *)&addr[roffs], rec->dtrd_size);
    505     0   stevel 			}
    506     0   stevel 
    507     0   stevel 			goto bufnext;
    508     0   stevel hashnext:
    509     0   stevel 			continue;
    510     0   stevel 		}
    511     0   stevel 
    512     0   stevel 		/*
    513     0   stevel 		 * If we're here, we couldn't find an entry for this record.
    514     0   stevel 		 */
    515     0   stevel 		if ((h = malloc(sizeof (dt_ahashent_t))) == NULL)
    516     0   stevel 			return (dt_set_errno(dtp, EDT_NOMEM));
    517     0   stevel 		bzero(h, sizeof (dt_ahashent_t));
    518     0   stevel 		aggdata = &h->dtahe_data;
    519     0   stevel 
    520     0   stevel 		if ((aggdata->dtada_data = malloc(size)) == NULL) {
    521     0   stevel 			free(h);
    522     0   stevel 			return (dt_set_errno(dtp, EDT_NOMEM));
    523     0   stevel 		}
    524     0   stevel 
    525     0   stevel 		bcopy(addr, aggdata->dtada_data, size);
    526     0   stevel 		aggdata->dtada_size = size;
    527     0   stevel 		aggdata->dtada_desc = agg;
    528     0   stevel 		aggdata->dtada_handle = dtp;
    529     0   stevel 		(void) dt_epid_lookup(dtp, agg->dtagd_epid,
    530     0   stevel 		    &aggdata->dtada_edesc, &aggdata->dtada_pdesc);
    531     0   stevel 		aggdata->dtada_normal = 1;
    532     0   stevel 
    533     0   stevel 		h->dtahe_hashval = hashval;
    534     0   stevel 		h->dtahe_size = size;
    535  1017      bmc 		(void) dt_aggregate_aggvarid(h);
    536     0   stevel 
    537     0   stevel 		rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1];
    538     0   stevel 
    539     0   stevel 		if (flags & DTRACE_A_PERCPU) {
    540     0   stevel 			int max_cpus = agp->dtat_maxcpu;
    541     0   stevel 			caddr_t *percpu = malloc(max_cpus * sizeof (caddr_t));
    542     0   stevel 
    543     0   stevel 			if (percpu == NULL) {
    544     0   stevel 				free(aggdata->dtada_data);
    545     0   stevel 				free(h);
    546     0   stevel 				return (dt_set_errno(dtp, EDT_NOMEM));
    547     0   stevel 			}
    548     0   stevel 
    549     0   stevel 			for (j = 0; j < max_cpus; j++) {
    550     0   stevel 				percpu[j] = malloc(rec->dtrd_size);
    551     0   stevel 
    552     0   stevel 				if (percpu[j] == NULL) {
    553     0   stevel 					while (--j >= 0)
    554     0   stevel 						free(percpu[j]);
    555     0   stevel 
    556     0   stevel 					free(aggdata->dtada_data);
    557     0   stevel 					free(h);
    558     0   stevel 					return (dt_set_errno(dtp, EDT_NOMEM));
    559     0   stevel 				}
    560     0   stevel 
    561     0   stevel 				if (j == cpu) {
    562     0   stevel 					bcopy(&addr[rec->dtrd_offset],
    563     0   stevel 					    percpu[j], rec->dtrd_size);
    564     0   stevel 				} else {
    565     0   stevel 					bzero(percpu[j], rec->dtrd_size);
    566     0   stevel 				}
    567     0   stevel 			}
    568     0   stevel 
    569     0   stevel 			aggdata->dtada_percpu = percpu;
    570     0   stevel 		}
    571     0   stevel 
    572     0   stevel 		switch (rec->dtrd_action) {
    573     0   stevel 		case DTRACEAGG_MIN:
    574     0   stevel 			h->dtahe_aggregate = dt_aggregate_min;
    575     0   stevel 			break;
    576     0   stevel 
    577     0   stevel 		case DTRACEAGG_MAX:
    578     0   stevel 			h->dtahe_aggregate = dt_aggregate_max;
    579     0   stevel 			break;
    580     0   stevel 
    581     0   stevel 		case DTRACEAGG_LQUANTIZE:
    582     0   stevel 			h->dtahe_aggregate = dt_aggregate_lquantize;
    583     0   stevel 			break;
    584     0   stevel 
    585     0   stevel 		case DTRACEAGG_COUNT:
    586     0   stevel 		case DTRACEAGG_SUM:
    587     0   stevel 		case DTRACEAGG_AVG:
    588  5984  jhaslam 		case DTRACEAGG_STDDEV:
    589     0   stevel 		case DTRACEAGG_QUANTIZE:
    590     0   stevel 			h->dtahe_aggregate = dt_aggregate_count;
    591     0   stevel 			break;
    592     0   stevel 
    593     0   stevel 		default:
    594     0   stevel 			return (dt_set_errno(dtp, EDT_BADAGG));
    595     0   stevel 		}
    596     0   stevel 
    597     0   stevel 		if (hash->dtah_hash[ndx] != NULL)
    598     0   stevel 			hash->dtah_hash[ndx]->dtahe_prev = h;
    599     0   stevel 
    600     0   stevel 		h->dtahe_next = hash->dtah_hash[ndx];
    601     0   stevel 		hash->dtah_hash[ndx] = h;
    602     0   stevel 
    603     0   stevel 		if (hash->dtah_all != NULL)
    604     0   stevel 			hash->dtah_all->dtahe_prevall = h;
    605     0   stevel 
    606     0   stevel 		h->dtahe_nextall = hash->dtah_all;
    607     0   stevel 		hash->dtah_all = h;
    608     0   stevel bufnext:
    609     0   stevel 		offs += agg->dtagd_size;
    610     0   stevel 	}
    611     0   stevel 
    612     0   stevel 	return (0);
    613     0   stevel }
    614     0   stevel 
    615     0   stevel int
    616     0   stevel dtrace_aggregate_snap(dtrace_hdl_t *dtp)
    617     0   stevel {
    618     0   stevel 	int i, rval;
    619     0   stevel 	dt_aggregate_t *agp = &dtp->dt_aggregate;
    620     0   stevel 	hrtime_t now = gethrtime();
    621     0   stevel 	dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_AGGRATE];
    622     0   stevel 
    623     0   stevel 	if (dtp->dt_lastagg != 0) {
    624     0   stevel 		if (now - dtp->dt_lastagg < interval)
    625     0   stevel 			return (0);
    626     0   stevel 
    627     0   stevel 		dtp->dt_lastagg += interval;
    628     0   stevel 	} else {
    629     0   stevel 		dtp->dt_lastagg = now;
    630     0   stevel 	}
    631     0   stevel 
    632     0   stevel 	if (!dtp->dt_active)
    633     0   stevel 		return (dt_set_errno(dtp, EINVAL));
    634     0   stevel 
    635     0   stevel 	if (agp->dtat_buf.dtbd_size == 0)
    636     0   stevel 		return (0);
    637     0   stevel 
    638     0   stevel 	for (i = 0; i < agp->dtat_ncpus; i++) {
    639     0   stevel 		if (rval = dt_aggregate_snap_cpu(dtp, agp->dtat_cpus[i]))
    640     0   stevel 			return (rval);
    641     0   stevel 	}
    642     0   stevel 
    643     0   stevel 	return (0);
    644     0   stevel }
    645     0   stevel 
    646     0   stevel static int
    647     0   stevel dt_aggregate_hashcmp(const void *lhs, const void *rhs)
    648     0   stevel {
    649     0   stevel 	dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
    650     0   stevel 	dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
    651     0   stevel 	dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
    652     0   stevel 	dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
    653     0   stevel 
    654     0   stevel 	if (lagg->dtagd_nrecs < ragg->dtagd_nrecs)
    655  1017      bmc 		return (DT_LESSTHAN);
    656     0   stevel 
    657     0   stevel 	if (lagg->dtagd_nrecs > ragg->dtagd_nrecs)
    658  1017      bmc 		return (DT_GREATERTHAN);
    659     0   stevel 
    660     0   stevel 	return (0);
    661     0   stevel }
    662     0   stevel 
    663     0   stevel static int
    664     0   stevel dt_aggregate_varcmp(const void *lhs, const void *rhs)
    665     0   stevel {
    666     0   stevel 	dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
    667     0   stevel 	dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
    668  1017      bmc 	dtrace_aggvarid_t lid, rid;
    669     0   stevel 
    670  1017      bmc 	lid = dt_aggregate_aggvarid(lh);
    671  1017      bmc 	rid = dt_aggregate_aggvarid(rh);
    672     0   stevel 
    673     0   stevel 	if (lid < rid)
    674  1017      bmc 		return (DT_LESSTHAN);
    675     0   stevel 
    676     0   stevel 	if (lid > rid)
    677  1017      bmc 		return (DT_GREATERTHAN);
    678     0   stevel 
    679     0   stevel 	return (0);
    680     0   stevel }
    681     0   stevel 
    682     0   stevel static int
    683     0   stevel dt_aggregate_keycmp(const void *lhs, const void *rhs)
    684     0   stevel {
    685     0   stevel 	dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
    686     0   stevel 	dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
    687     0   stevel 	dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
    688     0   stevel 	dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
    689     0   stevel 	dtrace_recdesc_t *lrec, *rrec;
    690     0   stevel 	char *ldata, *rdata;
    691  1017      bmc 	int rval, i, j, keypos, nrecs;
    692     0   stevel 
    693     0   stevel 	if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0)
    694     0   stevel 		return (rval);
    695     0   stevel 
    696  1017      bmc 	nrecs = lagg->dtagd_nrecs - 1;
    697  1017      bmc 	assert(nrecs == ragg->dtagd_nrecs - 1);
    698  1017      bmc 
    699  1017      bmc 	keypos = dt_keypos + 1 >= nrecs ? 0 : dt_keypos;
    700  1017      bmc 
    701  1017      bmc 	for (i = 1; i < nrecs; i++) {
    702     0   stevel 		uint64_t lval, rval;
    703  1017      bmc 		int ndx = i + keypos;
    704     0   stevel 
    705  1017      bmc 		if (ndx >= nrecs)
    706  1017      bmc 			ndx = ndx - nrecs + 1;
    707  1017      bmc 
    708  1017      bmc 		lrec = &lagg->dtagd_rec[ndx];
    709  1017      bmc 		rrec = &ragg->dtagd_rec[ndx];
    710     0   stevel 
    711     0   stevel 		ldata = lh->dtahe_data.dtada_data + lrec->dtrd_offset;
    712     0   stevel 		rdata = rh->dtahe_data.dtada_data + rrec->dtrd_offset;
    713     0   stevel 
    714     0   stevel 		if (lrec->dtrd_size < rrec->dtrd_size)
    715  1017      bmc 			return (DT_LESSTHAN);
    716     0   stevel 
    717     0   stevel 		if (lrec->dtrd_size > rrec->dtrd_size)
    718  1017      bmc 			return (DT_GREATERTHAN);
    719     0   stevel 
    720     0   stevel 		switch (lrec->dtrd_size) {
    721     0   stevel 		case sizeof (uint64_t):
    722     0   stevel 			/* LINTED - alignment */
    723     0   stevel 			lval = *((uint64_t *)ldata);
    724     0   stevel 			/* LINTED - alignment */
    725     0   stevel 			rval = *((uint64_t *)rdata);
    726     0   stevel 			break;
    727     0   stevel 
    728     0   stevel 		case sizeof (uint32_t):
    729     0   stevel 			/* LINTED - alignment */
    730     0   stevel 			lval = *((uint32_t *)ldata);
    731     0   stevel 			/* LINTED - alignment */
    732     0   stevel 			rval = *((uint32_t *)rdata);
    733     0   stevel 			break;
    734     0   stevel 
    735     0   stevel 		case sizeof (uint16_t):
    736     0   stevel 			/* LINTED - alignment */
    737     0   stevel 			lval = *((uint16_t *)ldata);
    738     0   stevel 			/* LINTED - alignment */
    739     0   stevel 			rval = *((uint16_t *)rdata);
    740     0   stevel 			break;
    741     0   stevel 
    742     0   stevel 		case sizeof (uint8_t):
    743     0   stevel 			lval = *((uint8_t *)ldata);
    744     0   stevel 			rval = *((uint8_t *)rdata);
    745     0   stevel 			break;
    746     0   stevel 
    747     0   stevel 		default:
    748  2777    tomee 			switch (lrec->dtrd_action) {
    749  2777    tomee 			case DTRACEACT_UMOD:
    750  2777    tomee 			case DTRACEACT_UADDR:
    751  2777    tomee 			case DTRACEACT_USYM:
    752  2777    tomee 				for (j = 0; j < 2; j++) {
    753  2777    tomee 					/* LINTED - alignment */
    754  2777    tomee 					lval = ((uint64_t *)ldata)[j];
    755  2777    tomee 					/* LINTED - alignment */
    756  2777    tomee 					rval = ((uint64_t *)rdata)[j];
    757     0   stevel 
    758  2777    tomee 					if (lval < rval)
    759  2777    tomee 						return (DT_LESSTHAN);
    760     0   stevel 
    761  2777    tomee 					if (lval > rval)
    762  2777    tomee 						return (DT_GREATERTHAN);
    763  2777    tomee 				}
    764  1017      bmc 
    765  2777    tomee 				break;
    766  2777    tomee 
    767  2777    tomee 			default:
    768  2777    tomee 				for (j = 0; j < lrec->dtrd_size; j++) {
    769  2777    tomee 					lval = ((uint8_t *)ldata)[j];
    770  2777    tomee 					rval = ((uint8_t *)rdata)[j];
    771  2777    tomee 
    772  2777    tomee 					if (lval < rval)
    773  2777    tomee 						return (DT_LESSTHAN);
    774  2777    tomee 
    775  2777    tomee 					if (lval > rval)
    776  2777    tomee 						return (DT_GREATERTHAN);
    777  2777    tomee 				}
    778     0   stevel 			}
    779     0   stevel 
    780     0   stevel 			continue;
    781     0   stevel 		}
    782     0   stevel 
    783     0   stevel 		if (lval < rval)
    784  1017      bmc 			return (DT_LESSTHAN);
    785     0   stevel 
    786     0   stevel 		if (lval > rval)
    787  1017      bmc 			return (DT_GREATERTHAN);
    788     0   stevel 	}
    789     0   stevel 
    790     0   stevel 	return (0);
    791     0   stevel }
    792     0   stevel 
    793     0   stevel static int
    794     0   stevel dt_aggregate_valcmp(const void *lhs, const void *rhs)
    795     0   stevel {
    796     0   stevel 	dt_ahashent_t *lh = *((dt_ahashent_t **)lhs);
    797     0   stevel 	dt_ahashent_t *rh = *((dt_ahashent_t **)rhs);
    798     0   stevel 	dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc;
    799     0   stevel 	dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc;
    800     0   stevel 	caddr_t ldata = lh->dtahe_data.dtada_data;
    801     0   stevel 	caddr_t rdata = rh->dtahe_data.dtada_data;
    802     0   stevel 	dtrace_recdesc_t *lrec, *rrec;
    803   491      bmc 	int64_t *laddr, *raddr;
    804     0   stevel 	int rval, i;
    805     0   stevel 
    806     0   stevel 	if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0)
    807     0   stevel 		return (rval);
    808     0   stevel 
    809  1017      bmc 	if (lagg->dtagd_nrecs > ragg->dtagd_nrecs)
    810  1017      bmc 		return (DT_GREATERTHAN);
    811  1017      bmc 
    812     0   stevel 	if (lagg->dtagd_nrecs < ragg->dtagd_nrecs)
    813  1017      bmc 		return (DT_LESSTHAN);
    814     0   stevel 
    815     0   stevel 	for (i = 0; i < lagg->dtagd_nrecs; i++) {
    816     0   stevel 		lrec = &lagg->dtagd_rec[i];
    817     0   stevel 		rrec = &ragg->dtagd_rec[i];
    818     0   stevel 
    819     0   stevel 		if (lrec->dtrd_offset < rrec->dtrd_offset)
    820  1017      bmc 			return (DT_LESSTHAN);
    821     0   stevel 
    822     0   stevel 		if (lrec->dtrd_offset > rrec->dtrd_offset)
    823  1017      bmc 			return (DT_GREATERTHAN);
    824     0   stevel 
    825     0   stevel 		if (lrec->dtrd_action < rrec->dtrd_action)
    826  1017      bmc 			return (DT_LESSTHAN);
    827     0   stevel 
    828     0   stevel 		if (lrec->dtrd_action > rrec->dtrd_action)
    829  1017      bmc 			return (DT_GREATERTHAN);
    830     0   stevel 	}
    831     0   stevel 
    832   491      bmc 	laddr = (int64_t *)(uintptr_t)(ldata + lrec->dtrd_offset);
    833   491      bmc 	raddr = (int64_t *)(uintptr_t)(rdata + rrec->dtrd_offset);
    834     0   stevel 
    835     0   stevel 	switch (lrec->dtrd_action) {
    836     0   stevel 	case DTRACEAGG_AVG:
    837     0   stevel 		rval = dt_aggregate_averagecmp(laddr, raddr);
    838  5984  jhaslam 		break;
    839  5984  jhaslam 
    840  5984  jhaslam 	case DTRACEAGG_STDDEV:
    841  5984  jhaslam 		rval = dt_aggregate_stddevcmp(laddr, raddr);
    842     0   stevel 		break;
    843     0   stevel 
    844     0   stevel 	case DTRACEAGG_QUANTIZE:
    845     0   stevel 		rval = dt_aggregate_quantizedcmp(laddr, raddr);
    846     0   stevel 		break;
    847     0   stevel 
    848     0   stevel 	case DTRACEAGG_LQUANTIZE:
    849     0   stevel 		rval = dt_aggregate_lquantizedcmp(laddr, raddr);
    850     0   stevel 		break;
    851     0   stevel 
    852     0   stevel 	case DTRACEAGG_COUNT:
    853     0   stevel 	case DTRACEAGG_SUM:
    854     0   stevel 	case DTRACEAGG_MIN:
    855     0   stevel 	case DTRACEAGG_MAX:
    856     0   stevel 		rval = dt_aggregate_countcmp(laddr, raddr);
    857     0   stevel 		break;
    858     0   stevel 
    859     0   stevel 	default:
    860     0   stevel 		assert(0);
    861     0   stevel 	}
    862     0   stevel 
    863  1017      bmc 	return (rval);
    864  1017      bmc }
    865  1017      bmc 
    866  1017      bmc static int
    867  1017      bmc dt_aggregate_valkeycmp(const void *lhs, const void *rhs)
    868  1017      bmc {
    869  1017      bmc 	int rval;
    870  1017      bmc 
    871  1017      bmc 	if ((rval = dt_aggregate_valcmp(lhs, rhs)) != 0)
    872     0   stevel 		return (rval);
    873     0   stevel 
    874     0   stevel 	/*
    875     0   stevel 	 * If we're here, the values for the two aggregation elements are
    876     0   stevel 	 * equal.  We already know that the key layout is the same for the two
    877     0   stevel 	 * elements; we must now compare the keys themselves as a tie-breaker.
    878     0   stevel 	 */
    879     0   stevel 	return (dt_aggregate_keycmp(lhs, rhs));
    880     0   stevel }
    881     0   stevel 
    882     0   stevel static int
    883     0   stevel dt_aggregate_keyvarcmp(const void *lhs, const void *rhs)
    884     0   stevel {
    885     0   stevel 	int rval;
    886     0   stevel 
    887     0   stevel 	if ((rval = dt_aggregate_keycmp(lhs, rhs)) != 0)
    888     0   stevel 		return (rval);
    889     0   stevel 
    890     0   stevel 	return (dt_aggregate_varcmp(lhs, rhs));
    891     0   stevel }
    892     0   stevel 
    893     0   stevel static int
    894     0   stevel dt_aggregate_varkeycmp(const void *lhs, const void *rhs)
    895     0   stevel {
    896     0   stevel 	int rval;
    897     0   stevel 
    898     0   stevel 	if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0)
    899     0   stevel 		return (rval);
    900     0   stevel 
    901     0   stevel 	return (dt_aggregate_keycmp(lhs, rhs));
    902     0   stevel }
    903     0   stevel 
    904     0   stevel static int
    905     0   stevel dt_aggregate_valvarcmp(const void *lhs, const void *rhs)
    906     0   stevel {
    907     0   stevel 	int rval;
    908     0   stevel 
    909  1017      bmc 	if ((rval = dt_aggregate_valkeycmp(lhs, rhs)) != 0)
    910     0   stevel 		return (rval);
    911     0   stevel 
    912     0   stevel 	return (dt_aggregate_varcmp(lhs, rhs));
    913     0   stevel }
    914     0   stevel 
    915     0   stevel static int
    916     0   stevel dt_aggregate_varvalcmp(const void *lhs, const void *rhs)
    917     0   stevel {
    918     0   stevel 	int rval;
    919     0   stevel 
    920     0   stevel 	if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0)
    921     0   stevel 		return (rval);
    922     0   stevel 
    923  1017      bmc 	return (dt_aggregate_valkeycmp(lhs, rhs));
    924     0   stevel }
    925     0   stevel 
    926     0   stevel static int
    927     0   stevel dt_aggregate_keyvarrevcmp(const void *lhs, const void *rhs)
    928     0   stevel {
    929     0   stevel 	return (dt_aggregate_keyvarcmp(rhs, lhs));
    930     0   stevel }
    931     0   stevel 
    932     0   stevel static int
    933     0   stevel dt_aggregate_varkeyrevcmp(const void *lhs, const void *rhs)
    934     0   stevel {
    935     0   stevel 	return (dt_aggregate_varkeycmp(rhs, lhs));
    936     0   stevel }
    937     0   stevel 
    938     0   stevel static int
    939     0   stevel dt_aggregate_valvarrevcmp(const void *lhs, const void *rhs)
    940     0   stevel {
    941     0   stevel 	return (dt_aggregate_valvarcmp(rhs, lhs));
    942     0   stevel }
    943     0   stevel 
    944     0   stevel static int
    945     0   stevel dt_aggregate_varvalrevcmp(const void *lhs, const void *rhs)
    946     0   stevel {
    947     0   stevel 	return (dt_aggregate_varvalcmp(rhs, lhs));
    948  1017      bmc }
    949  1017      bmc 
    950  1017      bmc static int
    951  1017      bmc dt_aggregate_bundlecmp(const void *lhs, const void *rhs)
    952  1017      bmc {
    953  1017      bmc 	dt_ahashent_t **lh = *((dt_ahashent_t ***)lhs);
    954  1017      bmc 	dt_ahashent_t **rh = *((dt_ahashent_t ***)rhs);
    955  1017      bmc 	int i, rval;
    956  1017      bmc 
    957  1017      bmc 	if (dt_keysort) {
    958  1017      bmc 		/*
    959  1017      bmc 		 * If we're sorting on keys, we need to scan until we find the
    960  1017      bmc 		 * last entry -- that's the representative key.  (The order of
    961  1017      bmc 		 * the bundle is values followed by key to accommodate the
    962  1017      bmc 		 * default behavior of sorting by value.)  If the keys are
    963  1017      bmc 		 * equal, we'll fall into the value comparison loop, below.
    964  1017      bmc 		 */
    965  1017      bmc 		for (i = 0; lh[i + 1] != NULL; i++)
    966  1017      bmc 			continue;
    967  1017      bmc 
    968  1017      bmc 		assert(i != 0);
    969  1017      bmc 		assert(rh[i + 1] == NULL);
    970  1017      bmc 
    971  1017      bmc 		if ((rval = dt_aggregate_keycmp(&lh[i], &rh[i])) != 0)
    972  1017      bmc 			return (rval);
    973  1017      bmc 	}
    974  1017      bmc 
    975  1017      bmc 	for (i = 0; ; i++) {
    976  1017      bmc 		if (lh[i + 1] == NULL) {
    977  1017      bmc 			/*
    978  1017      bmc 			 * All of the values are equal; if we're sorting on
    979  1017      bmc 			 * keys, then we're only here because the keys were
    980  1017      bmc 			 * found to be equal and these records are therefore
    981  1017      bmc 			 * equal.  If we're not sorting on keys, we'll use the
    982  1017      bmc 			 * key comparison from the representative key as the
    983  1017      bmc 			 * tie-breaker.
    984  1017      bmc 			 */
    985  1017      bmc 			if (dt_keysort)
    986  1017      bmc 				return (0);
    987  1017      bmc 
    988  1017      bmc 			assert(i != 0);
    989  1017      bmc 			assert(rh[i + 1] == NULL);
    990  1017      bmc 			return (dt_aggregate_keycmp(&lh[i], &rh[i]));
    991  1017      bmc 		} else {
    992  1017      bmc 			if ((rval = dt_aggregate_valcmp(&lh[i], &rh[i])) != 0)
    993  1017      bmc 				return (rval);
    994  1017      bmc 		}
    995  1017      bmc 	}
    996     0   stevel }
    997     0   stevel 
    998     0   stevel int
    999     0   stevel dt_aggregate_go(dtrace_hdl_t *dtp)
   1000     0   stevel {
   1001     0   stevel 	dt_aggregate_t *agp = &dtp->dt_aggregate;
   1002     0   stevel 	dtrace_optval_t size, cpu;
   1003     0   stevel 	dtrace_bufdesc_t *buf = &agp->dtat_buf;
   1004     0   stevel 	int rval, i;
   1005     0   stevel 
   1006     0   stevel 	assert(agp->dtat_maxcpu == 0);
   1007     0   stevel 	assert(agp->dtat_ncpu == 0);
   1008     0   stevel 	assert(agp->dtat_cpus == NULL);
   1009     0   stevel 
   1010     0   stevel 	agp->dtat_maxcpu = dt_sysconf(dtp, _SC_CPUID_MAX) + 1;
   1011     0   stevel 	agp->dtat_ncpu = dt_sysconf(dtp, _SC_NPROCESSORS_MAX);
   1012     0   stevel 	agp->dtat_cpus = malloc(agp->dtat_ncpu * sizeof (processorid_t));
   1013     0   stevel 
   1014     0   stevel 	if (agp->dtat_cpus == NULL)
   1015     0   stevel 		return (dt_set_errno(dtp, EDT_NOMEM));
   1016     0   stevel 
   1017     0   stevel 	/*
   1018     0   stevel 	 * Use the aggregation buffer size as reloaded from the kernel.
   1019     0   stevel 	 */
   1020     0   stevel 	size = dtp->dt_options[DTRACEOPT_AGGSIZE];
   1021     0   stevel 
   1022     0   stevel 	rval = dtrace_getopt(dtp, "aggsize", &size);
   1023     0   stevel 	assert(rval == 0);
   1024     0   stevel 
   1025     0   stevel 	if (size == 0 || size == DTRACEOPT_UNSET)
   1026     0   stevel 		return (0);
   1027     0   stevel 
   1028     0   stevel 	buf = &agp->dtat_buf;
   1029     0   stevel 	buf->dtbd_size = size;
   1030     0   stevel 
   1031     0   stevel 	if ((buf->dtbd_data = malloc(buf->dtbd_size)) == NULL)
   1032     0   stevel 		return (dt_set_errno(dtp, EDT_NOMEM));
   1033     0   stevel 
   1034     0   stevel 	/*
   1035     0   stevel 	 * Now query for the CPUs enabled.
   1036     0   stevel 	 */
   1037     0   stevel 	rval = dtrace_getopt(dtp, "cpu", &cpu);
   1038     0   stevel 	assert(rval == 0 && cpu != DTRACEOPT_UNSET);
   1039     0   stevel 
   1040     0   stevel 	if (cpu != DTRACE_CPUALL) {
   1041     0   stevel 		assert(cpu < agp->dtat_ncpu);
   1042     0   stevel 		agp->dtat_cpus[agp->dtat_ncpus++] = (processorid_t)cpu;
   1043     0   stevel 
   1044     0   stevel 		return (0);
   1045     0   stevel 	}
   1046     0   stevel 
   1047     0   stevel 	agp->dtat_ncpus = 0;
   1048     0   stevel 	for (i = 0; i < agp->dtat_maxcpu; i++) {
   1049     0   stevel 		if (dt_status(dtp, i) == -1)
   1050     0   stevel 			continue;
   1051     0   stevel 
   1052     0   stevel 		agp->dtat_cpus[agp->dtat_ncpus++] = i;
   1053     0   stevel 	}
   1054     0   stevel 
   1055     0   stevel 	return (0);
   1056     0   stevel }
   1057     0   stevel 
   1058     0   stevel static int
   1059     0   stevel dt_aggwalk_rval(dtrace_hdl_t *dtp, dt_ahashent_t *h, int rval)
   1060     0   stevel {
   1061     0   stevel 	dt_aggregate_t *agp = &dtp->dt_aggregate;
   1062     0   stevel 	dtrace_aggdata_t *data;
   1063     0   stevel 	dtrace_aggdesc_t *aggdesc;
   1064     0   stevel 	dtrace_recdesc_t *rec;
   1065     0   stevel 	int i;
   1066     0   stevel 
   1067     0   stevel 	switch (rval) {
   1068     0   stevel 	case DTRACE_AGGWALK_NEXT:
   1069     0   stevel 		break;
   1070     0   stevel 
   1071     0   stevel 	case DTRACE_AGGWALK_CLEAR: {
   1072     0   stevel 		uint32_t size, offs = 0;
   1073     0   stevel 
   1074     0   stevel 		aggdesc = h->dtahe_data.dtada_desc;
   1075     0   stevel 		rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
   1076     0   stevel 		size = rec->dtrd_size;
   1077     0   stevel 		data = &h->dtahe_data;
   1078     0   stevel 
   1079     0   stevel 		if (rec->dtrd_action == DTRACEAGG_LQUANTIZE) {
   1080     0   stevel 			offs = sizeof (uint64_t);
   1081     0   stevel 			size -= sizeof (uint64_t);
   1082     0   stevel 		}
   1083     0   stevel 
   1084     0   stevel 		bzero(&data->dtada_data[rec->dtrd_offset] + offs, size);
   1085     0   stevel 
   1086     0   stevel 		if (data->dtada_percpu == NULL)
   1087     0   stevel 			break;
   1088     0   stevel 
   1089     0   stevel 		for (i = 0; i < dtp->dt_aggregate.dtat_maxcpu; i++)
   1090     0   stevel 			bzero(data->dtada_percpu[i] + offs, size);
   1091     0   stevel 		break;
   1092     0   stevel 	}
   1093     0   stevel 
   1094     0   stevel 	case DTRACE_AGGWALK_ERROR:
   1095     0   stevel 		/*
   1096     0   stevel 		 * We assume that errno is already set in this case.
   1097     0   stevel 		 */
   1098     0   stevel 		return (dt_set_errno(dtp, errno));
   1099     0   stevel 
   1100     0   stevel 	case DTRACE_AGGWALK_ABORT:
   1101     0   stevel 		return (dt_set_errno(dtp, EDT_DIRABORT));
   1102     0   stevel 
   1103     0   stevel 	case DTRACE_AGGWALK_DENORMALIZE:
   1104     0   stevel 		h->dtahe_data.dtada_normal = 1;
   1105     0   stevel 		return (0);
   1106     0   stevel 
   1107     0   stevel 	case DTRACE_AGGWALK_NORMALIZE:
   1108     0   stevel 		if (h->dtahe_data.dtada_normal == 0) {
   1109     0   stevel 			h->dtahe_data.dtada_normal = 1;
   1110     0   stevel 			return (dt_set_errno(dtp, EDT_BADRVAL));
   1111     0   stevel 		}
   1112     0   stevel 
   1113     0   stevel 		return (0);
   1114     0   stevel 
   1115     0   stevel 	case DTRACE_AGGWALK_REMOVE: {
   1116     0   stevel 		dtrace_aggdata_t *aggdata = &h->dtahe_data;
   1117     0   stevel 		int i, max_cpus = agp->dtat_maxcpu;
   1118     0   stevel 
   1119     0   stevel 		/*
   1120     0   stevel 		 * First, remove this hash entry from its hash chain.
   1121     0   stevel 		 */
   1122     0   stevel 		if (h->dtahe_prev != NULL) {
   1123     0   stevel 			h->dtahe_prev->dtahe_next = h->dtahe_next;
   1124     0   stevel 		} else {
   1125     0   stevel 			dt_ahash_t *hash = &agp->dtat_hash;
   1126     0   stevel 			size_t ndx = h->dtahe_hashval % hash->dtah_size;
   1127     0   stevel 
   1128     0   stevel 			assert(hash->dtah_hash[ndx] == h);
   1129     0   stevel 			hash->dtah_hash[ndx] = h->dtahe_next;
   1130     0   stevel 		}
   1131     0   stevel 
   1132     0   stevel 		if (h->dtahe_next != NULL)
   1133     0   stevel 			h->dtahe_next->dtahe_prev = h->dtahe_prev;
   1134     0   stevel 
   1135     0   stevel 		/*
   1136     0   stevel 		 * Now remove it from the list of all hash entries.
   1137     0   stevel 		 */
   1138     0   stevel 		if (h->dtahe_prevall != NULL) {
   1139     0   stevel 			h->dtahe_prevall->dtahe_nextall = h->dtahe_nextall;
   1140     0   stevel 		} else {
   1141     0   stevel 			dt_ahash_t *hash = &agp->dtat_hash;
   1142     0   stevel 
   1143     0   stevel 			assert(hash->dtah_all == h);
   1144     0   stevel 			hash->dtah_all = h->dtahe_nextall;
   1145     0   stevel 		}
   1146     0   stevel 
   1147     0   stevel 		if (h->dtahe_nextall != NULL)
   1148     0   stevel 			h->dtahe_nextall->dtahe_prevall = h->dtahe_prevall;
   1149     0   stevel 
   1150     0   stevel 		/*
   1151     0   stevel 		 * We're unlinked.  We can safely destroy the data.
   1152     0   stevel 		 */
   1153     0   stevel 		if (aggdata->dtada_percpu != NULL) {
   1154     0   stevel 			for (i = 0; i < max_cpus; i++)
   1155     0   stevel 				free(aggdata->dtada_percpu[i]);
   1156     0   stevel 			free(aggdata->dtada_percpu);
   1157     0   stevel 		}
   1158     0   stevel 
   1159     0   stevel 		free(aggdata->dtada_data);
   1160     0   stevel 		free(h);
   1161     0   stevel 
   1162     0   stevel 		return (0);
   1163     0   stevel 	}
   1164     0   stevel 
   1165     0   stevel 	default:
   1166     0   stevel 		return (dt_set_errno(dtp, EDT_BADRVAL));
   1167     0   stevel 	}
   1168     0   stevel 
   1169     0   stevel 	return (0);
   1170     0   stevel }
   1171     0   stevel 
   1172  1017      bmc void
   1173  1017      bmc dt_aggregate_qsort(dtrace_hdl_t *dtp, void *base, size_t nel, size_t width,
   1174  1017      bmc     int (*compar)(const void *, const void *))
   1175  1017      bmc {
   1176  1017      bmc 	int rev = dt_revsort, key = dt_keysort, keypos = dt_keypos;
   1177  1017      bmc 	dtrace_optval_t keyposopt = dtp->dt_options[DTRACEOPT_AGGSORTKEYPOS];
   1178  1017      bmc 
   1179  1017      bmc 	dt_revsort = (dtp->dt_options[DTRACEOPT_AGGSORTREV] != DTRACEOPT_UNSET);
   1180  1017      bmc 	dt_keysort = (dtp->dt_options[DTRACEOPT_AGGSORTKEY] != DTRACEOPT_UNSET);
   1181  1017      bmc 
   1182  1017      bmc 	if (keyposopt != DTRACEOPT_UNSET && keyposopt <= INT_MAX) {
   1183  1017      bmc 		dt_keypos = (int)keyposopt;
   1184  1017      bmc 	} else {
   1185  1017      bmc 		dt_keypos = 0;
   1186  1017      bmc 	}
   1187  1017      bmc 
   1188  1017      bmc 	if (compar == NULL) {
   1189  1017      bmc 		if (!dt_keysort) {
   1190  1017      bmc 			compar = dt_aggregate_varvalcmp;
   1191  1017      bmc 		} else {
   1192  1017      bmc 			compar = dt_aggregate_varkeycmp;
   1193  1017      bmc 		}
   1194  1017      bmc 	}
   1195  1017      bmc 
   1196  1017      bmc 	qsort(base, nel, width, compar);
   1197  1017      bmc 
   1198  1017      bmc 	dt_revsort = rev;
   1199  1017      bmc 	dt_keysort = key;
   1200  1017      bmc 	dt_keypos = keypos;
   1201  1017      bmc }
   1202  1017      bmc 
   1203     0   stevel int
   1204     0   stevel dtrace_aggregate_walk(dtrace_hdl_t *dtp, dtrace_aggregate_f *func, void *arg)
   1205     0   stevel {
   1206     0   stevel 	dt_ahashent_t *h, *next;
   1207     0   stevel 	dt_ahash_t *hash = &dtp->dt_aggregate.dtat_hash;
   1208     0   stevel 
   1209     0   stevel 	for (h = hash->dtah_all; h != NULL; h = next) {
   1210     0   stevel 		/*
   1211     0   stevel 		 * dt_aggwalk_rval() can potentially remove the current hash
   1212     0   stevel 		 * entry; we need to load the next hash entry before calling
   1213     0   stevel 		 * into it.
   1214     0   stevel 		 */
   1215     0   stevel 		next = h->dtahe_nextall;
   1216     0   stevel 
   1217     0   stevel 		if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1)
   1218     0   stevel 			return (-1);
   1219     0   stevel 	}
   1220     0   stevel 
   1221     0   stevel 	return (0);
   1222     0   stevel }
   1223     0   stevel 
   1224     0   stevel static int
   1225     0   stevel dt_aggregate_walk_sorted(dtrace_hdl_t *dtp,
   1226     0   stevel     dtrace_aggregate_f *func, void *arg,
   1227     0   stevel     int (*sfunc)(const void *, const void *))
   1228     0   stevel {
   1229     0   stevel 	dt_aggregate_t *agp = &dtp->dt_aggregate;
   1230     0   stevel 	dt_ahashent_t *h, **sorted;
   1231     0   stevel 	dt_ahash_t *hash = &agp->dtat_hash;
   1232     0   stevel 	size_t i, nentries = 0;
   1233     0   stevel 
   1234     0   stevel 	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall)
   1235     0   stevel 		nentries++;
   1236     0   stevel 
   1237  1017      bmc 	sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *));
   1238     0   stevel 
   1239     0   stevel 	if (sorted == NULL)
   1240  1017      bmc 		return (-1);
   1241     0   stevel 
   1242     0   stevel 	for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall)
   1243     0   stevel 		sorted[i++] = h;
   1244     0   stevel 
   1245  1017      bmc 	(void) pthread_mutex_lock(&dt_qsort_lock);
   1246  1017      bmc 
   1247  1017      bmc 	if (sfunc == NULL) {
   1248  1017      bmc 		dt_aggregate_qsort(dtp, sorted, nentries,
   1249  1017      bmc 		    sizeof (dt_ahashent_t *), NULL);
   1250  1017      bmc 	} else {
   1251  1017      bmc 		/*
   1252  1017      bmc 		 * If we've been explicitly passed a sorting function,
   1253  1017      bmc 		 * we'll use that -- ignoring the values of the "aggsortrev",
   1254  1017      bmc 		 * "aggsortkey" and "aggsortkeypos" options.
   1255  1017      bmc 		 */
   1256  1017      bmc 		qsort(sorted, nentries, sizeof (dt_ahashent_t *), sfunc);
   1257  1017      bmc 	}
   1258  1017      bmc 
   1259  1017      bmc 	(void) pthread_mutex_unlock(&dt_qsort_lock);
   1260     0   stevel 
   1261     0   stevel 	for (i = 0; i < nentries; i++) {
   1262     0   stevel 		h = sorted[i];
   1263     0   stevel 
   1264  1017      bmc 		if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) {
   1265  1017      bmc 			dt_free(dtp, sorted);
   1266     0   stevel 			return (-1);
   1267  1017      bmc 		}
   1268     0   stevel 	}
   1269     0   stevel 
   1270  1017      bmc 	dt_free(dtp, sorted);
   1271     0   stevel 	return (0);
   1272  1017      bmc }
   1273  1017      bmc 
   1274  1017      bmc int
   1275  1017      bmc dtrace_aggregate_walk_sorted(dtrace_hdl_t *dtp,
   1276  1017      bmc     dtrace_aggregate_f *func, void *arg)
   1277  1017      bmc {
   1278  1017      bmc 	return (dt_aggregate_walk_sorted(dtp, func, arg, NULL));
   1279     0   stevel }
   1280     0   stevel 
   1281     0   stevel int
   1282     0   stevel dtrace_aggregate_walk_keysorted(dtrace_hdl_t *dtp,
   1283     0   stevel     dtrace_aggregate_f *func, void *arg)
   1284     0   stevel {
   1285     0   stevel 	return (dt_aggregate_walk_sorted(dtp, func,
   1286     0   stevel 	    arg, dt_aggregate_varkeycmp));
   1287     0   stevel }
   1288     0   stevel 
   1289     0   stevel int
   1290     0   stevel dtrace_aggregate_walk_valsorted(dtrace_hdl_t *dtp,
   1291     0   stevel     dtrace_aggregate_f *func, void *arg)
   1292     0   stevel {
   1293     0   stevel 	return (dt_aggregate_walk_sorted(dtp, func,
   1294     0   stevel 	    arg, dt_aggregate_varvalcmp));
   1295     0   stevel }
   1296     0   stevel 
   1297     0   stevel int
   1298     0   stevel dtrace_aggregate_walk_keyvarsorted(dtrace_hdl_t *dtp,
   1299     0   stevel     dtrace_aggregate_f *func, void *arg)
   1300     0   stevel {
   1301     0   stevel 	return (dt_aggregate_walk_sorted(dtp, func,
   1302     0   stevel 	    arg, dt_aggregate_keyvarcmp));
   1303     0   stevel }
   1304     0   stevel 
   1305     0   stevel int
   1306     0   stevel dtrace_aggregate_walk_valvarsorted(dtrace_hdl_t *dtp,
   1307     0   stevel     dtrace_aggregate_f *func, void *arg)
   1308     0   stevel {
   1309     0   stevel 	return (dt_aggregate_walk_sorted(dtp, func,
   1310     0   stevel 	    arg, dt_aggregate_valvarcmp));
   1311     0   stevel }
   1312     0   stevel 
   1313     0   stevel int
   1314     0   stevel dtrace_aggregate_walk_keyrevsorted(dtrace_hdl_t *dtp,
   1315     0   stevel     dtrace_aggregate_f *func, void *arg)
   1316     0   stevel {
   1317     0   stevel 	return (dt_aggregate_walk_sorted(dtp, func,
   1318     0   stevel 	    arg, dt_aggregate_varkeyrevcmp));
   1319     0   stevel }
   1320     0   stevel 
   1321     0   stevel int
   1322     0   stevel dtrace_aggregate_walk_valrevsorted(dtrace_hdl_t *dtp,
   1323     0   stevel     dtrace_aggregate_f *func, void *arg)
   1324     0   stevel {
   1325     0   stevel 	return (dt_aggregate_walk_sorted(dtp, func,
   1326     0   stevel 	    arg, dt_aggregate_varvalrevcmp));
   1327     0   stevel }
   1328     0   stevel 
   1329     0   stevel int
   1330     0   stevel dtrace_aggregate_walk_keyvarrevsorted(dtrace_hdl_t *dtp,
   1331     0   stevel     dtrace_aggregate_f *func, void *arg)
   1332     0   stevel {
   1333     0   stevel 	return (dt_aggregate_walk_sorted(dtp, func,
   1334     0   stevel 	    arg, dt_aggregate_keyvarrevcmp));
   1335     0   stevel }
   1336     0   stevel 
   1337     0   stevel int
   1338     0   stevel dtrace_aggregate_walk_valvarrevsorted(dtrace_hdl_t *dtp,
   1339     0   stevel     dtrace_aggregate_f *func, void *arg)
   1340     0   stevel {
   1341     0   stevel 	return (dt_aggregate_walk_sorted(dtp, func,
   1342     0   stevel 	    arg, dt_aggregate_valvarrevcmp));
   1343     0   stevel }
   1344     0   stevel 
   1345     0   stevel int
   1346  1017      bmc dtrace_aggregate_walk_joined(dtrace_hdl_t *dtp, dtrace_aggvarid_t *aggvars,
   1347  1017      bmc     int naggvars, dtrace_aggregate_walk_joined_f *func, void *arg)
   1348  1017      bmc {
   1349  1017      bmc 	dt_aggregate_t *agp = &dtp->dt_aggregate;
   1350  1017      bmc 	dt_ahashent_t *h, **sorted = NULL, ***bundle, **nbundle;
   1351  1017      bmc 	const dtrace_aggdata_t **data;
   1352  1017      bmc 	dt_ahashent_t *zaggdata = NULL;
   1353  1017      bmc 	dt_ahash_t *hash = &agp->dtat_hash;
   1354  1017      bmc 	size_t nentries = 0, nbundles = 0, start, zsize = 0, bundlesize;
   1355  1017      bmc 	dtrace_aggvarid_t max = 0, aggvar;
   1356  1017      bmc 	int rval = -1, *map, *remap = NULL;
   1357  1017      bmc 	int i, j;
   1358  1017      bmc 	dtrace_optval_t sortpos = dtp->dt_options[DTRACEOPT_AGGSORTPOS];
   1359  1017      bmc 
   1360  1017      bmc 	/*
   1361  1017      bmc 	 * If the sorting position is greater than the number of aggregation
   1362  1017      bmc 	 * variable IDs, we silently set it to 0.
   1363  1017      bmc 	 */
   1364  1017      bmc 	if (sortpos == DTRACEOPT_UNSET || sortpos >= naggvars)
   1365  1017      bmc 		sortpos = 0;
   1366  1017      bmc 
   1367  1017      bmc 	/*
   1368  1017      bmc 	 * First we need to translate the specified aggregation variable IDs
   1369  1017      bmc 	 * into a linear map that will allow us to translate an aggregation
   1370  1017      bmc 	 * variable ID into its position in the specified aggvars.
   1371  1017      bmc 	 */
   1372  1017      bmc 	for (i = 0; i < naggvars; i++) {
   1373  1017      bmc 		if (aggvars[i] == DTRACE_AGGVARIDNONE || aggvars[i] < 0)
   1374  1017      bmc 			return (dt_set_errno(dtp, EDT_BADAGGVAR));
   1375  1017      bmc 
   1376  1017      bmc 		if (aggvars[i] > max)
   1377  1017      bmc 			max = aggvars[i];
   1378  1017      bmc 	}
   1379  1017      bmc 
   1380  1017      bmc 	if ((map = dt_zalloc(dtp, (max + 1) * sizeof (int))) == NULL)
   1381  1017      bmc 		return (-1);
   1382  1017      bmc 
   1383  1017      bmc 	zaggdata = dt_zalloc(dtp, naggvars * sizeof (dt_ahashent_t));
   1384  1017      bmc 
   1385  1017      bmc 	if (zaggdata == NULL)
   1386  1017      bmc 		goto out;
   1387  1017      bmc 
   1388  1017      bmc 	for (i = 0; i < naggvars; i++) {
   1389  1017      bmc 		int ndx = i + sortpos;
   1390  1017      bmc 
   1391  1017      bmc 		if (ndx >= naggvars)
   1392  1017      bmc 			ndx -= naggvars;
   1393  1017      bmc 
   1394  1017      bmc 		aggvar = aggvars[ndx];
   1395  1017      bmc 		assert(aggvar <= max);
   1396  1017      bmc 
   1397  1017      bmc 		if (map[aggvar]) {
   1398  1017      bmc 			/*
   1399  1017      bmc 			 * We have an aggregation variable that is present
   1400  1017      bmc 			 * more than once in the array of aggregation
   1401  1017      bmc 			 * variables.  While it's unclear why one might want
   1402  1017      bmc 			 * to do this, it's legal.  To support this construct,
   1403  1017      bmc 			 * we will allocate a remap that will indicate the
   1404  1017      bmc 			 * position from which this aggregation variable
   1405  1017      bmc 			 * should be pulled.  (That is, where the remap will
   1406  1017      bmc 			 * map from one position to another.)
   1407  1017      bmc 			 */
   1408  1017      bmc 			if (remap == NULL) {
   1409  1017      bmc 				remap = dt_zalloc(dtp, naggvars * sizeof (int));
   1410  1017      bmc 
   1411  1017      bmc 				if (remap == NULL)
   1412  1017      bmc 					goto out;
   1413  1017      bmc 			}
   1414  1017      bmc 
   1415  1017      bmc 			/*
   1416  1017      bmc 			 * Given that the variable is already present, assert
   1417  1017      bmc 			 * that following through the mapping and adjusting
   1418  1017      bmc 			 * for the sort position yields the same aggregation
   1419  1017      bmc 			 * variable ID.
   1420  1017      bmc 			 */
   1421  1017      bmc 			assert(aggvars[(map[aggvar] - 1 + sortpos) %
   1422  1017      bmc 			    naggvars] == aggvars[ndx]);
   1423  1017      bmc 
   1424  1017      bmc 			remap[i] = map[aggvar];
   1425  1017      bmc 			continue;
   1426  1017      bmc 		}
   1427  1017      bmc 
   1428  1017      bmc 		map[aggvar] = i + 1;
   1429  1017      bmc 	}
   1430  1017      bmc 
   1431  1017      bmc 	/*
   1432  1017      bmc 	 * We need to take two passes over the data to size our allocation, so
   1433  1017      bmc 	 * we'll use the first pass to also fill in the zero-filled data to be
   1434  1017      bmc 	 * used to properly format a zero-valued aggregation.
   1435  1017      bmc 	 */
   1436  1017      bmc 	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
   1437  1017      bmc 		dtrace_aggvarid_t id;
   1438  1017      bmc 		int ndx;
   1439  1017      bmc 
   1440  1017      bmc 		if ((id = dt_aggregate_aggvarid(h)) > max || !(ndx = map[id]))
   1441  1017      bmc 			continue;
   1442  1017      bmc 
   1443  1017      bmc 		if (zaggdata[ndx - 1].dtahe_size == 0) {
   1444  1017      bmc 			zaggdata[ndx - 1].dtahe_size = h->dtahe_size;
   1445  1017      bmc 			zaggdata[ndx - 1].dtahe_data = h->dtahe_data;
   1446  1017      bmc 		}
   1447  1017      bmc 
   1448  1017      bmc 		nentries++;
   1449  1017      bmc 	}
   1450  1017      bmc 
   1451  1017      bmc 	if (nentries == 0) {
   1452  1017      bmc 		/*
   1453  1017      bmc 		 * We couldn't find any entries; there is nothing else to do.
   1454  1017      bmc 		 */
   1455  1017      bmc 		rval = 0;
   1456  1017      bmc 		goto out;
   1457  1017      bmc 	}
   1458  1017      bmc 
   1459  1017      bmc 	/*
   1460  1017      bmc 	 * Before we sort the data, we're going to look for any holes in our
   1461  1017      bmc 	 * zero-filled data.  This will occur if an aggregation variable that
   1462  1017      bmc 	 * we are being asked to print has not yet been assigned the result of
   1463  1017      bmc 	 * any aggregating action for _any_ tuple.  The issue becomes that we
   1464  1017      bmc 	 * would like a zero value to be printed for all columns for this
   1465  1017      bmc 	 * aggregation, but without any record description, we don't know the
   1466  1017      bmc 	 * aggregating action that corresponds to the aggregation variable.  To
   1467  1017      bmc 	 * try to find a match, we're simply going to lookup aggregation IDs
   1468  1017      bmc 	 * (which are guaranteed to be contiguous and to start from 1), looking
   1469  1017      bmc 	 * for the specified aggregation variable ID.  If we find a match,
   1470  1017      bmc 	 * we'll use that.  If we iterate over all aggregation IDs and don't
   1471  1017      bmc 	 * find a match, then we must be an anonymous enabling.  (Anonymous
   1472  1017      bmc 	 * enablings can't currently derive either aggregation variable IDs or
   1473  1017      bmc 	 * aggregation variable names given only an aggregation ID.)  In this
   1474  1017      bmc 	 * obscure case (anonymous enabling, multiple aggregation printa() with
   1475  1017      bmc 	 * some aggregations not represented for any tuple), our defined
   1476  1017      bmc 	 * behavior is that the zero will be printed in the format of the first
   1477  1017      bmc 	 * aggregation variable that contains any non-zero value.
   1478  1017      bmc 	 */
   1479  1017      bmc 	for (i = 0; i < naggvars; i++) {
   1480  1017      bmc 		if (zaggdata[i].dtahe_size == 0) {
   1481  1017      bmc 			dtrace_aggvarid_t aggvar;
   1482  1017      bmc 
   1483  1017      bmc 			aggvar = aggvars[(i - sortpos + naggvars) % naggvars];
   1484  1017      bmc 			assert(zaggdata[i].dtahe_data.dtada_data == NULL);
   1485  1017      bmc 
   1486  1017      bmc 			for (j = DTRACE_AGGIDNONE + 1; ; j++) {
   1487  1017      bmc 				dtrace_aggdesc_t *agg;
   1488  1017      bmc 				dtrace_aggdata_t *aggdata;
   1489  1017      bmc 
   1490  1017      bmc 				if (dt_aggid_lookup(dtp, j, &agg) != 0)
   1491  1017      bmc 					break;
   1492  1017      bmc 
   1493  1017      bmc 				if (agg->dtagd_varid != aggvar)
   1494  1017      bmc 					continue;
   1495  1017      bmc 
   1496  1017      bmc 				/*
   1497  1017      bmc 				 * We have our description -- now we need to
   1498  1017      bmc 				 * cons up the zaggdata entry for it.
   1499  1017      bmc 				 */
   1500  1017      bmc 				aggdata = &zaggdata[i].dtahe_data;
   1501  1017      bmc 				aggdata->dtada_size = agg->dtagd_size;
   1502  1017      bmc 				aggdata->dtada_desc = agg;
   1503  1017      bmc 				aggdata->dtada_handle = dtp;
   1504  1017      bmc 				(void) dt_epid_lookup(dtp, agg->dtagd_epid,
   1505  1017      bmc 				    &aggdata->dtada_edesc,
   1506  1017      bmc 				    &aggdata->dtada_pdesc);
   1507  1017      bmc 				aggdata->dtada_normal = 1;
   1508  1017      bmc 				zaggdata[i].dtahe_hashval = 0;
   1509  1017      bmc 				zaggdata[i].dtahe_size = agg->dtagd_size;
   1510  1017      bmc 				break;
   1511  1017      bmc 			}
   1512  1017      bmc 
   1513  1017      bmc 			if (zaggdata[i].dtahe_size == 0) {
   1514  1017      bmc 				caddr_t data;
   1515  1017      bmc 
   1516  1017      bmc 				/*
   1517  1017      bmc 				 * We couldn't find this aggregation, meaning
   1518  1017      bmc 				 * that we have never seen it before for any
   1519  1017      bmc 				 * tuple _and_ this is an anonymous enabling.
   1520  1017      bmc 				 * That is, we're in the obscure case outlined
   1521  1017      bmc 				 * above.  In this case, our defined behavior
   1522  1017      bmc 				 * is to format the data in the format of the
   1523  1017      bmc 				 * first non-zero aggregation -- of which, of
   1524  1017      bmc 				 * course, we know there to be at least one
   1525  1017      bmc 				 * (or nentries would have been zero).
   1526  1017      bmc 				 */
   1527  1017      bmc 				for (j = 0; j < naggvars; j++) {
   1528  1017      bmc 					if (zaggdata[j].dtahe_size != 0)
   1529  1017      bmc 						break;
   1530  1017      bmc 				}
   1531  1017      bmc 
   1532  1017      bmc 				assert(j < naggvars);
   1533  1017      bmc 				zaggdata[i] = zaggdata[j];
   1534  1017      bmc 
   1535  1017      bmc 				data = zaggdata[i].dtahe_data.dtada_data;
   1536  1017      bmc 				assert(data != NULL);
   1537  1017      bmc 			}
   1538  1017      bmc 		}
   1539  1017      bmc 	}
   1540  1017      bmc 
   1541  1017      bmc 	/*
   1542  1017      bmc 	 * Now we need to allocate our zero-filled data for use for
   1543  1017      bmc 	 * aggregations that don't have a value corresponding to a given key.
   1544  1017      bmc 	 */
   1545  1017      bmc 	for (i = 0; i < naggvars; i++) {
   1546  1017      bmc 		dtrace_aggdata_t *aggdata = &zaggdata[i].dtahe_data;
   1547  1017      bmc 		dtrace_aggdesc_t *aggdesc = aggdata->dtada_desc;
   1548  1017      bmc 		dtrace_recdesc_t *rec;
   1549  1017      bmc 		uint64_t larg;
   1550  1017      bmc 		caddr_t zdata;
   1551  1017      bmc 
   1552  1017      bmc 		zsize = zaggdata[i].dtahe_size;
   1553  1017      bmc 		assert(zsize != 0);
   1554  1017      bmc 
   1555  1017      bmc 		if ((zdata = dt_zalloc(dtp, zsize)) == NULL) {
   1556  1017      bmc 			/*
   1557  1017      bmc 			 * If we failed to allocated some zero-filled data, we
   1558  1017      bmc 			 * need to zero out the remaining dtada_data pointers
   1559  1017      bmc 			 * to prevent the wrong data from being freed below.
   1560  1017      bmc 			 */
   1561  1017      bmc 			for (j = i; j < naggvars; j++)
   1562  1017      bmc 				zaggdata[j].dtahe_data.dtada_data = NULL;
   1563  1017      bmc 			goto out;
   1564  1017      bmc 		}
   1565  1017      bmc 
   1566  1017      bmc 		aggvar = aggvars[(i - sortpos + naggvars) % naggvars];
   1567  1017      bmc 
   1568  1017      bmc 		/*
   1569  1017      bmc 		 * First, the easy bit.  To maintain compatibility with
   1570  1017      bmc 		 * consumers that pull the compiler-generated ID out of the
   1571  1017      bmc 		 * data, we put that ID at the top of the zero-filled data.
   1572  1017      bmc 		 */
   1573  1017      bmc 		rec = &aggdesc->dtagd_rec[0];
   1574  1017      bmc 		/* LINTED - alignment */
   1575  1017      bmc 		*((dtrace_aggvarid_t *)(zdata + rec->dtrd_offset)) = aggvar;
   1576  1017      bmc 
   1577  1017      bmc 		rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
   1578  1017      bmc 
   1579  1017      bmc 		/*
   1580  1017      bmc 		 * Now for the more complicated part.  If (and only if) this
   1581  1017      bmc 		 * is an lquantize() aggregating action, zero-filled data is
   1582  1017      bmc 		 * not equivalent to an empty record:  we must also get the
   1583  1017      bmc 		 * parameters for the lquantize().
   1584  1017      bmc 		 */
   1585  1017      bmc 		if (rec->dtrd_action == DTRACEAGG_LQUANTIZE) {
   1586  1017      bmc 			if (aggdata->dtada_data != NULL) {
   1587  1017      bmc 				/*
   1588  1017      bmc 				 * The easier case here is if we actually have
   1589  1017      bmc 				 * some prototype data -- in which case we
   1590  1017      bmc 				 * manually dig it out of the aggregation
   1591  1017      bmc 				 * record.
   1592  1017      bmc 				 */
   1593  1017      bmc 				/* LINTED - alignment */
   1594  1017      bmc 				larg = *((uint64_t *)(aggdata->dtada_data +
   1595  1017      bmc 				    rec->dtrd_offset));
   1596  1017      bmc 			} else {
   1597  1017      bmc 				/*
   1598  1017      bmc 				 * We don't have any prototype data.  As a
   1599  1017      bmc 				 * result, we know that we _do_ have the
   1600  1017      bmc 				 * compiler-generated information.  (If this
   1601  1017      bmc 				 * were an anonymous enabling, all of our
   1602  1017      bmc 				 * zero-filled data would have prototype data
   1603  1017      bmc 				 * -- either directly or indirectly.) So as
   1604  1017      bmc 				 * gross as it is, we'll grovel around in the
   1605  1017      bmc 				 * compiler-generated information to find the
   1606  1017      bmc 				 * lquantize() parameters.
   1607  1017      bmc 				 */
   1608  1017      bmc 				dtrace_stmtdesc_t *sdp;
   1609  1017      bmc 				dt_ident_t *aid;
   1610  1017      bmc 				dt_idsig_t *isp;
   1611  1017      bmc 
   1612  1017      bmc 				sdp = (dtrace_stmtdesc_t *)(uintptr_t)
   1613  1017      bmc 				    aggdesc->dtagd_rec[0].dtrd_uarg;
   1614  1017      bmc 				aid = sdp->dtsd_aggdata;
   1615  1017      bmc 				isp = (dt_idsig_t *)aid->di_data;
   1616  1017      bmc 				assert(isp->dis_auxinfo != 0);
   1617  1017      bmc 				larg = isp->dis_auxinfo;
   1618  1017      bmc 			}
   1619  1017      bmc 
   1620  1017      bmc 			/* LINTED - alignment */
   1621  1017      bmc 			*((uint64_t *)(zdata + rec->dtrd_offset)) = larg;
   1622  1017      bmc 		}
   1623  1017      bmc 
   1624  1017      bmc 		aggdata->dtada_data = zdata;
   1625  1017      bmc 	}
   1626  1017      bmc 
   1627  1017      bmc 	/*
   1628  1017      bmc 	 * Now that we've dealt with setting up our zero-filled data, we can
   1629  1017      bmc 	 * allocate our sorted array, and take another pass over the data to
   1630  1017      bmc 	 * fill it.
   1631  1017      bmc 	 */
   1632  1017      bmc 	sorted = dt_alloc(dtp, nentries * sizeof (dt_ahashent_t *));
   1633  1017      bmc 
   1634  1017      bmc 	if (sorted == NULL)
   1635  1017      bmc 		goto out;
   1636  1017      bmc 
   1637  1017      bmc 	for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall) {
   1638  1017      bmc 		dtrace_aggvarid_t id;
   1639  1017      bmc 
   1640  1017      bmc 		if ((id = dt_aggregate_aggvarid(h)) > max || !map[id])
   1641  1017      bmc 			continue;
   1642  1017      bmc 
   1643  1017      bmc 		sorted[i++] = h;
   1644  1017      bmc 	}
   1645  1017      bmc 
   1646  1017      bmc 	assert(i == nentries);
   1647  1017      bmc 
   1648  1017      bmc 	/*
   1649  1017      bmc 	 * We've loaded our array; now we need to sort by value to allow us
   1650  1017      bmc 	 * to create bundles of like value.  We're going to acquire the
   1651  1017      bmc 	 * dt_qsort_lock here, and hold it across all of our subsequent
   1652  1017      bmc 	 * comparison and sorting.
   1653  1017      bmc 	 */
   1654  1017      bmc 	(void) pthread_mutex_lock(&dt_qsort_lock);
   1655  1017      bmc 
   1656  1017      bmc 	qsort(sorted, nentries, sizeof (dt_ahashent_t *),
   1657  1017      bmc 	    dt_aggregate_keyvarcmp);
   1658  1017      bmc 
   1659  1017      bmc 	/*
   1660  1017      bmc 	 * Now we need to go through and create bundles.  Because the number
   1661  1017      bmc 	 * of bundles is bounded by the size of the sorted array, we're going
   1662  1017      bmc 	 * to reuse the underlying storage.  And note that "bundle" is an
   1663  1017      bmc 	 * array of pointers to arrays of pointers to dt_ahashent_t -- making
   1664  1017      bmc 	 * its type (regrettably) "dt_ahashent_t ***".  (Regrettable because
   1665  1017      bmc 	 * '*' -- like '_' and 'X' -- should never appear in triplicate in
   1666  1017      bmc 	 * an ideal world.)
   1667  1017      bmc 	 */
   1668  1017      bmc 	bundle = (dt_ahashent_t ***)sorted;
   1669  1017      bmc 
   1670  1017      bmc 	for (i = 1, start = 0; i <= nentries; i++) {
   1671  1017      bmc 		if (i < nentries &&
   1672  1017      bmc 		    dt_aggregate_keycmp(&sorted[i], &sorted[i - 1]) == 0)
   1673  1017      bmc 			continue;
   1674  1017      bmc 
   1675  1017      bmc 		/*
   1676  1017      bmc 		 * We have a bundle boundary.  Everything from start to
   1677  1017      bmc 		 * (i - 1) belongs in one bundle.
   1678  1017      bmc 		 */
   1679  1017      bmc 		assert(i - start <= naggvars);
   1680  1017      bmc 		bundlesize = (naggvars + 2) * sizeof (dt_ahashent_t *);
   1681  1017      bmc 
   1682  1017      bmc 		if ((nbundle = dt_zalloc(dtp, bundlesize)) == NULL) {
   1683  1017      bmc 			(void) pthread_mutex_unlock(&dt_qsort_lock);
   1684  1017      bmc 			goto out;
   1685  1017      bmc 		}
   1686  1017      bmc 
   1687  1017      bmc 		for (j = start; j < i; j++) {
   1688  1017      bmc 			dtrace_aggvarid_t id = dt_aggregate_aggvarid(sorted[j]);
   1689  1017      bmc 
   1690  1017      bmc 			assert(id <= max);
   1691  1017      bmc 			assert(map[id] != 0);
   1692  1017      bmc 			assert(map[id] - 1 < naggvars);
   1693  1017      bmc 			assert(nbundle[map[id] - 1] == NULL);
   1694  1017      bmc 			nbundle[map[id] - 1] = sorted[j];
   1695  1017      bmc 
   1696  1017      bmc 			if (nbundle[naggvars] == NULL)
   1697  1017      bmc 				nbundle[naggvars] = sorted[j];
   1698  1017      bmc 		}
   1699  1017      bmc 
   1700  1017      bmc 		for (j = 0; j < naggvars; j++) {
   1701  1017      bmc 			if (nbundle[j] != NULL)
   1702  1017      bmc 				continue;
   1703  1017      bmc 
   1704  1017      bmc 			/*
   1705  1017      bmc 			 * Before we assume that this aggregation variable
   1706  1017      bmc 			 * isn't present (and fall back to using the
   1707  1017      bmc 			 * zero-filled data allocated earlier), check the
   1708  1017      bmc 			 * remap.  If we have a remapping, we'll drop it in
   1709  1017      bmc 			 * here.  Note that we might be remapping an
   1710  1017      bmc 			 * aggregation variable that isn't present for this
   1711  1017      bmc 			 * key; in this case, the aggregation data that we
   1712  1017      bmc 			 * copy will point to the zeroed data.
   1713  1017      bmc 			 */
   1714  1017      bmc 			if (remap != NULL && remap[j]) {
   1715  1017      bmc 				assert(remap[j] - 1 < j);
   1716  1017      bmc 				assert(nbundle[remap[j] - 1] != NULL);
   1717  1017      bmc 				nbundle[j] = nbundle[remap[j] - 1];
   1718  1017      bmc 			} else {
   1719  1017      bmc 				nbundle[j] = &zaggdata[j];
   1720  1017      bmc 			}
   1721  1017      bmc 		}
   1722  1017      bmc 
   1723  1017      bmc 		bundle[nbundles++] = nbundle;
   1724  1017      bmc 		start = i;
   1725  1017      bmc 	}
   1726  1017      bmc 
   1727  1017      bmc 	/*
   1728  1017      bmc 	 * Now we need to re-sort based on the first value.
   1729  1017      bmc 	 */
   1730  1017      bmc 	dt_aggregate_qsort(dtp, bundle, nbundles, sizeof (dt_ahashent_t **),
   1731  1017      bmc 	    dt_aggregate_bundlecmp);
   1732  1017      bmc 
   1733  1017      bmc 	(void) pthread_mutex_unlock(&dt_qsort_lock);
   1734  1017      bmc 
   1735  1017      bmc 	/*
   1736  1017      bmc 	 * We're done!  Now we just need to go back over the sorted bundles,
   1737  1017      bmc 	 * calling the function.
   1738  1017      bmc 	 */
   1739  1017      bmc 	data = alloca((naggvars + 1) * sizeof (dtrace_aggdata_t *));
   1740  1017      bmc 
   1741  1017      bmc 	for (i = 0; i < nbundles; i++) {
   1742  1017      bmc 		for (j = 0; j < naggvars; j++)
   1743  1017      bmc 			data[j + 1] = NULL;
   1744  1017      bmc 
   1745  1017      bmc 		for (j = 0; j < naggvars; j++) {
   1746  1017      bmc 			int ndx = j - sortpos;
   1747  1017      bmc 
   1748  1017      bmc 			if (ndx < 0)
   1749  1017      bmc 				ndx += naggvars;
   1750  1017      bmc 
   1751  1017      bmc 			assert(bundle[i][ndx] != NULL);
   1752  1017      bmc 			data[j + 1] = &bundle[i][ndx]->dtahe_data;
   1753  1017      bmc 		}
   1754  1017      bmc 
   1755  1017      bmc 		for (j = 0; j < naggvars; j++)
   1756  1017      bmc 			assert(data[j + 1] != NULL);
   1757  1017      bmc 
   1758  1017      bmc 		/*
   1759  1017      bmc 		 * The representative key is the last element in the bundle.
   1760  1017      bmc 		 * Assert that we have one, and then set it to be the first
   1761  1017      bmc 		 * element of data.
   1762  1017      bmc 		 */
   1763  1017      bmc 		assert(bundle[i][j] != NULL);
   1764  1017      bmc 		data[0] = &bundle[i][j]->dtahe_data;
   1765  1017      bmc 
   1766  1017      bmc 		if ((rval = func(data, naggvars + 1, arg)) == -1)
   1767  1017      bmc 			goto out;
   1768  1017      bmc 	}
   1769  1017      bmc 
   1770  1017      bmc 	rval = 0;
   1771  1017      bmc out:
   1772  1017      bmc 	for (i = 0; i < nbundles; i++)
   1773  1017      bmc 		dt_free(dtp, bundle[i]);
   1774  1017      bmc 
   1775  1017      bmc 	if (zaggdata != NULL) {
   1776  1017      bmc 		for (i = 0; i < naggvars; i++)
   1777  1017      bmc 			dt_free(dtp, zaggdata[i].dtahe_data.dtada_data);
   1778  1017      bmc 	}
   1779  1017      bmc 
   1780  1017      bmc 	dt_free(dtp, zaggdata);
   1781  1017      bmc 	dt_free(dtp, sorted);
   1782  1017      bmc 	dt_free(dtp, remap);
   1783  1017      bmc 	dt_free(dtp, map);
   1784  1017      bmc 
   1785  1017      bmc 	return (rval);
   1786  1017      bmc }
   1787  1017      bmc 
   1788  1017      bmc int
   1789     0   stevel dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp,
   1790     0   stevel     dtrace_aggregate_walk_f *func)
   1791     0   stevel {
   1792     0   stevel 	dt_print_aggdata_t pd;
   1793     0   stevel 
   1794     0   stevel 	pd.dtpa_dtp = dtp;
   1795     0   stevel 	pd.dtpa_fp = fp;
   1796     0   stevel 	pd.dtpa_allunprint = 1;
   1797     0   stevel 
   1798     0   stevel 	if (func == NULL)
   1799  1017      bmc 		func = dtrace_aggregate_walk_sorted;
   1800     0   stevel 
   1801     0   stevel 	if ((*func)(dtp, dt_print_agg, &pd) == -1)
   1802     0   stevel 		return (dt_set_errno(dtp, dtp->dt_errno));
   1803     0   stevel 
   1804     0   stevel 	return (0);
   1805     0   stevel }
   1806     0   stevel 
   1807     0   stevel void
   1808     0   stevel dtrace_aggregate_clear(dtrace_hdl_t *dtp)
   1809     0   stevel {
   1810     0   stevel 	dt_aggregate_t *agp = &dtp->dt_aggregate;
   1811     0   stevel 	dt_ahash_t *hash = &agp->dtat_hash;
   1812     0   stevel 	dt_ahashent_t *h;
   1813     0   stevel 	dtrace_aggdata_t *data;
   1814     0   stevel 	dtrace_aggdesc_t *aggdesc;
   1815     0   stevel 	dtrace_recdesc_t *rec;
   1816     0   stevel 	int i, max_cpus = agp->dtat_maxcpu;
   1817     0   stevel 
   1818     0   stevel 	for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) {
   1819     0   stevel 		aggdesc = h->dtahe_data.dtada_desc;
   1820     0   stevel 		rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1];
   1821     0   stevel 		data = &h->dtahe_data;
   1822     0   stevel 
   1823     0   stevel 		bzero(&data->dtada_data[rec->dtrd_offset], rec->dtrd_size);
   1824     0   stevel 
   1825     0   stevel 		if (data->dtada_percpu == NULL)
   1826     0   stevel 			continue;
   1827     0   stevel 
   1828     0   stevel 		for (i = 0; i < max_cpus; i++)
   1829     0   stevel 			bzero(data->dtada_percpu[i], rec->dtrd_size);
   1830     0   stevel 	}
   1831     0   stevel }
   1832     0   stevel 
   1833     0   stevel void
   1834     0   stevel dt_aggregate_destroy(dtrace_hdl_t *dtp)
   1835     0   stevel {
   1836     0   stevel 	dt_aggregate_t *agp = &dtp->dt_aggregate;
   1837     0   stevel 	dt_ahash_t *hash = &agp->dtat_hash;
   1838     0   stevel 	dt_ahashent_t *h, *next;
   1839     0   stevel 	dtrace_aggdata_t *aggdata;
   1840     0   stevel 	int i, max_cpus = agp->dtat_maxcpu;
   1841     0   stevel 
   1842     0   stevel 	if (hash->dtah_hash == NULL) {
   1843     0   stevel 		assert(hash->dtah_all == NULL);
   1844     0   stevel 	} else {
   1845     0   stevel 		free(hash->dtah_hash);
   1846     0   stevel 
   1847     0   stevel 		for (h = hash->dtah_all; h != NULL; h = next) {
   1848     0   stevel 			next = h->dtahe_nextall;
   1849     0   stevel 
   1850     0   stevel 			aggdata = &h->dtahe_data;
   1851     0   stevel 
   1852     0   stevel 			if (aggdata->dtada_percpu != NULL) {
   1853     0   stevel 				for (i = 0; i < max_cpus; i++)
   1854     0   stevel 					free(aggdata->dtada_percpu[i]);
   1855     0   stevel 				free(aggdata->dtada_percpu);
   1856     0   stevel 			}
   1857     0   stevel 
   1858     0   stevel 			free(aggdata->dtada_data);
   1859     0   stevel 			free(h);
   1860     0   stevel 		}
   1861     0   stevel 
   1862     0   stevel 		hash->dtah_hash = NULL;
   1863     0   stevel 		hash->dtah_all = NULL;
   1864     0   stevel 		hash->dtah_size = 0;
   1865     0   stevel 	}
   1866     0   stevel 
   1867     0   stevel 	free(agp->dtat_buf.dtbd_data);
   1868     0   stevel 	free(agp->dtat_cpus);
   1869     0   stevel }
   1870