diff options
Diffstat (limited to 'usr/src/lib/libdtrace/common/dt_cc.c')
-rw-r--r-- | usr/src/lib/libdtrace/common/dt_cc.c | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/usr/src/lib/libdtrace/common/dt_cc.c b/usr/src/lib/libdtrace/common/dt_cc.c index 56ea585320..e1b794edbf 100644 --- a/usr/src/lib/libdtrace/common/dt_cc.c +++ b/usr/src/lib/libdtrace/common/dt_cc.c @@ -83,6 +83,7 @@ #include <sys/types.h> #include <sys/wait.h> +#include <sys/sysmacros.h> #include <assert.h> #include <strings.h> @@ -1292,6 +1293,145 @@ dt_compile_agg(dtrace_hdl_t *dtp, dt_node_t *dnp, dtrace_stmtdesc_t *sdp) argmax = 5; } + if (fid->di_id == DTRACEAGG_LLQUANTIZE) { + /* + * For log/linear quantizations, we have between one and five + * arguments in addition to the expression: + * + * arg1 => Factor + * arg2 => Low magnitude + * arg3 => High magnitude + * arg4 => Number of steps per magnitude + * arg5 => Quantization increment value (defaults to 1) + */ + dt_node_t *llarg = dnp->dn_aggfun->dn_args->dn_list; + uint64_t oarg, order, v; + dt_idsig_t *isp; + int i; + + struct { + char *str; /* string identifier */ + int badtype; /* error on bad type */ + int badval; /* error on bad value */ + int mismatch; /* error on bad match */ + int shift; /* shift value */ + uint16_t value; /* value itself */ + } args[] = { + { "factor", D_LLQUANT_FACTORTYPE, + D_LLQUANT_FACTORVAL, D_LLQUANT_FACTORMATCH, + DTRACE_LLQUANTIZE_FACTORSHIFT }, + { "low magnitude", D_LLQUANT_LOWTYPE, + D_LLQUANT_LOWVAL, D_LLQUANT_LOWMATCH, + DTRACE_LLQUANTIZE_LOWSHIFT }, + { "high magnitude", D_LLQUANT_HIGHTYPE, + D_LLQUANT_HIGHVAL, D_LLQUANT_HIGHMATCH, + DTRACE_LLQUANTIZE_HIGHSHIFT }, + { "linear steps per magnitude", D_LLQUANT_NSTEPTYPE, + D_LLQUANT_NSTEPVAL, D_LLQUANT_NSTEPMATCH, + DTRACE_LLQUANTIZE_NSTEPSHIFT }, + { NULL } + }; + + assert(arg == 0); + + for (i = 0; args[i].str != NULL; i++) { + if (llarg->dn_kind != DT_NODE_INT) { + dnerror(llarg, args[i].badtype, "llquantize( ) " + "argument #%d (%s) must be an " + "integer constant\n", i + 1, args[i].str); + } + + if ((uint64_t)llarg->dn_value > UINT16_MAX) { + dnerror(llarg, args[i].badval, "llquantize( ) " + "argument #%d (%s) must be an unsigned " + "16-bit quantity\n", i + 1, args[i].str); + } + + args[i].value = (uint16_t)llarg->dn_value; + + assert(!(arg & (UINT16_MAX << args[i].shift))); + arg |= ((uint64_t)args[i].value << args[i].shift); + llarg = llarg->dn_list; + } + + assert(arg != 0); + + if (args[0].value < 2) { + dnerror(dnp, D_LLQUANT_FACTORSMALL, "llquantize( ) " + "factor (argument #1) must be two or more\n"); + } + + if (args[1].value >= args[2].value) { + dnerror(dnp, D_LLQUANT_MAGRANGE, "llquantize( ) " + "high magnitude (argument #3) must be greater " + "than low magnitude (argument #2)\n"); + } + + if (args[3].value < args[0].value) { + dnerror(dnp, D_LLQUANT_FACTORNSTEPS, "llquantize( ) " + "factor (argument #1) must be less than or " + "equal to the number of linear steps per " + "magnitude (argument #4)\n"); + } + + for (v = args[0].value; v < args[3].value; v *= args[0].value) + continue; + + if ((args[3].value % args[0].value) || (v % args[3].value)) { + dnerror(dnp, D_LLQUANT_FACTOREVEN, "llquantize( ) " + "factor (argument #1) must evenly divide the " + "number of steps per magnitude (argument #4), " + "and the number of steps per magnitude must evenly " + "divide a power of the factor\n"); + } + + for (i = 0, order = 1; i < args[2].value; i++) { + if (order * args[0].value > order) { + order *= args[0].value; + continue; + } + + dnerror(dnp, D_LLQUANT_MAGTOOBIG, "llquantize( ) " + "factor (%d) raised to power of high magnitude " + "(%d) overflows 64-bits\n", args[0].value, + args[2].value); + } + + isp = (dt_idsig_t *)aid->di_data; + + if (isp->dis_auxinfo == 0) { + /* + * This is the first time we've seen an llquantize() + * for this aggregation; we'll store our argument + * as the auxiliary signature information. + */ + isp->dis_auxinfo = arg; + } else if ((oarg = isp->dis_auxinfo) != arg) { + /* + * If we have seen this llquantize() before and the + * argument doesn't match the original argument, pick + * the original argument apart to concisely report the + * mismatch. + */ + int expected = 0, found = 0; + + for (i = 0; expected == found; i++) { + assert(args[i].str != NULL); + + expected = (oarg >> args[i].shift) & UINT16_MAX; + found = (arg >> args[i].shift) & UINT16_MAX; + } + + dnerror(dnp, args[i - 1].mismatch, "llquantize( ) " + "%s (argument #%d) doesn't match previous " + "declaration: expected %d, found %d\n", + args[i - 1].str, i, expected, found); + } + + incr = llarg; + argmax = 6; + } + if (fid->di_id == DTRACEAGG_QUANTIZE) { incr = dnp->dn_aggfun->dn_args->dn_list; argmax = 2; |