17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <stdlib.h> 307c478bd9Sstevel@tonic-gate #include <strings.h> 317c478bd9Sstevel@tonic-gate #include <errno.h> 327c478bd9Sstevel@tonic-gate #include <unistd.h> 337c478bd9Sstevel@tonic-gate #include <dt_impl.h> 347c478bd9Sstevel@tonic-gate #include <assert.h> 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate #define DTRACE_AHASHSIZE 32779 /* big 'ol prime */ 377c478bd9Sstevel@tonic-gate 387c478bd9Sstevel@tonic-gate static void 39*187eccf8Sbmc dt_aggregate_count(int64_t *existing, int64_t *new, size_t size) 407c478bd9Sstevel@tonic-gate { 417c478bd9Sstevel@tonic-gate int i; 427c478bd9Sstevel@tonic-gate 43*187eccf8Sbmc for (i = 0; i < size / sizeof (int64_t); i++) 447c478bd9Sstevel@tonic-gate existing[i] = existing[i] + new[i]; 457c478bd9Sstevel@tonic-gate } 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate static int 48*187eccf8Sbmc dt_aggregate_countcmp(int64_t *lhs, int64_t *rhs) 497c478bd9Sstevel@tonic-gate { 50*187eccf8Sbmc int64_t lvar = *lhs; 51*187eccf8Sbmc int64_t rvar = *rhs; 527c478bd9Sstevel@tonic-gate 537c478bd9Sstevel@tonic-gate if (lvar > rvar) 547c478bd9Sstevel@tonic-gate return (1); 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate if (lvar < rvar) 577c478bd9Sstevel@tonic-gate return (-1); 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate return (0); 607c478bd9Sstevel@tonic-gate } 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 637c478bd9Sstevel@tonic-gate static void 64*187eccf8Sbmc dt_aggregate_min(int64_t *existing, int64_t *new, size_t size) 657c478bd9Sstevel@tonic-gate { 667c478bd9Sstevel@tonic-gate if (*new < *existing) 677c478bd9Sstevel@tonic-gate *existing = *new; 687c478bd9Sstevel@tonic-gate } 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 717c478bd9Sstevel@tonic-gate static void 72*187eccf8Sbmc dt_aggregate_max(int64_t *existing, int64_t *new, size_t size) 737c478bd9Sstevel@tonic-gate { 747c478bd9Sstevel@tonic-gate if (*new > *existing) 757c478bd9Sstevel@tonic-gate *existing = *new; 767c478bd9Sstevel@tonic-gate } 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static int 79*187eccf8Sbmc dt_aggregate_averagecmp(int64_t *lhs, int64_t *rhs) 807c478bd9Sstevel@tonic-gate { 81*187eccf8Sbmc int64_t lavg = lhs[0] ? (lhs[1] / lhs[0]) : 0; 82*187eccf8Sbmc int64_t ravg = rhs[0] ? (rhs[1] / rhs[0]) : 0; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate if (lavg > ravg) 857c478bd9Sstevel@tonic-gate return (1); 867c478bd9Sstevel@tonic-gate 877c478bd9Sstevel@tonic-gate if (lavg < ravg) 887c478bd9Sstevel@tonic-gate return (-1); 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate return (0); 917c478bd9Sstevel@tonic-gate } 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 947c478bd9Sstevel@tonic-gate static void 95*187eccf8Sbmc dt_aggregate_lquantize(int64_t *existing, int64_t *new, size_t size) 967c478bd9Sstevel@tonic-gate { 97*187eccf8Sbmc int64_t arg = *existing++; 987c478bd9Sstevel@tonic-gate uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg); 997c478bd9Sstevel@tonic-gate int i; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate for (i = 0; i <= levels + 1; i++) 1027c478bd9Sstevel@tonic-gate existing[i] = existing[i] + new[i + 1]; 1037c478bd9Sstevel@tonic-gate } 1047c478bd9Sstevel@tonic-gate 105a1b5e537Sbmc static long double 106*187eccf8Sbmc dt_aggregate_lquantizedsum(int64_t *lquanta) 1077c478bd9Sstevel@tonic-gate { 108*187eccf8Sbmc int64_t arg = *lquanta++; 1097c478bd9Sstevel@tonic-gate int32_t base = DTRACE_LQUANTIZE_BASE(arg); 1107c478bd9Sstevel@tonic-gate uint16_t step = DTRACE_LQUANTIZE_STEP(arg); 1117c478bd9Sstevel@tonic-gate uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg), i; 112a1b5e537Sbmc long double total = (long double)lquanta[0] * (long double)(base - 1); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate for (i = 0; i < levels; base += step, i++) 115a1b5e537Sbmc total += (long double)lquanta[i + 1] * (long double)base; 1167c478bd9Sstevel@tonic-gate 117a1b5e537Sbmc return (total + (long double)lquanta[levels + 1] * 118a1b5e537Sbmc (long double)(base + 1)); 1197c478bd9Sstevel@tonic-gate } 1207c478bd9Sstevel@tonic-gate 121*187eccf8Sbmc static int64_t 122*187eccf8Sbmc dt_aggregate_lquantizedzero(int64_t *lquanta) 123*187eccf8Sbmc { 124*187eccf8Sbmc int64_t arg = *lquanta++; 125*187eccf8Sbmc int32_t base = DTRACE_LQUANTIZE_BASE(arg); 126*187eccf8Sbmc uint16_t step = DTRACE_LQUANTIZE_STEP(arg); 127*187eccf8Sbmc uint16_t levels = DTRACE_LQUANTIZE_LEVELS(arg), i; 128*187eccf8Sbmc 129*187eccf8Sbmc if (base - 1 == 0) 130*187eccf8Sbmc return (lquanta[0]); 131*187eccf8Sbmc 132*187eccf8Sbmc for (i = 0; i < levels; base += step, i++) { 133*187eccf8Sbmc if (base != 0) 134*187eccf8Sbmc continue; 135*187eccf8Sbmc 136*187eccf8Sbmc return (lquanta[i + 1]); 137*187eccf8Sbmc } 138*187eccf8Sbmc 139*187eccf8Sbmc if (base + 1 == 0) 140*187eccf8Sbmc return (lquanta[levels + 1]); 141*187eccf8Sbmc 142*187eccf8Sbmc return (0); 143*187eccf8Sbmc } 144*187eccf8Sbmc 1457c478bd9Sstevel@tonic-gate static int 146*187eccf8Sbmc dt_aggregate_lquantizedcmp(int64_t *lhs, int64_t *rhs) 1477c478bd9Sstevel@tonic-gate { 148a1b5e537Sbmc long double lsum = dt_aggregate_lquantizedsum(lhs); 149a1b5e537Sbmc long double rsum = dt_aggregate_lquantizedsum(rhs); 150*187eccf8Sbmc int64_t lzero, rzero; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate if (lsum > rsum) 1537c478bd9Sstevel@tonic-gate return (1); 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate if (lsum < rsum) 1567c478bd9Sstevel@tonic-gate return (-1); 1577c478bd9Sstevel@tonic-gate 158*187eccf8Sbmc /* 159*187eccf8Sbmc * If they're both equal, then we will compare based on the weights at 160*187eccf8Sbmc * zero. If the weights at zero are equal (or if zero is not within 161*187eccf8Sbmc * the range of the linear quantization), then this will be judged a 162*187eccf8Sbmc * tie and will be resolved based on the key comparison. 163*187eccf8Sbmc */ 164*187eccf8Sbmc lzero = dt_aggregate_lquantizedzero(lhs); 165*187eccf8Sbmc rzero = dt_aggregate_lquantizedzero(rhs); 166*187eccf8Sbmc 167*187eccf8Sbmc if (lzero > rzero) 168*187eccf8Sbmc return (1); 169*187eccf8Sbmc 170*187eccf8Sbmc if (lzero < rzero) 171*187eccf8Sbmc return (-1); 172*187eccf8Sbmc 1737c478bd9Sstevel@tonic-gate return (0); 1747c478bd9Sstevel@tonic-gate } 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate static int 177*187eccf8Sbmc dt_aggregate_quantizedcmp(int64_t *lhs, int64_t *rhs) 1787c478bd9Sstevel@tonic-gate { 1797c478bd9Sstevel@tonic-gate int nbuckets = DTRACE_QUANTIZE_NBUCKETS, i; 180a1b5e537Sbmc long double ltotal = 0, rtotal = 0; 181*187eccf8Sbmc int64_t lzero, rzero; 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate for (i = 0; i < nbuckets; i++) { 1847c478bd9Sstevel@tonic-gate int64_t bucketval = DTRACE_QUANTIZE_BUCKETVAL(i); 1857c478bd9Sstevel@tonic-gate 186*187eccf8Sbmc if (bucketval == 0) { 187*187eccf8Sbmc lzero = lhs[i]; 188*187eccf8Sbmc rzero = rhs[i]; 189*187eccf8Sbmc } 190*187eccf8Sbmc 191a1b5e537Sbmc ltotal += (long double)bucketval * (long double)lhs[i]; 192a1b5e537Sbmc rtotal += (long double)bucketval * (long double)rhs[i]; 1937c478bd9Sstevel@tonic-gate } 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate if (ltotal > rtotal) 1967c478bd9Sstevel@tonic-gate return (1); 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate if (ltotal < rtotal) 1997c478bd9Sstevel@tonic-gate return (-1); 2007c478bd9Sstevel@tonic-gate 201*187eccf8Sbmc /* 202*187eccf8Sbmc * If they're both equal, then we will compare based on the weights at 203*187eccf8Sbmc * zero. If the weights at zero are equal, then this will be judged a 204*187eccf8Sbmc * tie and will be resolved based on the key comparison. 205*187eccf8Sbmc */ 206*187eccf8Sbmc if (lzero > rzero) 207*187eccf8Sbmc return (1); 208*187eccf8Sbmc 209*187eccf8Sbmc if (lzero < rzero) 210*187eccf8Sbmc return (-1); 211*187eccf8Sbmc 2127c478bd9Sstevel@tonic-gate return (0); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate 215a1b5e537Sbmc static void 216a1b5e537Sbmc dt_aggregate_usym(dtrace_hdl_t *dtp, uint64_t *data) 217a1b5e537Sbmc { 218a1b5e537Sbmc uint64_t pid = data[0]; 219a1b5e537Sbmc uint64_t *pc = &data[1]; 220a1b5e537Sbmc struct ps_prochandle *P; 221a1b5e537Sbmc GElf_Sym sym; 222a1b5e537Sbmc 223a1b5e537Sbmc if (dtp->dt_vector != NULL) 224a1b5e537Sbmc return; 225a1b5e537Sbmc 226a1b5e537Sbmc if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL) 227a1b5e537Sbmc return; 228a1b5e537Sbmc 229a1b5e537Sbmc dt_proc_lock(dtp, P); 230a1b5e537Sbmc 231a1b5e537Sbmc if (Plookup_by_addr(P, *pc, NULL, 0, &sym) == 0) 232a1b5e537Sbmc *pc = sym.st_value; 233a1b5e537Sbmc 234a1b5e537Sbmc dt_proc_unlock(dtp, P); 235a1b5e537Sbmc dt_proc_release(dtp, P); 236a1b5e537Sbmc } 237a1b5e537Sbmc 238a1b5e537Sbmc static void 239a1b5e537Sbmc dt_aggregate_umod(dtrace_hdl_t *dtp, uint64_t *data) 240a1b5e537Sbmc { 241a1b5e537Sbmc uint64_t pid = data[0]; 242a1b5e537Sbmc uint64_t *pc = &data[1]; 243a1b5e537Sbmc struct ps_prochandle *P; 244a1b5e537Sbmc const prmap_t *map; 245a1b5e537Sbmc 246a1b5e537Sbmc if (dtp->dt_vector != NULL) 247a1b5e537Sbmc return; 248a1b5e537Sbmc 249a1b5e537Sbmc if ((P = dt_proc_grab(dtp, pid, PGRAB_RDONLY | PGRAB_FORCE, 0)) == NULL) 250a1b5e537Sbmc return; 251a1b5e537Sbmc 252a1b5e537Sbmc dt_proc_lock(dtp, P); 253a1b5e537Sbmc 254a1b5e537Sbmc if ((map = Paddr_to_map(P, *pc)) != NULL) 255a1b5e537Sbmc *pc = map->pr_vaddr; 256a1b5e537Sbmc 257a1b5e537Sbmc dt_proc_unlock(dtp, P); 258a1b5e537Sbmc dt_proc_release(dtp, P); 259a1b5e537Sbmc } 260a1b5e537Sbmc 261a1b5e537Sbmc static void 262a1b5e537Sbmc dt_aggregate_sym(dtrace_hdl_t *dtp, uint64_t *data) 263a1b5e537Sbmc { 264a1b5e537Sbmc GElf_Sym sym; 265a1b5e537Sbmc uint64_t *pc = data; 266a1b5e537Sbmc 267a1b5e537Sbmc if (dtrace_lookup_by_addr(dtp, *pc, &sym, NULL) == 0) 268a1b5e537Sbmc *pc = sym.st_value; 269a1b5e537Sbmc } 270a1b5e537Sbmc 271a1b5e537Sbmc static void 272a1b5e537Sbmc dt_aggregate_mod(dtrace_hdl_t *dtp, uint64_t *data) 273a1b5e537Sbmc { 274a1b5e537Sbmc uint64_t *pc = data; 275a1b5e537Sbmc dt_module_t *dmp; 276a1b5e537Sbmc 277a1b5e537Sbmc if (dtp->dt_vector != NULL) { 278a1b5e537Sbmc /* 279a1b5e537Sbmc * We don't have a way of just getting the module for a 280a1b5e537Sbmc * vectored open, and it doesn't seem to be worth defining 281a1b5e537Sbmc * one. This means that use of mod() won't get true 282a1b5e537Sbmc * aggregation in the postmortem case (some modules may 283a1b5e537Sbmc * appear more than once in aggregation output). It seems 284a1b5e537Sbmc * unlikely that anyone will ever notice or care... 285a1b5e537Sbmc */ 286a1b5e537Sbmc return; 287a1b5e537Sbmc } 288a1b5e537Sbmc 289a1b5e537Sbmc for (dmp = dt_list_next(&dtp->dt_modlist); dmp != NULL; 290a1b5e537Sbmc dmp = dt_list_next(dmp)) { 291a1b5e537Sbmc if (*pc - dmp->dm_text_va < dmp->dm_text_size) { 292a1b5e537Sbmc *pc = dmp->dm_text_va; 293a1b5e537Sbmc return; 294a1b5e537Sbmc } 295a1b5e537Sbmc } 296a1b5e537Sbmc } 297a1b5e537Sbmc 2987c478bd9Sstevel@tonic-gate static int 2997c478bd9Sstevel@tonic-gate dt_aggregate_snap_cpu(dtrace_hdl_t *dtp, processorid_t cpu) 3007c478bd9Sstevel@tonic-gate { 3017c478bd9Sstevel@tonic-gate dtrace_epid_t id; 3027c478bd9Sstevel@tonic-gate uint64_t hashval; 3037c478bd9Sstevel@tonic-gate size_t offs, roffs, size, ndx; 3047c478bd9Sstevel@tonic-gate int i, j, rval; 3057c478bd9Sstevel@tonic-gate caddr_t addr, data; 3067c478bd9Sstevel@tonic-gate dtrace_recdesc_t *rec; 3077c478bd9Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 3087c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *agg; 3097c478bd9Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 3107c478bd9Sstevel@tonic-gate dt_ahashent_t *h; 3117c478bd9Sstevel@tonic-gate dtrace_bufdesc_t b = agp->dtat_buf, *buf = &b; 3127c478bd9Sstevel@tonic-gate dtrace_aggdata_t *aggdata; 3137c478bd9Sstevel@tonic-gate int flags = agp->dtat_flags; 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate buf->dtbd_cpu = cpu; 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate if (dt_ioctl(dtp, DTRACEIOC_AGGSNAP, buf) == -1) { 3187c478bd9Sstevel@tonic-gate if (errno == ENOENT) { 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * If that failed with ENOENT, it may be because the 3217c478bd9Sstevel@tonic-gate * CPU was unconfigured. This is okay; we'll just 3227c478bd9Sstevel@tonic-gate * do nothing but return success. 3237c478bd9Sstevel@tonic-gate */ 3247c478bd9Sstevel@tonic-gate return (0); 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 3277c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate if (buf->dtbd_drops != 0) { 3317c478bd9Sstevel@tonic-gate if (dt_handle_cpudrop(dtp, cpu, 3327c478bd9Sstevel@tonic-gate DTRACEDROP_AGGREGATION, buf->dtbd_drops) == -1) 3337c478bd9Sstevel@tonic-gate return (-1); 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate if (buf->dtbd_size == 0) 3377c478bd9Sstevel@tonic-gate return (0); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if (hash->dtah_hash == NULL) { 3407c478bd9Sstevel@tonic-gate size_t size; 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate hash->dtah_size = DTRACE_AHASHSIZE; 3437c478bd9Sstevel@tonic-gate size = hash->dtah_size * sizeof (dt_ahashent_t *); 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate if ((hash->dtah_hash = malloc(size)) == NULL) 3467c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate bzero(hash->dtah_hash, size); 3497c478bd9Sstevel@tonic-gate } 3507c478bd9Sstevel@tonic-gate 3517c478bd9Sstevel@tonic-gate for (offs = 0; offs < buf->dtbd_size; ) { 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * We're guaranteed to have an ID. 3547c478bd9Sstevel@tonic-gate */ 3557c478bd9Sstevel@tonic-gate id = *((dtrace_epid_t *)((uintptr_t)buf->dtbd_data + 3567c478bd9Sstevel@tonic-gate (uintptr_t)offs)); 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate if (id == DTRACE_AGGIDNONE) { 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * This is filler to assure proper alignment of the 3617c478bd9Sstevel@tonic-gate * next record; we simply ignore it. 3627c478bd9Sstevel@tonic-gate */ 3637c478bd9Sstevel@tonic-gate offs += sizeof (id); 3647c478bd9Sstevel@tonic-gate continue; 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate if ((rval = dt_aggid_lookup(dtp, id, &agg)) != 0) 3687c478bd9Sstevel@tonic-gate return (rval); 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate addr = buf->dtbd_data + offs; 3717c478bd9Sstevel@tonic-gate size = agg->dtagd_size; 3727c478bd9Sstevel@tonic-gate hashval = 0; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate for (j = 0; j < agg->dtagd_nrecs - 1; j++) { 3757c478bd9Sstevel@tonic-gate rec = &agg->dtagd_rec[j]; 3767c478bd9Sstevel@tonic-gate roffs = rec->dtrd_offset; 3777c478bd9Sstevel@tonic-gate 378a1b5e537Sbmc switch (rec->dtrd_action) { 379a1b5e537Sbmc case DTRACEACT_USYM: 380a1b5e537Sbmc dt_aggregate_usym(dtp, 381a1b5e537Sbmc /* LINTED - alignment */ 382a1b5e537Sbmc (uint64_t *)&addr[roffs]); 383a1b5e537Sbmc break; 384a1b5e537Sbmc 385a1b5e537Sbmc case DTRACEACT_UMOD: 386a1b5e537Sbmc dt_aggregate_umod(dtp, 387a1b5e537Sbmc /* LINTED - alignment */ 388a1b5e537Sbmc (uint64_t *)&addr[roffs]); 389a1b5e537Sbmc break; 390a1b5e537Sbmc 391a1b5e537Sbmc case DTRACEACT_SYM: 392a1b5e537Sbmc /* LINTED - alignment */ 393a1b5e537Sbmc dt_aggregate_sym(dtp, (uint64_t *)&addr[roffs]); 394a1b5e537Sbmc break; 395a1b5e537Sbmc 396a1b5e537Sbmc case DTRACEACT_MOD: 397a1b5e537Sbmc /* LINTED - alignment */ 398a1b5e537Sbmc dt_aggregate_mod(dtp, (uint64_t *)&addr[roffs]); 399a1b5e537Sbmc break; 400a1b5e537Sbmc 401a1b5e537Sbmc default: 402a1b5e537Sbmc break; 403a1b5e537Sbmc } 404a1b5e537Sbmc 4057c478bd9Sstevel@tonic-gate for (i = 0; i < rec->dtrd_size; i++) 4067c478bd9Sstevel@tonic-gate hashval += addr[roffs + i]; 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate ndx = hashval % hash->dtah_size; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate for (h = hash->dtah_hash[ndx]; h != NULL; h = h->dtahe_next) { 4127c478bd9Sstevel@tonic-gate if (h->dtahe_hashval != hashval) 4137c478bd9Sstevel@tonic-gate continue; 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate if (h->dtahe_size != size) 4167c478bd9Sstevel@tonic-gate continue; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate aggdata = &h->dtahe_data; 4197c478bd9Sstevel@tonic-gate data = aggdata->dtada_data; 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate for (j = 0; j < agg->dtagd_nrecs - 1; j++) { 4227c478bd9Sstevel@tonic-gate rec = &agg->dtagd_rec[j]; 4237c478bd9Sstevel@tonic-gate roffs = rec->dtrd_offset; 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate for (i = 0; i < rec->dtrd_size; i++) 4267c478bd9Sstevel@tonic-gate if (addr[roffs + i] != data[roffs + i]) 4277c478bd9Sstevel@tonic-gate goto hashnext; 4287c478bd9Sstevel@tonic-gate } 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate /* 4317c478bd9Sstevel@tonic-gate * We found it. Now we need to apply the aggregating 4327c478bd9Sstevel@tonic-gate * action on the data here. 4337c478bd9Sstevel@tonic-gate */ 4347c478bd9Sstevel@tonic-gate rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1]; 4357c478bd9Sstevel@tonic-gate roffs = rec->dtrd_offset; 4367c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 437*187eccf8Sbmc h->dtahe_aggregate((int64_t *)&data[roffs], 4387c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 439*187eccf8Sbmc (int64_t *)&addr[roffs], rec->dtrd_size); 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * If we're keeping per CPU data, apply the aggregating 4437c478bd9Sstevel@tonic-gate * action there as well. 4447c478bd9Sstevel@tonic-gate */ 4457c478bd9Sstevel@tonic-gate if (aggdata->dtada_percpu != NULL) { 4467c478bd9Sstevel@tonic-gate data = aggdata->dtada_percpu[cpu]; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 449*187eccf8Sbmc h->dtahe_aggregate((int64_t *)data, 4507c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 451*187eccf8Sbmc (int64_t *)&addr[roffs], rec->dtrd_size); 4527c478bd9Sstevel@tonic-gate } 4537c478bd9Sstevel@tonic-gate 4547c478bd9Sstevel@tonic-gate goto bufnext; 4557c478bd9Sstevel@tonic-gate hashnext: 4567c478bd9Sstevel@tonic-gate continue; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * If we're here, we couldn't find an entry for this record. 4617c478bd9Sstevel@tonic-gate */ 4627c478bd9Sstevel@tonic-gate if ((h = malloc(sizeof (dt_ahashent_t))) == NULL) 4637c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 4647c478bd9Sstevel@tonic-gate bzero(h, sizeof (dt_ahashent_t)); 4657c478bd9Sstevel@tonic-gate aggdata = &h->dtahe_data; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if ((aggdata->dtada_data = malloc(size)) == NULL) { 4687c478bd9Sstevel@tonic-gate free(h); 4697c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate bcopy(addr, aggdata->dtada_data, size); 4737c478bd9Sstevel@tonic-gate aggdata->dtada_size = size; 4747c478bd9Sstevel@tonic-gate aggdata->dtada_desc = agg; 4757c478bd9Sstevel@tonic-gate aggdata->dtada_handle = dtp; 4767c478bd9Sstevel@tonic-gate (void) dt_epid_lookup(dtp, agg->dtagd_epid, 4777c478bd9Sstevel@tonic-gate &aggdata->dtada_edesc, &aggdata->dtada_pdesc); 4787c478bd9Sstevel@tonic-gate aggdata->dtada_normal = 1; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate h->dtahe_hashval = hashval; 4817c478bd9Sstevel@tonic-gate h->dtahe_size = size; 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate rec = &agg->dtagd_rec[agg->dtagd_nrecs - 1]; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate if (flags & DTRACE_A_PERCPU) { 4867c478bd9Sstevel@tonic-gate int max_cpus = agp->dtat_maxcpu; 4877c478bd9Sstevel@tonic-gate caddr_t *percpu = malloc(max_cpus * sizeof (caddr_t)); 4887c478bd9Sstevel@tonic-gate 4897c478bd9Sstevel@tonic-gate if (percpu == NULL) { 4907c478bd9Sstevel@tonic-gate free(aggdata->dtada_data); 4917c478bd9Sstevel@tonic-gate free(h); 4927c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 4937c478bd9Sstevel@tonic-gate } 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate for (j = 0; j < max_cpus; j++) { 4967c478bd9Sstevel@tonic-gate percpu[j] = malloc(rec->dtrd_size); 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate if (percpu[j] == NULL) { 4997c478bd9Sstevel@tonic-gate while (--j >= 0) 5007c478bd9Sstevel@tonic-gate free(percpu[j]); 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate free(aggdata->dtada_data); 5037c478bd9Sstevel@tonic-gate free(h); 5047c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 5057c478bd9Sstevel@tonic-gate } 5067c478bd9Sstevel@tonic-gate 5077c478bd9Sstevel@tonic-gate if (j == cpu) { 5087c478bd9Sstevel@tonic-gate bcopy(&addr[rec->dtrd_offset], 5097c478bd9Sstevel@tonic-gate percpu[j], rec->dtrd_size); 5107c478bd9Sstevel@tonic-gate } else { 5117c478bd9Sstevel@tonic-gate bzero(percpu[j], rec->dtrd_size); 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate aggdata->dtada_percpu = percpu; 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate switch (rec->dtrd_action) { 5197c478bd9Sstevel@tonic-gate case DTRACEAGG_MIN: 5207c478bd9Sstevel@tonic-gate h->dtahe_aggregate = dt_aggregate_min; 5217c478bd9Sstevel@tonic-gate break; 5227c478bd9Sstevel@tonic-gate 5237c478bd9Sstevel@tonic-gate case DTRACEAGG_MAX: 5247c478bd9Sstevel@tonic-gate h->dtahe_aggregate = dt_aggregate_max; 5257c478bd9Sstevel@tonic-gate break; 5267c478bd9Sstevel@tonic-gate 5277c478bd9Sstevel@tonic-gate case DTRACEAGG_LQUANTIZE: 5287c478bd9Sstevel@tonic-gate h->dtahe_aggregate = dt_aggregate_lquantize; 5297c478bd9Sstevel@tonic-gate break; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate case DTRACEAGG_COUNT: 5327c478bd9Sstevel@tonic-gate case DTRACEAGG_SUM: 5337c478bd9Sstevel@tonic-gate case DTRACEAGG_AVG: 5347c478bd9Sstevel@tonic-gate case DTRACEAGG_QUANTIZE: 5357c478bd9Sstevel@tonic-gate h->dtahe_aggregate = dt_aggregate_count; 5367c478bd9Sstevel@tonic-gate break; 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate default: 5397c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADAGG)); 5407c478bd9Sstevel@tonic-gate } 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate if (hash->dtah_hash[ndx] != NULL) 5437c478bd9Sstevel@tonic-gate hash->dtah_hash[ndx]->dtahe_prev = h; 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate h->dtahe_next = hash->dtah_hash[ndx]; 5467c478bd9Sstevel@tonic-gate hash->dtah_hash[ndx] = h; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate if (hash->dtah_all != NULL) 5497c478bd9Sstevel@tonic-gate hash->dtah_all->dtahe_prevall = h; 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate h->dtahe_nextall = hash->dtah_all; 5527c478bd9Sstevel@tonic-gate hash->dtah_all = h; 5537c478bd9Sstevel@tonic-gate bufnext: 5547c478bd9Sstevel@tonic-gate offs += agg->dtagd_size; 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate return (0); 5587c478bd9Sstevel@tonic-gate } 5597c478bd9Sstevel@tonic-gate 5607c478bd9Sstevel@tonic-gate int 5617c478bd9Sstevel@tonic-gate dtrace_aggregate_snap(dtrace_hdl_t *dtp) 5627c478bd9Sstevel@tonic-gate { 5637c478bd9Sstevel@tonic-gate int i, rval; 5647c478bd9Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 5657c478bd9Sstevel@tonic-gate hrtime_t now = gethrtime(); 5667c478bd9Sstevel@tonic-gate dtrace_optval_t interval = dtp->dt_options[DTRACEOPT_AGGRATE]; 5677c478bd9Sstevel@tonic-gate 5687c478bd9Sstevel@tonic-gate if (dtp->dt_lastagg != 0) { 5697c478bd9Sstevel@tonic-gate if (now - dtp->dt_lastagg < interval) 5707c478bd9Sstevel@tonic-gate return (0); 5717c478bd9Sstevel@tonic-gate 5727c478bd9Sstevel@tonic-gate dtp->dt_lastagg += interval; 5737c478bd9Sstevel@tonic-gate } else { 5747c478bd9Sstevel@tonic-gate dtp->dt_lastagg = now; 5757c478bd9Sstevel@tonic-gate } 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate if (!dtp->dt_active) 5787c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EINVAL)); 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate if (agp->dtat_buf.dtbd_size == 0) 5817c478bd9Sstevel@tonic-gate return (0); 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate for (i = 0; i < agp->dtat_ncpus; i++) { 5847c478bd9Sstevel@tonic-gate if (rval = dt_aggregate_snap_cpu(dtp, agp->dtat_cpus[i])) 5857c478bd9Sstevel@tonic-gate return (rval); 5867c478bd9Sstevel@tonic-gate } 5877c478bd9Sstevel@tonic-gate 5887c478bd9Sstevel@tonic-gate return (0); 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate static int 5927c478bd9Sstevel@tonic-gate dt_aggregate_hashcmp(const void *lhs, const void *rhs) 5937c478bd9Sstevel@tonic-gate { 5947c478bd9Sstevel@tonic-gate dt_ahashent_t *lh = *((dt_ahashent_t **)lhs); 5957c478bd9Sstevel@tonic-gate dt_ahashent_t *rh = *((dt_ahashent_t **)rhs); 5967c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc; 5977c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc; 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate if (lagg->dtagd_nrecs < ragg->dtagd_nrecs) 6007c478bd9Sstevel@tonic-gate return (-1); 6017c478bd9Sstevel@tonic-gate 6027c478bd9Sstevel@tonic-gate if (lagg->dtagd_nrecs > ragg->dtagd_nrecs) 6037c478bd9Sstevel@tonic-gate return (1); 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate return (0); 6067c478bd9Sstevel@tonic-gate } 6077c478bd9Sstevel@tonic-gate 6087c478bd9Sstevel@tonic-gate static int 6097c478bd9Sstevel@tonic-gate dt_aggregate_varcmp(const void *lhs, const void *rhs) 6107c478bd9Sstevel@tonic-gate { 6117c478bd9Sstevel@tonic-gate dt_ahashent_t *lh = *((dt_ahashent_t **)lhs); 6127c478bd9Sstevel@tonic-gate dt_ahashent_t *rh = *((dt_ahashent_t **)rhs); 6137c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc; 6147c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc; 6157c478bd9Sstevel@tonic-gate caddr_t ldata = lh->dtahe_data.dtada_data; 6167c478bd9Sstevel@tonic-gate caddr_t rdata = rh->dtahe_data.dtada_data; 6177c478bd9Sstevel@tonic-gate dtrace_recdesc_t *lrec, *rrec; 6187c478bd9Sstevel@tonic-gate uint64_t lid, rid; 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate /* 6217c478bd9Sstevel@tonic-gate * We know that we have a compiler-generated ID as the first record. 6227c478bd9Sstevel@tonic-gate */ 6237c478bd9Sstevel@tonic-gate lrec = lagg->dtagd_rec; 6247c478bd9Sstevel@tonic-gate rrec = ragg->dtagd_rec; 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate lid = *((uint64_t *)(uintptr_t)(ldata + lrec->dtrd_offset)); 6277c478bd9Sstevel@tonic-gate rid = *((uint64_t *)(uintptr_t)(rdata + rrec->dtrd_offset)); 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate if (lid < rid) 6307c478bd9Sstevel@tonic-gate return (-1); 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate if (lid > rid) 6337c478bd9Sstevel@tonic-gate return (1); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate return (0); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate 6387c478bd9Sstevel@tonic-gate static int 6397c478bd9Sstevel@tonic-gate dt_aggregate_keycmp(const void *lhs, const void *rhs) 6407c478bd9Sstevel@tonic-gate { 6417c478bd9Sstevel@tonic-gate dt_ahashent_t *lh = *((dt_ahashent_t **)lhs); 6427c478bd9Sstevel@tonic-gate dt_ahashent_t *rh = *((dt_ahashent_t **)rhs); 6437c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc; 6447c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc; 6457c478bd9Sstevel@tonic-gate dtrace_recdesc_t *lrec, *rrec; 6467c478bd9Sstevel@tonic-gate char *ldata, *rdata; 647a67d40caSbmc int rval, i, j; 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0) 6507c478bd9Sstevel@tonic-gate return (rval); 6517c478bd9Sstevel@tonic-gate 6527c478bd9Sstevel@tonic-gate for (i = 1; i < lagg->dtagd_nrecs - 1; i++) { 6537c478bd9Sstevel@tonic-gate uint64_t lval, rval; 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate lrec = &lagg->dtagd_rec[i]; 6567c478bd9Sstevel@tonic-gate rrec = &ragg->dtagd_rec[i]; 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate ldata = lh->dtahe_data.dtada_data + lrec->dtrd_offset; 6597c478bd9Sstevel@tonic-gate rdata = rh->dtahe_data.dtada_data + rrec->dtrd_offset; 6607c478bd9Sstevel@tonic-gate 6617c478bd9Sstevel@tonic-gate if (lrec->dtrd_size < rrec->dtrd_size) 6627c478bd9Sstevel@tonic-gate return (-1); 6637c478bd9Sstevel@tonic-gate 6647c478bd9Sstevel@tonic-gate if (lrec->dtrd_size > rrec->dtrd_size) 6657c478bd9Sstevel@tonic-gate return (1); 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate switch (lrec->dtrd_size) { 6687c478bd9Sstevel@tonic-gate case sizeof (uint64_t): 6697c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 6707c478bd9Sstevel@tonic-gate lval = *((uint64_t *)ldata); 6717c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 6727c478bd9Sstevel@tonic-gate rval = *((uint64_t *)rdata); 6737c478bd9Sstevel@tonic-gate break; 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate case sizeof (uint32_t): 6767c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 6777c478bd9Sstevel@tonic-gate lval = *((uint32_t *)ldata); 6787c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 6797c478bd9Sstevel@tonic-gate rval = *((uint32_t *)rdata); 6807c478bd9Sstevel@tonic-gate break; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate case sizeof (uint16_t): 6837c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 6847c478bd9Sstevel@tonic-gate lval = *((uint16_t *)ldata); 6857c478bd9Sstevel@tonic-gate /* LINTED - alignment */ 6867c478bd9Sstevel@tonic-gate rval = *((uint16_t *)rdata); 6877c478bd9Sstevel@tonic-gate break; 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate case sizeof (uint8_t): 6907c478bd9Sstevel@tonic-gate lval = *((uint8_t *)ldata); 6917c478bd9Sstevel@tonic-gate rval = *((uint8_t *)rdata); 6927c478bd9Sstevel@tonic-gate break; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate default: 695a67d40caSbmc for (j = 0; j < lrec->dtrd_size; j++) { 696a67d40caSbmc lval = ((uint8_t *)ldata)[j]; 697a67d40caSbmc rval = ((uint8_t *)rdata)[j]; 6987c478bd9Sstevel@tonic-gate 6997c478bd9Sstevel@tonic-gate if (lval < rval) 7007c478bd9Sstevel@tonic-gate return (-1); 7017c478bd9Sstevel@tonic-gate 7027c478bd9Sstevel@tonic-gate if (lval > rval) 7037c478bd9Sstevel@tonic-gate return (1); 7047c478bd9Sstevel@tonic-gate } 7057c478bd9Sstevel@tonic-gate 7067c478bd9Sstevel@tonic-gate continue; 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate 7097c478bd9Sstevel@tonic-gate if (lval < rval) 7107c478bd9Sstevel@tonic-gate return (-1); 7117c478bd9Sstevel@tonic-gate 7127c478bd9Sstevel@tonic-gate if (lval > rval) 7137c478bd9Sstevel@tonic-gate return (1); 7147c478bd9Sstevel@tonic-gate } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate return (0); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate static int 7207c478bd9Sstevel@tonic-gate dt_aggregate_valcmp(const void *lhs, const void *rhs) 7217c478bd9Sstevel@tonic-gate { 7227c478bd9Sstevel@tonic-gate dt_ahashent_t *lh = *((dt_ahashent_t **)lhs); 7237c478bd9Sstevel@tonic-gate dt_ahashent_t *rh = *((dt_ahashent_t **)rhs); 7247c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *lagg = lh->dtahe_data.dtada_desc; 7257c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *ragg = rh->dtahe_data.dtada_desc; 7267c478bd9Sstevel@tonic-gate caddr_t ldata = lh->dtahe_data.dtada_data; 7277c478bd9Sstevel@tonic-gate caddr_t rdata = rh->dtahe_data.dtada_data; 7287c478bd9Sstevel@tonic-gate dtrace_recdesc_t *lrec, *rrec; 729*187eccf8Sbmc int64_t *laddr, *raddr; 7307c478bd9Sstevel@tonic-gate int rval, i; 7317c478bd9Sstevel@tonic-gate 7327c478bd9Sstevel@tonic-gate if ((rval = dt_aggregate_hashcmp(lhs, rhs)) != 0) 7337c478bd9Sstevel@tonic-gate return (rval); 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate if (lagg->dtagd_nrecs < ragg->dtagd_nrecs) 7367c478bd9Sstevel@tonic-gate return (-1); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate if (lagg->dtagd_nrecs > ragg->dtagd_nrecs) 7397c478bd9Sstevel@tonic-gate return (1); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate for (i = 0; i < lagg->dtagd_nrecs; i++) { 7427c478bd9Sstevel@tonic-gate lrec = &lagg->dtagd_rec[i]; 7437c478bd9Sstevel@tonic-gate rrec = &ragg->dtagd_rec[i]; 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate if (lrec->dtrd_offset < rrec->dtrd_offset) 7467c478bd9Sstevel@tonic-gate return (-1); 7477c478bd9Sstevel@tonic-gate 7487c478bd9Sstevel@tonic-gate if (lrec->dtrd_offset > rrec->dtrd_offset) 7497c478bd9Sstevel@tonic-gate return (1); 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate if (lrec->dtrd_action < rrec->dtrd_action) 7527c478bd9Sstevel@tonic-gate return (-1); 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate if (lrec->dtrd_action > rrec->dtrd_action) 7557c478bd9Sstevel@tonic-gate return (1); 7567c478bd9Sstevel@tonic-gate } 7577c478bd9Sstevel@tonic-gate 758*187eccf8Sbmc laddr = (int64_t *)(uintptr_t)(ldata + lrec->dtrd_offset); 759*187eccf8Sbmc raddr = (int64_t *)(uintptr_t)(rdata + rrec->dtrd_offset); 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate switch (lrec->dtrd_action) { 7627c478bd9Sstevel@tonic-gate case DTRACEAGG_AVG: 7637c478bd9Sstevel@tonic-gate rval = dt_aggregate_averagecmp(laddr, raddr); 7647c478bd9Sstevel@tonic-gate break; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate case DTRACEAGG_QUANTIZE: 7677c478bd9Sstevel@tonic-gate rval = dt_aggregate_quantizedcmp(laddr, raddr); 7687c478bd9Sstevel@tonic-gate break; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate case DTRACEAGG_LQUANTIZE: 7717c478bd9Sstevel@tonic-gate rval = dt_aggregate_lquantizedcmp(laddr, raddr); 7727c478bd9Sstevel@tonic-gate break; 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate case DTRACEAGG_COUNT: 7757c478bd9Sstevel@tonic-gate case DTRACEAGG_SUM: 7767c478bd9Sstevel@tonic-gate case DTRACEAGG_MIN: 7777c478bd9Sstevel@tonic-gate case DTRACEAGG_MAX: 7787c478bd9Sstevel@tonic-gate rval = dt_aggregate_countcmp(laddr, raddr); 7797c478bd9Sstevel@tonic-gate break; 7807c478bd9Sstevel@tonic-gate 7817c478bd9Sstevel@tonic-gate default: 7827c478bd9Sstevel@tonic-gate assert(0); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate if (rval != 0) 7867c478bd9Sstevel@tonic-gate return (rval); 7877c478bd9Sstevel@tonic-gate 7887c478bd9Sstevel@tonic-gate /* 7897c478bd9Sstevel@tonic-gate * If we're here, the values for the two aggregation elements are 7907c478bd9Sstevel@tonic-gate * equal. We already know that the key layout is the same for the two 7917c478bd9Sstevel@tonic-gate * elements; we must now compare the keys themselves as a tie-breaker. 7927c478bd9Sstevel@tonic-gate */ 7937c478bd9Sstevel@tonic-gate return (dt_aggregate_keycmp(lhs, rhs)); 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate 7967c478bd9Sstevel@tonic-gate static int 7977c478bd9Sstevel@tonic-gate dt_aggregate_keyvarcmp(const void *lhs, const void *rhs) 7987c478bd9Sstevel@tonic-gate { 7997c478bd9Sstevel@tonic-gate int rval; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate if ((rval = dt_aggregate_keycmp(lhs, rhs)) != 0) 8027c478bd9Sstevel@tonic-gate return (rval); 8037c478bd9Sstevel@tonic-gate 8047c478bd9Sstevel@tonic-gate return (dt_aggregate_varcmp(lhs, rhs)); 8057c478bd9Sstevel@tonic-gate } 8067c478bd9Sstevel@tonic-gate 8077c478bd9Sstevel@tonic-gate static int 8087c478bd9Sstevel@tonic-gate dt_aggregate_varkeycmp(const void *lhs, const void *rhs) 8097c478bd9Sstevel@tonic-gate { 8107c478bd9Sstevel@tonic-gate int rval; 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0) 8137c478bd9Sstevel@tonic-gate return (rval); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate return (dt_aggregate_keycmp(lhs, rhs)); 8167c478bd9Sstevel@tonic-gate } 8177c478bd9Sstevel@tonic-gate 8187c478bd9Sstevel@tonic-gate static int 8197c478bd9Sstevel@tonic-gate dt_aggregate_valvarcmp(const void *lhs, const void *rhs) 8207c478bd9Sstevel@tonic-gate { 8217c478bd9Sstevel@tonic-gate int rval; 8227c478bd9Sstevel@tonic-gate 8237c478bd9Sstevel@tonic-gate if ((rval = dt_aggregate_valcmp(lhs, rhs)) != 0) 8247c478bd9Sstevel@tonic-gate return (rval); 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate return (dt_aggregate_varcmp(lhs, rhs)); 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate static int 8307c478bd9Sstevel@tonic-gate dt_aggregate_varvalcmp(const void *lhs, const void *rhs) 8317c478bd9Sstevel@tonic-gate { 8327c478bd9Sstevel@tonic-gate int rval; 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate if ((rval = dt_aggregate_varcmp(lhs, rhs)) != 0) 8357c478bd9Sstevel@tonic-gate return (rval); 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate return (dt_aggregate_valcmp(lhs, rhs)); 8387c478bd9Sstevel@tonic-gate } 8397c478bd9Sstevel@tonic-gate 8407c478bd9Sstevel@tonic-gate static int 8417c478bd9Sstevel@tonic-gate dt_aggregate_keyvarrevcmp(const void *lhs, const void *rhs) 8427c478bd9Sstevel@tonic-gate { 8437c478bd9Sstevel@tonic-gate return (dt_aggregate_keyvarcmp(rhs, lhs)); 8447c478bd9Sstevel@tonic-gate } 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate static int 8477c478bd9Sstevel@tonic-gate dt_aggregate_varkeyrevcmp(const void *lhs, const void *rhs) 8487c478bd9Sstevel@tonic-gate { 8497c478bd9Sstevel@tonic-gate return (dt_aggregate_varkeycmp(rhs, lhs)); 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate static int 8537c478bd9Sstevel@tonic-gate dt_aggregate_valvarrevcmp(const void *lhs, const void *rhs) 8547c478bd9Sstevel@tonic-gate { 8557c478bd9Sstevel@tonic-gate return (dt_aggregate_valvarcmp(rhs, lhs)); 8567c478bd9Sstevel@tonic-gate } 8577c478bd9Sstevel@tonic-gate 8587c478bd9Sstevel@tonic-gate static int 8597c478bd9Sstevel@tonic-gate dt_aggregate_varvalrevcmp(const void *lhs, const void *rhs) 8607c478bd9Sstevel@tonic-gate { 8617c478bd9Sstevel@tonic-gate return (dt_aggregate_varvalcmp(rhs, lhs)); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate int 8657c478bd9Sstevel@tonic-gate dt_aggregate_go(dtrace_hdl_t *dtp) 8667c478bd9Sstevel@tonic-gate { 8677c478bd9Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 8687c478bd9Sstevel@tonic-gate dtrace_optval_t size, cpu; 8697c478bd9Sstevel@tonic-gate dtrace_bufdesc_t *buf = &agp->dtat_buf; 8707c478bd9Sstevel@tonic-gate int rval, i; 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate assert(agp->dtat_maxcpu == 0); 8737c478bd9Sstevel@tonic-gate assert(agp->dtat_ncpu == 0); 8747c478bd9Sstevel@tonic-gate assert(agp->dtat_cpus == NULL); 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate agp->dtat_maxcpu = dt_sysconf(dtp, _SC_CPUID_MAX) + 1; 8777c478bd9Sstevel@tonic-gate agp->dtat_ncpu = dt_sysconf(dtp, _SC_NPROCESSORS_MAX); 8787c478bd9Sstevel@tonic-gate agp->dtat_cpus = malloc(agp->dtat_ncpu * sizeof (processorid_t)); 8797c478bd9Sstevel@tonic-gate 8807c478bd9Sstevel@tonic-gate if (agp->dtat_cpus == NULL) 8817c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate /* 8847c478bd9Sstevel@tonic-gate * Use the aggregation buffer size as reloaded from the kernel. 8857c478bd9Sstevel@tonic-gate */ 8867c478bd9Sstevel@tonic-gate size = dtp->dt_options[DTRACEOPT_AGGSIZE]; 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate rval = dtrace_getopt(dtp, "aggsize", &size); 8897c478bd9Sstevel@tonic-gate assert(rval == 0); 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate if (size == 0 || size == DTRACEOPT_UNSET) 8927c478bd9Sstevel@tonic-gate return (0); 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate buf = &agp->dtat_buf; 8957c478bd9Sstevel@tonic-gate buf->dtbd_size = size; 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate if ((buf->dtbd_data = malloc(buf->dtbd_size)) == NULL) 8987c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate /* 9017c478bd9Sstevel@tonic-gate * Now query for the CPUs enabled. 9027c478bd9Sstevel@tonic-gate */ 9037c478bd9Sstevel@tonic-gate rval = dtrace_getopt(dtp, "cpu", &cpu); 9047c478bd9Sstevel@tonic-gate assert(rval == 0 && cpu != DTRACEOPT_UNSET); 9057c478bd9Sstevel@tonic-gate 9067c478bd9Sstevel@tonic-gate if (cpu != DTRACE_CPUALL) { 9077c478bd9Sstevel@tonic-gate assert(cpu < agp->dtat_ncpu); 9087c478bd9Sstevel@tonic-gate agp->dtat_cpus[agp->dtat_ncpus++] = (processorid_t)cpu; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate return (0); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate agp->dtat_ncpus = 0; 9147c478bd9Sstevel@tonic-gate for (i = 0; i < agp->dtat_maxcpu; i++) { 9157c478bd9Sstevel@tonic-gate if (dt_status(dtp, i) == -1) 9167c478bd9Sstevel@tonic-gate continue; 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate agp->dtat_cpus[agp->dtat_ncpus++] = i; 9197c478bd9Sstevel@tonic-gate } 9207c478bd9Sstevel@tonic-gate 9217c478bd9Sstevel@tonic-gate return (0); 9227c478bd9Sstevel@tonic-gate } 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate static int 9257c478bd9Sstevel@tonic-gate dt_aggwalk_rval(dtrace_hdl_t *dtp, dt_ahashent_t *h, int rval) 9267c478bd9Sstevel@tonic-gate { 9277c478bd9Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 9287c478bd9Sstevel@tonic-gate dtrace_aggdata_t *data; 9297c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *aggdesc; 9307c478bd9Sstevel@tonic-gate dtrace_recdesc_t *rec; 9317c478bd9Sstevel@tonic-gate int i; 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate switch (rval) { 9347c478bd9Sstevel@tonic-gate case DTRACE_AGGWALK_NEXT: 9357c478bd9Sstevel@tonic-gate break; 9367c478bd9Sstevel@tonic-gate 9377c478bd9Sstevel@tonic-gate case DTRACE_AGGWALK_CLEAR: { 9387c478bd9Sstevel@tonic-gate uint32_t size, offs = 0; 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate aggdesc = h->dtahe_data.dtada_desc; 9417c478bd9Sstevel@tonic-gate rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1]; 9427c478bd9Sstevel@tonic-gate size = rec->dtrd_size; 9437c478bd9Sstevel@tonic-gate data = &h->dtahe_data; 9447c478bd9Sstevel@tonic-gate 9457c478bd9Sstevel@tonic-gate if (rec->dtrd_action == DTRACEAGG_LQUANTIZE) { 9467c478bd9Sstevel@tonic-gate offs = sizeof (uint64_t); 9477c478bd9Sstevel@tonic-gate size -= sizeof (uint64_t); 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate bzero(&data->dtada_data[rec->dtrd_offset] + offs, size); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate if (data->dtada_percpu == NULL) 9537c478bd9Sstevel@tonic-gate break; 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate for (i = 0; i < dtp->dt_aggregate.dtat_maxcpu; i++) 9567c478bd9Sstevel@tonic-gate bzero(data->dtada_percpu[i] + offs, size); 9577c478bd9Sstevel@tonic-gate break; 9587c478bd9Sstevel@tonic-gate } 9597c478bd9Sstevel@tonic-gate 9607c478bd9Sstevel@tonic-gate case DTRACE_AGGWALK_ERROR: 9617c478bd9Sstevel@tonic-gate /* 9627c478bd9Sstevel@tonic-gate * We assume that errno is already set in this case. 9637c478bd9Sstevel@tonic-gate */ 9647c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, errno)); 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate case DTRACE_AGGWALK_ABORT: 9677c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_DIRABORT)); 9687c478bd9Sstevel@tonic-gate 9697c478bd9Sstevel@tonic-gate case DTRACE_AGGWALK_DENORMALIZE: 9707c478bd9Sstevel@tonic-gate h->dtahe_data.dtada_normal = 1; 9717c478bd9Sstevel@tonic-gate return (0); 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate case DTRACE_AGGWALK_NORMALIZE: 9747c478bd9Sstevel@tonic-gate if (h->dtahe_data.dtada_normal == 0) { 9757c478bd9Sstevel@tonic-gate h->dtahe_data.dtada_normal = 1; 9767c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate return (0); 9807c478bd9Sstevel@tonic-gate 9817c478bd9Sstevel@tonic-gate case DTRACE_AGGWALK_REMOVE: { 9827c478bd9Sstevel@tonic-gate dtrace_aggdata_t *aggdata = &h->dtahe_data; 9837c478bd9Sstevel@tonic-gate int i, max_cpus = agp->dtat_maxcpu; 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* 9867c478bd9Sstevel@tonic-gate * First, remove this hash entry from its hash chain. 9877c478bd9Sstevel@tonic-gate */ 9887c478bd9Sstevel@tonic-gate if (h->dtahe_prev != NULL) { 9897c478bd9Sstevel@tonic-gate h->dtahe_prev->dtahe_next = h->dtahe_next; 9907c478bd9Sstevel@tonic-gate } else { 9917c478bd9Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 9927c478bd9Sstevel@tonic-gate size_t ndx = h->dtahe_hashval % hash->dtah_size; 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate assert(hash->dtah_hash[ndx] == h); 9957c478bd9Sstevel@tonic-gate hash->dtah_hash[ndx] = h->dtahe_next; 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate if (h->dtahe_next != NULL) 9997c478bd9Sstevel@tonic-gate h->dtahe_next->dtahe_prev = h->dtahe_prev; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* 10027c478bd9Sstevel@tonic-gate * Now remove it from the list of all hash entries. 10037c478bd9Sstevel@tonic-gate */ 10047c478bd9Sstevel@tonic-gate if (h->dtahe_prevall != NULL) { 10057c478bd9Sstevel@tonic-gate h->dtahe_prevall->dtahe_nextall = h->dtahe_nextall; 10067c478bd9Sstevel@tonic-gate } else { 10077c478bd9Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 10087c478bd9Sstevel@tonic-gate 10097c478bd9Sstevel@tonic-gate assert(hash->dtah_all == h); 10107c478bd9Sstevel@tonic-gate hash->dtah_all = h->dtahe_nextall; 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate if (h->dtahe_nextall != NULL) 10147c478bd9Sstevel@tonic-gate h->dtahe_nextall->dtahe_prevall = h->dtahe_prevall; 10157c478bd9Sstevel@tonic-gate 10167c478bd9Sstevel@tonic-gate /* 10177c478bd9Sstevel@tonic-gate * We're unlinked. We can safely destroy the data. 10187c478bd9Sstevel@tonic-gate */ 10197c478bd9Sstevel@tonic-gate if (aggdata->dtada_percpu != NULL) { 10207c478bd9Sstevel@tonic-gate for (i = 0; i < max_cpus; i++) 10217c478bd9Sstevel@tonic-gate free(aggdata->dtada_percpu[i]); 10227c478bd9Sstevel@tonic-gate free(aggdata->dtada_percpu); 10237c478bd9Sstevel@tonic-gate } 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate free(aggdata->dtada_data); 10267c478bd9Sstevel@tonic-gate free(h); 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate return (0); 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate default: 10327c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_BADRVAL)); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 10357c478bd9Sstevel@tonic-gate return (0); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate int 10397c478bd9Sstevel@tonic-gate dtrace_aggregate_walk(dtrace_hdl_t *dtp, dtrace_aggregate_f *func, void *arg) 10407c478bd9Sstevel@tonic-gate { 10417c478bd9Sstevel@tonic-gate dt_ahashent_t *h, *next; 10427c478bd9Sstevel@tonic-gate dt_ahash_t *hash = &dtp->dt_aggregate.dtat_hash; 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate for (h = hash->dtah_all; h != NULL; h = next) { 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * dt_aggwalk_rval() can potentially remove the current hash 10477c478bd9Sstevel@tonic-gate * entry; we need to load the next hash entry before calling 10487c478bd9Sstevel@tonic-gate * into it. 10497c478bd9Sstevel@tonic-gate */ 10507c478bd9Sstevel@tonic-gate next = h->dtahe_nextall; 10517c478bd9Sstevel@tonic-gate 10527c478bd9Sstevel@tonic-gate if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) 10537c478bd9Sstevel@tonic-gate return (-1); 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate return (0); 10577c478bd9Sstevel@tonic-gate } 10587c478bd9Sstevel@tonic-gate 10597c478bd9Sstevel@tonic-gate static int 10607c478bd9Sstevel@tonic-gate dt_aggregate_walk_sorted(dtrace_hdl_t *dtp, 10617c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg, 10627c478bd9Sstevel@tonic-gate int (*sfunc)(const void *, const void *)) 10637c478bd9Sstevel@tonic-gate { 10647c478bd9Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 10657c478bd9Sstevel@tonic-gate dt_ahashent_t *h, **sorted; 10667c478bd9Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 10677c478bd9Sstevel@tonic-gate size_t i, nentries = 0; 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) 10707c478bd9Sstevel@tonic-gate nentries++; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate sorted = malloc(nentries * sizeof (dt_ahashent_t *)); 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate if (sorted == NULL) 10757c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, EDT_NOMEM)); 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate for (h = hash->dtah_all, i = 0; h != NULL; h = h->dtahe_nextall) 10787c478bd9Sstevel@tonic-gate sorted[i++] = h; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate qsort(sorted, nentries, sizeof (dt_ahashent_t *), sfunc); 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate for (i = 0; i < nentries; i++) { 10837c478bd9Sstevel@tonic-gate h = sorted[i]; 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate if (dt_aggwalk_rval(dtp, h, func(&h->dtahe_data, arg)) == -1) 10867c478bd9Sstevel@tonic-gate return (-1); 10877c478bd9Sstevel@tonic-gate } 10887c478bd9Sstevel@tonic-gate 10897c478bd9Sstevel@tonic-gate free(sorted); 10907c478bd9Sstevel@tonic-gate return (0); 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate int 10947c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_keysorted(dtrace_hdl_t *dtp, 10957c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 10967c478bd9Sstevel@tonic-gate { 10977c478bd9Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 10987c478bd9Sstevel@tonic-gate arg, dt_aggregate_varkeycmp)); 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate int 11027c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_valsorted(dtrace_hdl_t *dtp, 11037c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 11047c478bd9Sstevel@tonic-gate { 11057c478bd9Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 11067c478bd9Sstevel@tonic-gate arg, dt_aggregate_varvalcmp)); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate int 11107c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_keyvarsorted(dtrace_hdl_t *dtp, 11117c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 11127c478bd9Sstevel@tonic-gate { 11137c478bd9Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 11147c478bd9Sstevel@tonic-gate arg, dt_aggregate_keyvarcmp)); 11157c478bd9Sstevel@tonic-gate } 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate int 11187c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_valvarsorted(dtrace_hdl_t *dtp, 11197c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 11207c478bd9Sstevel@tonic-gate { 11217c478bd9Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 11227c478bd9Sstevel@tonic-gate arg, dt_aggregate_valvarcmp)); 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate 11257c478bd9Sstevel@tonic-gate int 11267c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_keyrevsorted(dtrace_hdl_t *dtp, 11277c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 11287c478bd9Sstevel@tonic-gate { 11297c478bd9Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 11307c478bd9Sstevel@tonic-gate arg, dt_aggregate_varkeyrevcmp)); 11317c478bd9Sstevel@tonic-gate } 11327c478bd9Sstevel@tonic-gate 11337c478bd9Sstevel@tonic-gate int 11347c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_valrevsorted(dtrace_hdl_t *dtp, 11357c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 11367c478bd9Sstevel@tonic-gate { 11377c478bd9Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 11387c478bd9Sstevel@tonic-gate arg, dt_aggregate_varvalrevcmp)); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate int 11427c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_keyvarrevsorted(dtrace_hdl_t *dtp, 11437c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 11447c478bd9Sstevel@tonic-gate { 11457c478bd9Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 11467c478bd9Sstevel@tonic-gate arg, dt_aggregate_keyvarrevcmp)); 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate 11497c478bd9Sstevel@tonic-gate int 11507c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_valvarrevsorted(dtrace_hdl_t *dtp, 11517c478bd9Sstevel@tonic-gate dtrace_aggregate_f *func, void *arg) 11527c478bd9Sstevel@tonic-gate { 11537c478bd9Sstevel@tonic-gate return (dt_aggregate_walk_sorted(dtp, func, 11547c478bd9Sstevel@tonic-gate arg, dt_aggregate_valvarrevcmp)); 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate int 11587c478bd9Sstevel@tonic-gate dtrace_aggregate_print(dtrace_hdl_t *dtp, FILE *fp, 11597c478bd9Sstevel@tonic-gate dtrace_aggregate_walk_f *func) 11607c478bd9Sstevel@tonic-gate { 11617c478bd9Sstevel@tonic-gate dt_print_aggdata_t pd; 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate pd.dtpa_dtp = dtp; 11647c478bd9Sstevel@tonic-gate pd.dtpa_fp = fp; 11657c478bd9Sstevel@tonic-gate pd.dtpa_allunprint = 1; 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate if (func == NULL) 11687c478bd9Sstevel@tonic-gate func = dtrace_aggregate_walk_valsorted; 11697c478bd9Sstevel@tonic-gate 11707c478bd9Sstevel@tonic-gate if ((*func)(dtp, dt_print_agg, &pd) == -1) 11717c478bd9Sstevel@tonic-gate return (dt_set_errno(dtp, dtp->dt_errno)); 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate return (0); 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate 11767c478bd9Sstevel@tonic-gate void 11777c478bd9Sstevel@tonic-gate dtrace_aggregate_clear(dtrace_hdl_t *dtp) 11787c478bd9Sstevel@tonic-gate { 11797c478bd9Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 11807c478bd9Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 11817c478bd9Sstevel@tonic-gate dt_ahashent_t *h; 11827c478bd9Sstevel@tonic-gate dtrace_aggdata_t *data; 11837c478bd9Sstevel@tonic-gate dtrace_aggdesc_t *aggdesc; 11847c478bd9Sstevel@tonic-gate dtrace_recdesc_t *rec; 11857c478bd9Sstevel@tonic-gate int i, max_cpus = agp->dtat_maxcpu; 11867c478bd9Sstevel@tonic-gate 11877c478bd9Sstevel@tonic-gate for (h = hash->dtah_all; h != NULL; h = h->dtahe_nextall) { 11887c478bd9Sstevel@tonic-gate aggdesc = h->dtahe_data.dtada_desc; 11897c478bd9Sstevel@tonic-gate rec = &aggdesc->dtagd_rec[aggdesc->dtagd_nrecs - 1]; 11907c478bd9Sstevel@tonic-gate data = &h->dtahe_data; 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate bzero(&data->dtada_data[rec->dtrd_offset], rec->dtrd_size); 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate if (data->dtada_percpu == NULL) 11957c478bd9Sstevel@tonic-gate continue; 11967c478bd9Sstevel@tonic-gate 11977c478bd9Sstevel@tonic-gate for (i = 0; i < max_cpus; i++) 11987c478bd9Sstevel@tonic-gate bzero(data->dtada_percpu[i], rec->dtrd_size); 11997c478bd9Sstevel@tonic-gate } 12007c478bd9Sstevel@tonic-gate } 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate void 12037c478bd9Sstevel@tonic-gate dt_aggregate_destroy(dtrace_hdl_t *dtp) 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate dt_aggregate_t *agp = &dtp->dt_aggregate; 12067c478bd9Sstevel@tonic-gate dt_ahash_t *hash = &agp->dtat_hash; 12077c478bd9Sstevel@tonic-gate dt_ahashent_t *h, *next; 12087c478bd9Sstevel@tonic-gate dtrace_aggdata_t *aggdata; 12097c478bd9Sstevel@tonic-gate int i, max_cpus = agp->dtat_maxcpu; 12107c478bd9Sstevel@tonic-gate 12117c478bd9Sstevel@tonic-gate if (hash->dtah_hash == NULL) { 12127c478bd9Sstevel@tonic-gate assert(hash->dtah_all == NULL); 12137c478bd9Sstevel@tonic-gate } else { 12147c478bd9Sstevel@tonic-gate free(hash->dtah_hash); 12157c478bd9Sstevel@tonic-gate 12167c478bd9Sstevel@tonic-gate for (h = hash->dtah_all; h != NULL; h = next) { 12177c478bd9Sstevel@tonic-gate next = h->dtahe_nextall; 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate aggdata = &h->dtahe_data; 12207c478bd9Sstevel@tonic-gate 12217c478bd9Sstevel@tonic-gate if (aggdata->dtada_percpu != NULL) { 12227c478bd9Sstevel@tonic-gate for (i = 0; i < max_cpus; i++) 12237c478bd9Sstevel@tonic-gate free(aggdata->dtada_percpu[i]); 12247c478bd9Sstevel@tonic-gate free(aggdata->dtada_percpu); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate free(aggdata->dtada_data); 12287c478bd9Sstevel@tonic-gate free(h); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate hash->dtah_hash = NULL; 12327c478bd9Sstevel@tonic-gate hash->dtah_all = NULL; 12337c478bd9Sstevel@tonic-gate hash->dtah_size = 0; 12347c478bd9Sstevel@tonic-gate } 12357c478bd9Sstevel@tonic-gate 12367c478bd9Sstevel@tonic-gate free(agp->dtat_buf.dtbd_data); 12377c478bd9Sstevel@tonic-gate free(agp->dtat_cpus); 12387c478bd9Sstevel@tonic-gate } 1239