break;
}
+ case DTRACEAGG_LLQUANTIZE: {
+ uint16_t factor = DTRACE_LLQUANTIZE_FACTOR(desc->dtad_arg);
+ uint16_t lmag = DTRACE_LLQUANTIZE_LMAG(desc->dtad_arg);
+ uint16_t hmag = DTRACE_LLQUANTIZE_HMAG(desc->dtad_arg);
+ uint16_t steps = DTRACE_LLQUANTIZE_STEPS(desc->dtad_arg);
+
+ agg->dtag_initial = desc->dtad_arg;
+ agg->dtag_aggregate = dtrace_aggregate_llquantize;
+
+ /*
+ * 64 is the largest hmag can practically be (for the smallest
+ * possible value of factor, 2). libdtrace has already checked
+ * for overflow, so if hmag > 64, we have corrupted DOF.
+ */
+ if (factor < 2 || steps == 0 || hmag > 64)
+ goto err;
+
+ /*
+ * The size of the buffer for an llquantize() is given by:
+ * (hmag-lmag+1) logarithmic ranges
+ * x
+ * (steps - steps/factor) bins per range
+ * x
+ * 2 signs
+ * +
+ * two overflow bins
+ * +
+ * one underflow bin
+ * +
+ * beginning word to encode factor,lmag,hmag,steps
+ */
+ size = ((hmag-lmag+1)*(steps-steps/factor)*2+4) * sizeof (uint64_t);
+ break;
+ }
+
case DTRACEAGG_AVG:
agg->dtag_aggregate = dtrace_aggregate_avg;
size = sizeof(uint64_t) * 2;
lquanta[levels + 1] += incr;
}
+static uint64_t dtrace_pow(uint64_t base, uint64_t exp)
+{
+ uint64_t p, r;
+
+ p = base;
+ r = 1;
+ while (exp > 0) {
+ if (exp & 1)
+ r *= p;
+
+ p *= p;
+ exp >>= 1;
+ }
+
+ return (r);
+}
+
+void dtrace_aggregate_llquantize(uint64_t *llquanta, uint64_t nval, uint64_t incr)
+{
+ uint64_t arg = *llquanta++;
+ int factor = DTRACE_LLQUANTIZE_FACTOR(arg);
+ int lmag = DTRACE_LLQUANTIZE_LMAG(arg);
+ int hmag = DTRACE_LLQUANTIZE_HMAG(arg);
+ int steps = DTRACE_LLQUANTIZE_STEPS(arg);
+ int i, signbit, steps_factor, mag, underflow_bin;
+ uint64_t val, bucket_max;
+
+ ASSERT(steps != 0);
+ ASSERT(factor > 1);
+
+ if (nval >> (64 - 1)) {
+ signbit = -1;
+ val = 1 + ~nval;
+ } else {
+ signbit = +1;
+ val = nval;
+ }
+
+ /*
+ * Compute steps/factor.
+ * Notice that while we say there are "steps" bins per logarithmic range,
+ * steps/factor of them actually overlap with lower ranges.
+ * E.g., if factor=10 and steps=20, for mag=2 we have the 20 bins
+ * 0 50 100 150 200 250 300 350 ... 800 850 900 950
+ * but the first two actually belong to lower ranges.
+ */
+ steps_factor = steps/factor;
+
+ /* the underflow bin is in the middle */
+ underflow_bin = 1 + (hmag-lmag+1) * (steps-steps_factor);
+
+ bucket_max = dtrace_pow(factor, lmag);
+
+ /* check for "underflow" (smaller than the smallest bin) */
+ if ( val < bucket_max ) {
+ llquanta[underflow_bin] += incr;
+ return;
+ }
+
+ /* loop over the logarithmic ranges */
+ i = 0;
+ for (mag = lmag; mag <= hmag; mag++) {
+ bucket_max *= factor;
+ if (val >= bucket_max) continue;
+
+ /*
+ * We want
+ * i = val * steps / bucket_max;
+ * but val*steps could overflow. An alternative is
+ * i = val / ( bucket_max/steps )
+ * but bucket_max/steps might not divide evenly.
+ * (Plus, we end up with an extra divide.)
+ *
+ * From Solaris, we inherit constraints on factor and steps
+ * that mean bucket_max/steps divides evenly when mag>0.
+ * Meanwhile, if mag==0, val*steps cannot overflow.
+ * So between our two expressions for i, at least one
+ * will work and we just have to pick which one to use.
+ */
+ if (mag == 0) {
+ i = val * steps / bucket_max;
+ } else {
+ i = val / ( bucket_max/steps );
+ }
+
+ // shift for low indices that can never happen
+ i -= steps_factor;
+ break;
+ }
+ i = underflow_bin+signbit*((steps-steps_factor)*(mag-lmag)+i+1);
+ llquanta[i] += incr;
+}
+
void dtrace_aggregate_avg(uint64_t *data, uint64_t nval, uint64_t arg)
{
data[0]++;
if (!agg->dtag_hasarg)
/*
- * Currently, only quantize() and lquantize() take additional
- * arguments, and they have the same semantics: an increment
- * value that defaults to 1 when not present. If additional
- * aggregating actions take arguments, the setting of the
- * default argument value will presumably have to become more
- * sophisticated...
+ * Currently, only quantize(), lquantize() and llquantize()
+ * take additional arguments, and they have the same semantics:
+ * an increment value that defaults to 1 when not present. If
+ * additional aggregating actions take arguments, the setting
+ * of the default argument value will presumably have to
+ * become more sophisticated...
*/
arg = 1;
extern void dtrace_aggregate_max(uint64_t *, uint64_t, uint64_t);
extern void dtrace_aggregate_quantize(uint64_t *, uint64_t, uint64_t);
extern void dtrace_aggregate_lquantize(uint64_t *, uint64_t, uint64_t);
+extern void dtrace_aggregate_llquantize(uint64_t *, uint64_t, uint64_t);
extern void dtrace_aggregate_avg(uint64_t *, uint64_t, uint64_t);
extern void dtrace_aggregate_stddev(uint64_t *, uint64_t, uint64_t);
extern void dtrace_aggregate_count(uint64_t *, uint64_t, uint64_t);
#define DTRACEAGG_STDDEV (DTRACEACT_AGGREGATION + 6)
#define DTRACEAGG_QUANTIZE (DTRACEACT_AGGREGATION + 7)
#define DTRACEAGG_LQUANTIZE (DTRACEACT_AGGREGATION + 8)
+#define DTRACEAGG_LLQUANTIZE (DTRACEACT_AGGREGATION + 9)
#define DTRACE_QUANTIZE_NBUCKETS \
(((sizeof (uint64_t) * NBBY) - 1) * 2 + 1)
(int32_t)(((x) & DTRACE_LQUANTIZE_BASEMASK) >> \
DTRACE_LQUANTIZE_BASESHIFT)
+#define DTRACE_LLQUANTIZE_STEPSSHIFT 48
+#define DTRACE_LLQUANTIZE_STEPSMASK ((uint64_t)UINT16_MAX << 48)
+#define DTRACE_LLQUANTIZE_HMAGSHIFT 32
+#define DTRACE_LLQUANTIZE_HMAGMASK ((uint64_t)UINT16_MAX << 32)
+#define DTRACE_LLQUANTIZE_LMAGSHIFT 16
+#define DTRACE_LLQUANTIZE_LMAGMASK ((uint64_t)UINT16_MAX << 16)
+#define DTRACE_LLQUANTIZE_FACTORSHIFT 0
+#define DTRACE_LLQUANTIZE_FACTORMASK UINT16_MAX
+
+#define DTRACE_LLQUANTIZE_STEPS(x) \
+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_STEPSMASK) >> \
+ DTRACE_LLQUANTIZE_STEPSSHIFT)
+
+#define DTRACE_LLQUANTIZE_HMAG(x) \
+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_HMAGMASK) >> \
+ DTRACE_LLQUANTIZE_HMAGSHIFT)
+
+#define DTRACE_LLQUANTIZE_LMAG(x) \
+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_LMAGMASK) >> \
+ DTRACE_LLQUANTIZE_LMAGSHIFT)
+
+#define DTRACE_LLQUANTIZE_FACTOR(x) \
+ (uint16_t)(((x) & DTRACE_LLQUANTIZE_FACTORMASK) >> \
+ DTRACE_LLQUANTIZE_FACTORSHIFT)
+
#define DTRACE_USTACK_NFRAMES(x) (uint32_t)((x) & UINT32_MAX)
#define DTRACE_USTACK_STRSIZE(x) (uint32_t)((x) >> 32)
#define DTRACE_USTACK_ARG(x, y) \