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 1050Sstevel@tonic-gate static int64_t 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; 1120Sstevel@tonic-gate int64_t total = lquanta[0] * (base - 1); 1130Sstevel@tonic-gate 1140Sstevel@tonic-gate for (i = 0; i < levels; base += step, i++) 1150Sstevel@tonic-gate total += lquanta[i + 1] * base; 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate return (total + lquanta[levels + 1] * (base + 1)); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate static int 1210Sstevel@tonic-gate dt_aggregate_lquantizedcmp(uint64_t *lhs, uint64_t *rhs) 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate int64_t lsum = dt_aggregate_lquantizedsum(lhs); 1240Sstevel@tonic-gate int64_t rsum = dt_aggregate_lquantizedsum(rhs); 1250Sstevel@tonic-gate 1260Sstevel@tonic-gate if (lsum > rsum) 1270Sstevel@tonic-gate return (1); 1280Sstevel@tonic-gate 1290Sstevel@tonic-gate if (lsum < rsum) 1300Sstevel@tonic-gate return (-1); 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate return (0); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate static int 1360Sstevel@tonic-gate dt_aggregate_quantizedcmp(uint64_t *lhs, uint64_t *rhs) 1370Sstevel@tonic-gate { 1380Sstevel@tonic-gate int nbuckets = DTRACE_QUANTIZE_NBUCKETS, i; 1390Sstevel@tonic-gate int64_t ltotal = 0, rtotal = 0; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate for (i = 0; i < nbuckets; i++) { 1420Sstevel@tonic-gate int64_t bucketval = DTRACE_QUANTIZE_BUCKETVAL(i); 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate ltotal += bucketval * lhs[i]; 1450Sstevel@tonic-gate rtotal += bucketval * rhs[i]; 1460Sstevel@tonic-gate } 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate if (ltotal > rtotal) 1490Sstevel@tonic-gate return (1); 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate if (ltotal < rtotal) 1520Sstevel@tonic-gate return (-1); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate return (0); 1550Sstevel@tonic-gate } 1560Sstevel@tonic-gate 1570Sstevel@tonic-gate static int 1580Sstevel@tonic-gate dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu) 1590Sstevel@tonic-gate { 1600Sstevel@tonic-gate dtrace_epid_t id; 1610Sstevel@tonic-gate uint64_t hashval; 1620Sstevel@tonic-gate size_t offs, roffs, size, ndx; 1630Sstevel@tonic-gate int i, j, rval; 1640Sstevel@tonic-gate caddr_t addr, data; 1650Sstevel@tonic-gate dtrace_recdesc_t *rec; 1660Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 1670Sstevel@tonic-gate dtrace_aggdesc_t *agg; 1680Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 1690Sstevel@tonic-gate dt_ahashent_t *h; 1700Sstevel@tonic-gate dtrace_bufdesc_t b = agp->dtat_buf, *buf = &b; 1710Sstevel@tonic-gate dtrace_aggdata_t *aggdata; 1720Sstevel@tonic-gate int flags = agp->dtat_flags; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate buf->dtbd_cpu = cpu; 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, buf) == -1) { 1770Sstevel@tonic-gate if (errno == ENOENT) { 1780Sstevel@tonic-gate /* 1790Sstevel@tonic-gate * If that failed with ENOENT, it may be because the 1800Sstevel@tonic-gate * CPU was unconfigured. This is okay; we'll just 1810Sstevel@tonic-gate * do nothing but return success. 1820Sstevel@tonic-gate */ 1830Sstevel@tonic-gate return (0); 1840Sstevel@tonic-gate } 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 1870Sstevel@tonic-gate } 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate if (buf->dtbd_drops != 0) { 1900Sstevel@tonic-gate if (dt_handle_cpudrop(dtp, cpu, 1910Sstevel@tonic-gate DTRACEDROP_AGGREGATION, buf->dtbd_drops) == -1) 1920Sstevel@tonic-gate return (-1); 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate if (buf->dtbd_size == 0) 1960Sstevel@tonic-gate return (0); 1970Sstevel@tonic-gate 1980Sstevel@tonic-gate if (hash->dtah_hash == NULL) { 1990Sstevel@tonic-gate size_t size; 2000Sstevel@tonic-gate 2010Sstevel@tonic-gate hash->dtah_size = DTRACE_AHASHSIZE; 2020Sstevel@tonic-gate size = hash->dtah_size * sizeof (dt_ahashent_t *); 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if ((hash->dtah_hash = malloc(size)) == NULL) 2050Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate bzero(hash->dtah_hash, size); 2080Sstevel@tonic-gate } 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate for (offs = 0; offs < buf->dtbd_size; ) { 2110Sstevel@tonic-gate /* 2120Sstevel@tonic-gate * We're guaranteed to have an ID. 2130Sstevel@tonic-gate */ 2140Sstevel@tonic-gate id = *((dtrace_epid_t *)((uintptr_t)buf->dtbd_data + 2150Sstevel@tonic-gate (uintptr_t)offs)); 2160Sstevel@tonic-gate 2170Sstevel@tonic-gate if (id == DTRACE_AGGIDNONE) { 2180Sstevel@tonic-gate /* 2190Sstevel@tonic-gate * This is filler to assure proper alignment of the 2200Sstevel@tonic-gate * next record; we simply ignore it. 2210Sstevel@tonic-gate */ 2220Sstevel@tonic-gate offs += sizeof (id); 2230Sstevel@tonic-gate continue; 2240Sstevel@tonic-gate } 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if ((rval = dt_aggid_lookup(dtp, id, &agg)) != 0) 2270Sstevel@tonic-gate return (rval); 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate addr = buf->dtbd_data + offs; 2300Sstevel@tonic-gate size = agg->dtagd_size; 2310Sstevel@tonic-gate hashval = 0; 2320Sstevel@tonic-gate 2330Sstevel@tonic-gate for (j = 0; j < agg->dtagd_nrecs - 1; j++) { 2340Sstevel@tonic-gate rec = &agg->dtagd_rec[j]; 2350Sstevel@tonic-gate roffs = rec->dtrd_offset; 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate for (i = 0; i < rec->dtrd_size; i++) 2380Sstevel@tonic-gate hashval += addr[roffs + i]; 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate ndx = hashval % hash->dtah_size; 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate for (h = hash->dtah_hash[ndx]; h != NULL; h = h->dtahe_next) { 2440Sstevel@tonic-gate if (h->dtahe_hashval != hashval) 2450Sstevel@tonic-gate continue; 2460Sstevel@tonic-gate 2470Sstevel@tonic-gate if (h->dtahe_size != size) 2480Sstevel@tonic-gate continue; 2490Sstevel@tonic-gate 2500Sstevel@tonic-gate aggdata = &h->dtahe_data; 2510Sstevel@tonic-gate data = aggdata->dtada_data; 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate for (j = 0; j < agg->dtagd_nrecs - 1; j++) { 2540Sstevel@tonic-gate rec = &agg->dtagd_rec[j]; 2550Sstevel@tonic-gate roffs = rec->dtrd_offset; 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate for (i = 0; i < rec->dtrd_size; i++) 2580Sstevel@tonic-gate if (addr[roffs + i] != data[roffs + i]) 2590Sstevel@tonic-gate goto hashnext; 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate /* 2630Sstevel@tonic-gate * We found it. Now we need to apply the aggregating 2640Sstevel@tonic-gate * action on the data here. 2650Sstevel@tonic-gate */ 2660Sstevel@tonic-gate rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1]; 2670Sstevel@tonic-gate roffs = rec->dtrd_offset; 2680Sstevel@tonic-gate /* LINTED - alignment */ 2690Sstevel@tonic-gate h->dtahe_aggregate((uint64_t *)&data[roffs], 2700Sstevel@tonic-gate /* LINTED - alignment */ 2710Sstevel@tonic-gate (uint64_t *)&addr[roffs], rec->dtrd_size); 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate /* 2740Sstevel@tonic-gate * If we're keeping per CPU data, apply the aggregating 2750Sstevel@tonic-gate * action there as well. 2760Sstevel@tonic-gate */ 2770Sstevel@tonic-gate if (aggdata->dtada_percpu != NULL) { 2780Sstevel@tonic-gate data = aggdata->dtada_percpu[cpu]; 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate /* LINTED - alignment */ 2810Sstevel@tonic-gate h->dtahe_aggregate((uint64_t *)data, 2820Sstevel@tonic-gate /* LINTED - alignment */ 2830Sstevel@tonic-gate (uint64_t *)&addr[roffs], rec->dtrd_size); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate goto bufnext; 2870Sstevel@tonic-gate hashnext: 2880Sstevel@tonic-gate continue; 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate /* 2920Sstevel@tonic-gate * If we're here, we couldn't find an entry for this record. 2930Sstevel@tonic-gate */ 2940Sstevel@tonic-gate if ((h = malloc(sizeof (dt_ahashent_t))) == NULL) 2950Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 2960Sstevel@tonic-gate bzero(h, sizeof (dt_ahashent_t)); 2970Sstevel@tonic-gate aggdata = &h->dtahe_data; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate if ((aggdata->dtada_data = malloc(size)) == NULL) { 3000Sstevel@tonic-gate free(h); 3010Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3020Sstevel@tonic-gate } 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate bcopy(addr, aggdata->dtada_data, size); 3050Sstevel@tonic-gate aggdata->dtada_size = size; 3060Sstevel@tonic-gate aggdata->dtada_desc = agg; 3070Sstevel@tonic-gate aggdata->dtada_handle = dtp; 3080Sstevel@tonic-gate (void) dt_epid_lookup(dtp, agg->dtagd_epid, 3090Sstevel@tonic-gate &aggdata->dtada_edesc, &aggdata->dtada_pdesc); 3100Sstevel@tonic-gate aggdata->dtada_normal = 1; 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate h->dtahe_hashval = hashval; 3130Sstevel@tonic-gate h->dtahe_size = size; 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1]; 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate if (flags & DTRACE_A_PERCPU) { 3180Sstevel@tonic-gate int max_cpus = agp->dtat_maxcpu; 3190Sstevel@tonic-gate caddr_t *percpu = malloc(max_cpus * sizeof (caddr_t)); 3200Sstevel@tonic-gate 3210Sstevel@tonic-gate if (percpu == NULL) { 3220Sstevel@tonic-gate free(aggdata->dtada_data); 3230Sstevel@tonic-gate free(h); 3240Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3250Sstevel@tonic-gate } 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate for (j = 0; j < max_cpus; j++) { 3280Sstevel@tonic-gate percpu[j] = malloc(rec->dtrd_size); 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate if (percpu[j] == NULL) { 3310Sstevel@tonic-gate while (--j >= 0) 3320Sstevel@tonic-gate free(percpu[j]); 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate free(aggdata->dtada_data); 3350Sstevel@tonic-gate free(h); 3360Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3370Sstevel@tonic-gate } 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate if (j == cpu) { 3400Sstevel@tonic-gate bcopy(&addr[rec->dtrd_offset], 3410Sstevel@tonic-gate percpu[j], rec->dtrd_size); 3420Sstevel@tonic-gate } else { 3430Sstevel@tonic-gate bzero(percpu[j], rec->dtrd_size); 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate } 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate aggdata->dtada_percpu = percpu; 3480Sstevel@tonic-gate } 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate switch (rec->dtrd_action) { 3510Sstevel@tonic-gate case DTRACEAGG_MIN: 3520Sstevel@tonic-gate h->dtahe_aggregate = dt_aggregate_min; 3530Sstevel@tonic-gate break; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate case DTRACEAGG_MAX: 3560Sstevel@tonic-gate h->dtahe_aggregate = dt_aggregate_max; 3570Sstevel@tonic-gate break; 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate case DTRACEAGG_LQUANTIZE: 3600Sstevel@tonic-gate h->dtahe_aggregate = dt_aggregate_lquantize; 3610Sstevel@tonic-gate break; 3620Sstevel@tonic-gate 3630Sstevel@tonic-gate case DTRACEAGG_COUNT: 3640Sstevel@tonic-gate case DTRACEAGG_SUM: 3650Sstevel@tonic-gate case DTRACEAGG_AVG: 3660Sstevel@tonic-gate case DTRACEAGG_QUANTIZE: 3670Sstevel@tonic-gate h->dtahe_aggregate = dt_aggregate_count; 3680Sstevel@tonic-gate break; 3690Sstevel@tonic-gate 3700Sstevel@tonic-gate default: 3710Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADAGG)); 3720Sstevel@tonic-gate } 3730Sstevel@tonic-gate 3740Sstevel@tonic-gate if (hash->dtah_hash[ndx] != NULL) 3750Sstevel@tonic-gate hash->dtah_hash[ndx]->dtahe_prev = h; 3760Sstevel@tonic-gate 3770Sstevel@tonic-gate h->dtahe_next = hash->dtah_hash[ndx]; 3780Sstevel@tonic-gate hash->dtah_hash[ndx] = h; 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate if (hash->dtah_all != NULL) 3810Sstevel@tonic-gate hash->dtah_all->dtahe_prevall = h; 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate h->dtahe_nextall = hash->dtah_all; 3840Sstevel@tonic-gate hash->dtah_all = h; 3850Sstevel@tonic-gate bufnext: 3860Sstevel@tonic-gate offs += agg->dtagd_size; 3870Sstevel@tonic-gate } 3880Sstevel@tonic-gate 3890Sstevel@tonic-gate return (0); 3900Sstevel@tonic-gate } 3910Sstevel@tonic-gate 3920Sstevel@tonic-gate int 3930Sstevel@tonic-gate dtrace_aggregate_snap(dtrace_hdl_t *dtp) 3940Sstevel@tonic-gate { 3950Sstevel@tonic-gate int i, rval; 3960Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 3970Sstevel@tonic-gate hrtime_t now = gethrtime(); 3980Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_AGGRATE]; 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate if (dtp->dt_lastagg != 0) { 4010Sstevel@tonic-gate if (now - dtp->dt_lastagg < interval) 4020Sstevel@tonic-gate return (0); 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate dtp->dt_lastagg += interval; 4050Sstevel@tonic-gate } else { 4060Sstevel@tonic-gate dtp->dt_lastagg = now; 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate if (!dtp->dt_active) 4100Sstevel@tonic-gate return (dt_set_errno(dtp, EINVAL)); 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate if (agp->dtat_buf.dtbd_size == 0) 4130Sstevel@tonic-gate return (0); 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate for (i = 0; i < agp->dtat_ncpus; i++) { 4160Sstevel@tonic-gate if (rval = dt_aggregate_snap_cpu(dtp, agp->dtat_cpus[i])) 4170Sstevel@tonic-gate return (rval); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate 4200Sstevel@tonic-gate return (0); 4210Sstevel@tonic-gate } 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate static int 4240Sstevel@tonic-gate dt_aggregate_hashcmp(const void *lhs, const void *rhs) 4250Sstevel@tonic-gate { 4260Sstevel@tonic-gate dt_ahashent_t *lh = *((dt_ahashent_t **)lhs); 4270Sstevel@tonic-gate dt_ahashent_t *rh = *((dt_ahashent_t **)rhs); 4280Sstevel@tonic-gate dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc; 4290Sstevel@tonic-gate dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc; 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate if (lagg->dtagd_nrecs < ragg->dtagd_nrecs) 4320Sstevel@tonic-gate return (-1); 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate if (lagg->dtagd_nrecs > ragg->dtagd_nrecs) 4350Sstevel@tonic-gate return (1); 4360Sstevel@tonic-gate 4370Sstevel@tonic-gate return (0); 4380Sstevel@tonic-gate } 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate static int 4410Sstevel@tonic-gate dt_aggregate_varcmp(const void *lhs, const void *rhs) 4420Sstevel@tonic-gate { 4430Sstevel@tonic-gate dt_ahashent_t *lh = *((dt_ahashent_t **)lhs); 4440Sstevel@tonic-gate dt_ahashent_t *rh = *((dt_ahashent_t **)rhs); 4450Sstevel@tonic-gate dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc; 4460Sstevel@tonic-gate dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc; 4470Sstevel@tonic-gate caddr_t ldata = lh->dtahe_data.dtada_data; 4480Sstevel@tonic-gate caddr_t rdata = rh->dtahe_data.dtada_data; 4490Sstevel@tonic-gate dtrace_recdesc_t *lrec, *rrec; 4500Sstevel@tonic-gate uint64_t lid, rid; 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate /* 4530Sstevel@tonic-gate * We know that we have a compiler-generated ID as the first record. 4540Sstevel@tonic-gate */ 4550Sstevel@tonic-gate lrec = lagg->dtagd_rec; 4560Sstevel@tonic-gate rrec = ragg->dtagd_rec; 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate lid = *((uint64_t *)(uintptr_t)(ldata + lrec->dtrd_offset)); 4590Sstevel@tonic-gate rid = *((uint64_t *)(uintptr_t)(rdata + rrec->dtrd_offset)); 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate if (lid < rid) 4620Sstevel@tonic-gate return (-1); 4630Sstevel@tonic-gate 4640Sstevel@tonic-gate if (lid > rid) 4650Sstevel@tonic-gate return (1); 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate return (0); 4680Sstevel@tonic-gate } 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate static int 4710Sstevel@tonic-gate dt_aggregate_keycmp(const void *lhs, const void *rhs) 4720Sstevel@tonic-gate { 4730Sstevel@tonic-gate dt_ahashent_t *lh = *((dt_ahashent_t **)lhs); 4740Sstevel@tonic-gate dt_ahashent_t *rh = *((dt_ahashent_t **)rhs); 4750Sstevel@tonic-gate dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc; 4760Sstevel@tonic-gate dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc; 4770Sstevel@tonic-gate dtrace_recdesc_t *lrec, *rrec; 4780Sstevel@tonic-gate char *ldata, *rdata; 479*403Sbmc int rval, i, j; 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0) 4820Sstevel@tonic-gate return (rval); 4830Sstevel@tonic-gate 4840Sstevel@tonic-gate for (i = 1; i < lagg->dtagd_nrecs - 1; i++) { 4850Sstevel@tonic-gate uint64_t lval, rval; 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate lrec = &lagg->dtagd_rec[i]; 4880Sstevel@tonic-gate rrec = &ragg->dtagd_rec[i]; 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate ldata = lh->dtahe_data.dtada_data + lrec->dtrd_offset; 4910Sstevel@tonic-gate rdata = rh->dtahe_data.dtada_data + rrec->dtrd_offset; 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate if (lrec->dtrd_size < rrec->dtrd_size) 4940Sstevel@tonic-gate return (-1); 4950Sstevel@tonic-gate 4960Sstevel@tonic-gate if (lrec->dtrd_size > rrec->dtrd_size) 4970Sstevel@tonic-gate return (1); 4980Sstevel@tonic-gate 4990Sstevel@tonic-gate switch (lrec->dtrd_size) { 5000Sstevel@tonic-gate case sizeof (uint64_t): 5010Sstevel@tonic-gate /* LINTED - alignment */ 5020Sstevel@tonic-gate lval = *((uint64_t *)ldata); 5030Sstevel@tonic-gate /* LINTED - alignment */ 5040Sstevel@tonic-gate rval = *((uint64_t *)rdata); 5050Sstevel@tonic-gate break; 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate case sizeof (uint32_t): 5080Sstevel@tonic-gate /* LINTED - alignment */ 5090Sstevel@tonic-gate lval = *((uint32_t *)ldata); 5100Sstevel@tonic-gate /* LINTED - alignment */ 5110Sstevel@tonic-gate rval = *((uint32_t *)rdata); 5120Sstevel@tonic-gate break; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate case sizeof (uint16_t): 5150Sstevel@tonic-gate /* LINTED - alignment */ 5160Sstevel@tonic-gate lval = *((uint16_t *)ldata); 5170Sstevel@tonic-gate /* LINTED - alignment */ 5180Sstevel@tonic-gate rval = *((uint16_t *)rdata); 5190Sstevel@tonic-gate break; 5200Sstevel@tonic-gate 5210Sstevel@tonic-gate case sizeof (uint8_t): 5220Sstevel@tonic-gate lval = *((uint8_t *)ldata); 5230Sstevel@tonic-gate rval = *((uint8_t *)rdata); 5240Sstevel@tonic-gate break; 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate default: 527*403Sbmc for (j = 0; j < lrec->dtrd_size; j++) { 528*403Sbmc lval = ((uint8_t *)ldata)[j]; 529*403Sbmc rval = ((uint8_t *)rdata)[j]; 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate if (lval < rval) 5320Sstevel@tonic-gate return (-1); 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate if (lval > rval) 5350Sstevel@tonic-gate return (1); 5360Sstevel@tonic-gate } 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate continue; 5390Sstevel@tonic-gate } 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if (lval < rval) 5420Sstevel@tonic-gate return (-1); 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate if (lval > rval) 5450Sstevel@tonic-gate return (1); 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate return (0); 5490Sstevel@tonic-gate } 5500Sstevel@tonic-gate 5510Sstevel@tonic-gate static int 5520Sstevel@tonic-gate dt_aggregate_valcmp(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 *laddr, *raddr; 5620Sstevel@tonic-gate int rval, i; 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0) 5650Sstevel@tonic-gate return (rval); 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate if (lagg->dtagd_nrecs < ragg->dtagd_nrecs) 5680Sstevel@tonic-gate return (-1); 5690Sstevel@tonic-gate 5700Sstevel@tonic-gate if (lagg->dtagd_nrecs > ragg->dtagd_nrecs) 5710Sstevel@tonic-gate return (1); 5720Sstevel@tonic-gate 5730Sstevel@tonic-gate for (i = 0; i < lagg->dtagd_nrecs; i++) { 5740Sstevel@tonic-gate lrec = &lagg->dtagd_rec[i]; 5750Sstevel@tonic-gate rrec = &ragg->dtagd_rec[i]; 5760Sstevel@tonic-gate 5770Sstevel@tonic-gate if (lrec->dtrd_offset < rrec->dtrd_offset) 5780Sstevel@tonic-gate return (-1); 5790Sstevel@tonic-gate 5800Sstevel@tonic-gate if (lrec->dtrd_offset > rrec->dtrd_offset) 5810Sstevel@tonic-gate return (1); 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (lrec->dtrd_action < rrec->dtrd_action) 5840Sstevel@tonic-gate return (-1); 5850Sstevel@tonic-gate 5860Sstevel@tonic-gate if (lrec->dtrd_action > rrec->dtrd_action) 5870Sstevel@tonic-gate return (1); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate laddr = (uint64_t *)(uintptr_t)(ldata + lrec->dtrd_offset); 5910Sstevel@tonic-gate raddr = (uint64_t *)(uintptr_t)(rdata + rrec->dtrd_offset); 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate switch (lrec->dtrd_action) { 5940Sstevel@tonic-gate case DTRACEAGG_AVG: 5950Sstevel@tonic-gate rval = dt_aggregate_averagecmp(laddr, raddr); 5960Sstevel@tonic-gate break; 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate case DTRACEAGG_QUANTIZE: 5990Sstevel@tonic-gate rval = dt_aggregate_quantizedcmp(laddr, raddr); 6000Sstevel@tonic-gate break; 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate case DTRACEAGG_LQUANTIZE: 6030Sstevel@tonic-gate rval = dt_aggregate_lquantizedcmp(laddr, raddr); 6040Sstevel@tonic-gate break; 6050Sstevel@tonic-gate 6060Sstevel@tonic-gate case DTRACEAGG_COUNT: 6070Sstevel@tonic-gate case DTRACEAGG_SUM: 6080Sstevel@tonic-gate case DTRACEAGG_MIN: 6090Sstevel@tonic-gate case DTRACEAGG_MAX: 6100Sstevel@tonic-gate rval = dt_aggregate_countcmp(laddr, raddr); 6110Sstevel@tonic-gate break; 6120Sstevel@tonic-gate 6130Sstevel@tonic-gate default: 6140Sstevel@tonic-gate assert(0); 6150Sstevel@tonic-gate } 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate if (rval != 0) 6180Sstevel@tonic-gate return (rval); 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate /* 6210Sstevel@tonic-gate * If we're here, the values for the two aggregation elements are 6220Sstevel@tonic-gate * equal. We already know that the key layout is the same for the two 6230Sstevel@tonic-gate * elements; we must now compare the keys themselves as a tie-breaker. 6240Sstevel@tonic-gate */ 6250Sstevel@tonic-gate return (dt_aggregate_keycmp(lhs, rhs)); 6260Sstevel@tonic-gate } 6270Sstevel@tonic-gate 6280Sstevel@tonic-gate static int 6290Sstevel@tonic-gate dt_aggregate_keyvarcmp(const void *lhs, const void *rhs) 6300Sstevel@tonic-gate { 6310Sstevel@tonic-gate int rval; 6320Sstevel@tonic-gate 6330Sstevel@tonic-gate if ((rval = dt_aggregate_keycmp(lhs, rhs)) != 0) 6340Sstevel@tonic-gate return (rval); 6350Sstevel@tonic-gate 6360Sstevel@tonic-gate return (dt_aggregate_varcmp(lhs, rhs)); 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate static int 6400Sstevel@tonic-gate dt_aggregate_varkeycmp(const void *lhs, const void *rhs) 6410Sstevel@tonic-gate { 6420Sstevel@tonic-gate int rval; 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0) 6450Sstevel@tonic-gate return (rval); 6460Sstevel@tonic-gate 6470Sstevel@tonic-gate return (dt_aggregate_keycmp(lhs, rhs)); 6480Sstevel@tonic-gate } 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate static int 6510Sstevel@tonic-gate dt_aggregate_valvarcmp(const void *lhs, const void *rhs) 6520Sstevel@tonic-gate { 6530Sstevel@tonic-gate int rval; 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate if ((rval = dt_aggregate_valcmp(lhs, rhs)) != 0) 6560Sstevel@tonic-gate return (rval); 6570Sstevel@tonic-gate 6580Sstevel@tonic-gate return (dt_aggregate_varcmp(lhs, rhs)); 6590Sstevel@tonic-gate } 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate static int 6620Sstevel@tonic-gate dt_aggregate_varvalcmp(const void *lhs, const void *rhs) 6630Sstevel@tonic-gate { 6640Sstevel@tonic-gate int rval; 6650Sstevel@tonic-gate 6660Sstevel@tonic-gate if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0) 6670Sstevel@tonic-gate return (rval); 6680Sstevel@tonic-gate 6690Sstevel@tonic-gate return (dt_aggregate_valcmp(lhs, rhs)); 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate static int 6730Sstevel@tonic-gate dt_aggregate_keyvarrevcmp(const void *lhs, const void *rhs) 6740Sstevel@tonic-gate { 6750Sstevel@tonic-gate return (dt_aggregate_keyvarcmp(rhs, lhs)); 6760Sstevel@tonic-gate } 6770Sstevel@tonic-gate 6780Sstevel@tonic-gate static int 6790Sstevel@tonic-gate dt_aggregate_varkeyrevcmp(const void *lhs, const void *rhs) 6800Sstevel@tonic-gate { 6810Sstevel@tonic-gate return (dt_aggregate_varkeycmp(rhs, lhs)); 6820Sstevel@tonic-gate } 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate static int 6850Sstevel@tonic-gate dt_aggregate_valvarrevcmp(const void *lhs, const void *rhs) 6860Sstevel@tonic-gate { 6870Sstevel@tonic-gate return (dt_aggregate_valvarcmp(rhs, lhs)); 6880Sstevel@tonic-gate } 6890Sstevel@tonic-gate 6900Sstevel@tonic-gate static int 6910Sstevel@tonic-gate dt_aggregate_varvalrevcmp(const void *lhs, const void *rhs) 6920Sstevel@tonic-gate { 6930Sstevel@tonic-gate return (dt_aggregate_varvalcmp(rhs, lhs)); 6940Sstevel@tonic-gate } 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate int 6970Sstevel@tonic-gate dt_aggregate_go(dtrace_hdl_t *dtp) 6980Sstevel@tonic-gate { 6990Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 7000Sstevel@tonic-gate dtrace_optval_t size, cpu; 7010Sstevel@tonic-gate dtrace_bufdesc_t *buf = &agp->dtat_buf; 7020Sstevel@tonic-gate int rval, i; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate assert(agp->dtat_maxcpu == 0); 7050Sstevel@tonic-gate assert(agp->dtat_ncpu == 0); 7060Sstevel@tonic-gate assert(agp->dtat_cpus == NULL); 7070Sstevel@tonic-gate 7080Sstevel@tonic-gate agp->dtat_maxcpu = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 7090Sstevel@tonic-gate agp->dtat_ncpu = dt_sysconf(dtp, _SC_NPROCESSORS_MAX); 7100Sstevel@tonic-gate agp->dtat_cpus = malloc(agp->dtat_ncpu * sizeof (processorid_t)); 7110Sstevel@tonic-gate 7120Sstevel@tonic-gate if (agp->dtat_cpus == NULL) 7130Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate /* 7160Sstevel@tonic-gate * Use the aggregation buffer size as reloaded from the kernel. 7170Sstevel@tonic-gate */ 7180Sstevel@tonic-gate size = dtp->dt_options[DTRACEOPT_AGGSIZE]; 7190Sstevel@tonic-gate 7200Sstevel@tonic-gate rval = dtrace_getopt(dtp, "aggsize", &size); 7210Sstevel@tonic-gate assert(rval == 0); 7220Sstevel@tonic-gate 7230Sstevel@tonic-gate if (size == 0 || size == DTRACEOPT_UNSET) 7240Sstevel@tonic-gate return (0); 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate buf = &agp->dtat_buf; 7270Sstevel@tonic-gate buf->dtbd_size = size; 7280Sstevel@tonic-gate 7290Sstevel@tonic-gate if ((buf->dtbd_data = malloc(buf->dtbd_size)) == NULL) 7300Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate /* 7330Sstevel@tonic-gate * Now query for the CPUs enabled. 7340Sstevel@tonic-gate */ 7350Sstevel@tonic-gate rval = dtrace_getopt(dtp, "cpu", &cpu); 7360Sstevel@tonic-gate assert(rval == 0 && cpu != DTRACEOPT_UNSET); 7370Sstevel@tonic-gate 7380Sstevel@tonic-gate if (cpu != DTRACE_CPUALL) { 7390Sstevel@tonic-gate assert(cpu < agp->dtat_ncpu); 7400Sstevel@tonic-gate agp->dtat_cpus[agp->dtat_ncpus++] = (processorid_t)cpu; 7410Sstevel@tonic-gate 7420Sstevel@tonic-gate return (0); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate agp->dtat_ncpus = 0; 7460Sstevel@tonic-gate for (i = 0; i < agp->dtat_maxcpu; i++) { 7470Sstevel@tonic-gate if (dt_status(dtp, i) == -1) 7480Sstevel@tonic-gate continue; 7490Sstevel@tonic-gate 7500Sstevel@tonic-gate agp->dtat_cpus[agp->dtat_ncpus++] = i; 7510Sstevel@tonic-gate } 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate return (0); 7540Sstevel@tonic-gate } 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate static int 7570Sstevel@tonic-gate dt_aggwalk_rval(dtrace_hdl_t *dtp, dt_ahashent_t *h, int rval) 7580Sstevel@tonic-gate { 7590Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 7600Sstevel@tonic-gate dtrace_aggdata_t *data; 7610Sstevel@tonic-gate dtrace_aggdesc_t *aggdesc; 7620Sstevel@tonic-gate dtrace_recdesc_t *rec; 7630Sstevel@tonic-gate int i; 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate switch (rval) { 7660Sstevel@tonic-gate case DTRACE_AGGWALK_NEXT: 7670Sstevel@tonic-gate break; 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate case DTRACE_AGGWALK_CLEAR: { 7700Sstevel@tonic-gate uint32_t size, offs = 0; 7710Sstevel@tonic-gate 7720Sstevel@tonic-gate aggdesc = h->dtahe_data.dtada_desc; 7730Sstevel@tonic-gate rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1]; 7740Sstevel@tonic-gate size = rec->dtrd_size; 7750Sstevel@tonic-gate data = &h->dtahe_data; 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate if (rec->dtrd_action == DTRACEAGG_LQUANTIZE) { 7780Sstevel@tonic-gate offs = sizeof (uint64_t); 7790Sstevel@tonic-gate size -= sizeof (uint64_t); 7800Sstevel@tonic-gate } 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate bzero(&data->dtada_data[rec->dtrd_offset] + offs, size); 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate if (data->dtada_percpu == NULL) 7850Sstevel@tonic-gate break; 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate for (i = 0; i < dtp->dt_aggregate.dtat_maxcpu; i++) 7880Sstevel@tonic-gate bzero(data->dtada_percpu[i] + offs, size); 7890Sstevel@tonic-gate break; 7900Sstevel@tonic-gate } 7910Sstevel@tonic-gate 7920Sstevel@tonic-gate case DTRACE_AGGWALK_ERROR: 7930Sstevel@tonic-gate /* 7940Sstevel@tonic-gate * We assume that errno is already set in this case. 7950Sstevel@tonic-gate */ 7960Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate case DTRACE_AGGWALK_ABORT: 7990Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 8000Sstevel@tonic-gate 8010Sstevel@tonic-gate case DTRACE_AGGWALK_DENORMALIZE: 8020Sstevel@tonic-gate h->dtahe_data.dtada_normal = 1; 8030Sstevel@tonic-gate return (0); 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate case DTRACE_AGGWALK_NORMALIZE: 8060Sstevel@tonic-gate if (h->dtahe_data.dtada_normal == 0) { 8070Sstevel@tonic-gate h->dtahe_data.dtada_normal = 1; 8080Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 8090Sstevel@tonic-gate } 8100Sstevel@tonic-gate 8110Sstevel@tonic-gate return (0); 8120Sstevel@tonic-gate 8130Sstevel@tonic-gate case DTRACE_AGGWALK_REMOVE: { 8140Sstevel@tonic-gate dtrace_aggdata_t *aggdata = &h->dtahe_data; 8150Sstevel@tonic-gate int i, max_cpus = agp->dtat_maxcpu; 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate /* 8180Sstevel@tonic-gate * First, remove this hash entry from its hash chain. 8190Sstevel@tonic-gate */ 8200Sstevel@tonic-gate if (h->dtahe_prev != NULL) { 8210Sstevel@tonic-gate h->dtahe_prev->dtahe_next = h->dtahe_next; 8220Sstevel@tonic-gate } else { 8230Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 8240Sstevel@tonic-gate size_t ndx = h->dtahe_hashval % hash->dtah_size; 8250Sstevel@tonic-gate 8260Sstevel@tonic-gate assert(hash->dtah_hash[ndx] == h); 8270Sstevel@tonic-gate hash->dtah_hash[ndx] = h->dtahe_next; 8280Sstevel@tonic-gate } 8290Sstevel@tonic-gate 8300Sstevel@tonic-gate if (h->dtahe_next != NULL) 8310Sstevel@tonic-gate h->dtahe_next->dtahe_prev = h->dtahe_prev; 8320Sstevel@tonic-gate 8330Sstevel@tonic-gate /* 8340Sstevel@tonic-gate * Now remove it from the list of all hash entries. 8350Sstevel@tonic-gate */ 8360Sstevel@tonic-gate if (h->dtahe_prevall != NULL) { 8370Sstevel@tonic-gate h->dtahe_prevall->dtahe_nextall = h->dtahe_nextall; 8380Sstevel@tonic-gate } else { 8390Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate assert(hash->dtah_all == h); 8420Sstevel@tonic-gate hash->dtah_all = h->dtahe_nextall; 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate if (h->dtahe_nextall != NULL) 8460Sstevel@tonic-gate h->dtahe_nextall->dtahe_prevall = h->dtahe_prevall; 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate /* 8490Sstevel@tonic-gate * We're unlinked. We can safely destroy the data. 8500Sstevel@tonic-gate */ 8510Sstevel@tonic-gate if (aggdata->dtada_percpu != NULL) { 8520Sstevel@tonic-gate for (i = 0; i < max_cpus; i++) 8530Sstevel@tonic-gate free(aggdata->dtada_percpu[i]); 8540Sstevel@tonic-gate free(aggdata->dtada_percpu); 8550Sstevel@tonic-gate } 8560Sstevel@tonic-gate 8570Sstevel@tonic-gate free(aggdata->dtada_data); 8580Sstevel@tonic-gate free(h); 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate return (0); 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate default: 8640Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 8650Sstevel@tonic-gate } 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate return (0); 8680Sstevel@tonic-gate } 8690Sstevel@tonic-gate 8700Sstevel@tonic-gate int 8710Sstevel@tonic-gate dtrace_aggregate_walk(dtrace_hdl_t *dtp, dtrace_aggregate_f *func, void *arg) 8720Sstevel@tonic-gate { 8730Sstevel@tonic-gate dt_ahashent_t *h, *next; 8740Sstevel@tonic-gate dt_ahash_t *hash = &dtp->dt_aggregate.dtat_hash; 8750Sstevel@tonic-gate 8760Sstevel@tonic-gate for (h = hash->dtah_all; h != NULL; h = next) { 8770Sstevel@tonic-gate /* 8780Sstevel@tonic-gate * dt_aggwalk_rval() can potentially remove the current hash 8790Sstevel@tonic-gate * entry; we need to load the next hash entry before calling 8800Sstevel@tonic-gate * into it. 8810Sstevel@tonic-gate */ 8820Sstevel@tonic-gate next = h->dtahe_nextall; 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) 8850Sstevel@tonic-gate return (-1); 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate 8880Sstevel@tonic-gate return (0); 8890Sstevel@tonic-gate } 8900Sstevel@tonic-gate 8910Sstevel@tonic-gate static int 8920Sstevel@tonic-gate dt_aggregate_walk_sorted(dtrace_hdl_t *dtp, 8930Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg, 8940Sstevel@tonic-gate int (*sfunc)(const void *, const void *)) 8950Sstevel@tonic-gate { 8960Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 8970Sstevel@tonic-gate dt_ahashent_t *h, **sorted; 8980Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 8990Sstevel@tonic-gate size_t i, nentries = 0; 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) 9020Sstevel@tonic-gate nentries++; 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate sorted = malloc(nentries * sizeof (dt_ahashent_t *)); 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate if (sorted == NULL) 9070Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall) 9100Sstevel@tonic-gate sorted[i++] = h; 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate qsort(sorted, nentries, sizeof (dt_ahashent_t *), sfunc); 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate for (i = 0; i < nentries; i++) { 9150Sstevel@tonic-gate h = sorted[i]; 9160Sstevel@tonic-gate 9170Sstevel@tonic-gate if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) 9180Sstevel@tonic-gate return (-1); 9190Sstevel@tonic-gate } 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate free(sorted); 9220Sstevel@tonic-gate return (0); 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate int 9260Sstevel@tonic-gate dtrace_aggregate_walk_keysorted(dtrace_hdl_t *dtp, 9270Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 9280Sstevel@tonic-gate { 9290Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 9300Sstevel@tonic-gate arg, dt_aggregate_varkeycmp)); 9310Sstevel@tonic-gate } 9320Sstevel@tonic-gate 9330Sstevel@tonic-gate int 9340Sstevel@tonic-gate dtrace_aggregate_walk_valsorted(dtrace_hdl_t *dtp, 9350Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 9360Sstevel@tonic-gate { 9370Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 9380Sstevel@tonic-gate arg, dt_aggregate_varvalcmp)); 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate int 9420Sstevel@tonic-gate dtrace_aggregate_walk_keyvarsorted(dtrace_hdl_t *dtp, 9430Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 9440Sstevel@tonic-gate { 9450Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 9460Sstevel@tonic-gate arg, dt_aggregate_keyvarcmp)); 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate 9490Sstevel@tonic-gate int 9500Sstevel@tonic-gate dtrace_aggregate_walk_valvarsorted(dtrace_hdl_t *dtp, 9510Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 9520Sstevel@tonic-gate { 9530Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 9540Sstevel@tonic-gate arg, dt_aggregate_valvarcmp)); 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate int 9580Sstevel@tonic-gate dtrace_aggregate_walk_keyrevsorted(dtrace_hdl_t *dtp, 9590Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 9600Sstevel@tonic-gate { 9610Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 9620Sstevel@tonic-gate arg, dt_aggregate_varkeyrevcmp)); 9630Sstevel@tonic-gate } 9640Sstevel@tonic-gate 9650Sstevel@tonic-gate int 9660Sstevel@tonic-gate dtrace_aggregate_walk_valrevsorted(dtrace_hdl_t *dtp, 9670Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 9680Sstevel@tonic-gate { 9690Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 9700Sstevel@tonic-gate arg, dt_aggregate_varvalrevcmp)); 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate int 9740Sstevel@tonic-gate dtrace_aggregate_walk_keyvarrevsorted(dtrace_hdl_t *dtp, 9750Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 9760Sstevel@tonic-gate { 9770Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 9780Sstevel@tonic-gate arg, dt_aggregate_keyvarrevcmp)); 9790Sstevel@tonic-gate } 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate int 9820Sstevel@tonic-gate dtrace_aggregate_walk_valvarrevsorted(dtrace_hdl_t *dtp, 9830Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 9840Sstevel@tonic-gate { 9850Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 9860Sstevel@tonic-gate arg, dt_aggregate_valvarrevcmp)); 9870Sstevel@tonic-gate } 9880Sstevel@tonic-gate 9890Sstevel@tonic-gate int 9900Sstevel@tonic-gate dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp, 9910Sstevel@tonic-gate dtrace_aggregate_walk_f *func) 9920Sstevel@tonic-gate { 9930Sstevel@tonic-gate dt_print_aggdata_t pd; 9940Sstevel@tonic-gate 9950Sstevel@tonic-gate pd.dtpa_dtp = dtp; 9960Sstevel@tonic-gate pd.dtpa_fp = fp; 9970Sstevel@tonic-gate pd.dtpa_allunprint = 1; 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate if (func == NULL) 10000Sstevel@tonic-gate func = dtrace_aggregate_walk_valsorted; 10010Sstevel@tonic-gate 10020Sstevel@tonic-gate if ((*func)(dtp, dt_print_agg, &pd) == -1) 10030Sstevel@tonic-gate return (dt_set_errno(dtp, dtp->dt_errno)); 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate return (0); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate void 10090Sstevel@tonic-gate dtrace_aggregate_clear(dtrace_hdl_t *dtp) 10100Sstevel@tonic-gate { 10110Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 10120Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 10130Sstevel@tonic-gate dt_ahashent_t *h; 10140Sstevel@tonic-gate dtrace_aggdata_t *data; 10150Sstevel@tonic-gate dtrace_aggdesc_t *aggdesc; 10160Sstevel@tonic-gate dtrace_recdesc_t *rec; 10170Sstevel@tonic-gate int i, max_cpus = agp->dtat_maxcpu; 10180Sstevel@tonic-gate 10190Sstevel@tonic-gate for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) { 10200Sstevel@tonic-gate aggdesc = h->dtahe_data.dtada_desc; 10210Sstevel@tonic-gate rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1]; 10220Sstevel@tonic-gate data = &h->dtahe_data; 10230Sstevel@tonic-gate 10240Sstevel@tonic-gate bzero(&data->dtada_data[rec->dtrd_offset], rec->dtrd_size); 10250Sstevel@tonic-gate 10260Sstevel@tonic-gate if (data->dtada_percpu == NULL) 10270Sstevel@tonic-gate continue; 10280Sstevel@tonic-gate 10290Sstevel@tonic-gate for (i = 0; i < max_cpus; i++) 10300Sstevel@tonic-gate bzero(data->dtada_percpu[i], rec->dtrd_size); 10310Sstevel@tonic-gate } 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate void 10350Sstevel@tonic-gate dt_aggregate_destroy(dtrace_hdl_t *dtp) 10360Sstevel@tonic-gate { 10370Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 10380Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 10390Sstevel@tonic-gate dt_ahashent_t *h, *next; 10400Sstevel@tonic-gate dtrace_aggdata_t *aggdata; 10410Sstevel@tonic-gate int i, max_cpus = agp->dtat_maxcpu; 10420Sstevel@tonic-gate 10430Sstevel@tonic-gate if (hash->dtah_hash == NULL) { 10440Sstevel@tonic-gate assert(hash->dtah_all == NULL); 10450Sstevel@tonic-gate } else { 10460Sstevel@tonic-gate free(hash->dtah_hash); 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate for (h = hash->dtah_all; h != NULL; h = next) { 10490Sstevel@tonic-gate next = h->dtahe_nextall; 10500Sstevel@tonic-gate 10510Sstevel@tonic-gate aggdata = &h->dtahe_data; 10520Sstevel@tonic-gate 10530Sstevel@tonic-gate if (aggdata->dtada_percpu != NULL) { 10540Sstevel@tonic-gate for (i = 0; i < max_cpus; i++) 10550Sstevel@tonic-gate free(aggdata->dtada_percpu[i]); 10560Sstevel@tonic-gate free(aggdata->dtada_percpu); 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate 10590Sstevel@tonic-gate free(aggdata->dtada_data); 10600Sstevel@tonic-gate free(h); 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate hash->dtah_hash = NULL; 10640Sstevel@tonic-gate hash->dtah_all = NULL; 10650Sstevel@tonic-gate hash->dtah_size = 0; 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate free(agp->dtat_buf.dtbd_data); 10690Sstevel@tonic-gate free(agp->dtat_cpus); 10700Sstevel@tonic-gate } 1071