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