summaryrefslogtreecommitdiff
path: root/usr/src/lib/libdtrace/common/dt_cc.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libdtrace/common/dt_cc.c')
-rw-r--r--usr/src/lib/libdtrace/common/dt_cc.c140
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;