[DTrace-devel] [PATCH] Add support for rand() subroutine

eugene.loh at oracle.com eugene.loh at oracle.com
Fri Oct 29 16:11:44 PDT 2021


From: Eugene Loh <eugene.loh at oracle.com>

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_cg.c                     |  22 +++-
 test/unittest/dif/rand.d              |   1 -
 test/unittest/funcs/tst.rand.d        |   5 +-
 test/unittest/funcs/tst.rand_inter.sh | 176 ++++++++++++++++++++++++++
 test/unittest/funcs/tst.rand_intra.sh | 162 ++++++++++++++++++++++++
 5 files changed, 360 insertions(+), 6 deletions(-)
 create mode 100755 test/unittest/funcs/tst.rand_inter.sh
 create mode 100755 test/unittest/funcs/tst.rand_intra.sh

diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
index fec20d47..919ec0fb 100644
--- a/libdtrace/dt_cg.c
+++ b/libdtrace/dt_cg.c
@@ -3267,6 +3267,26 @@ dt_cg_subr_lltostr(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 	TRACE_REGSET("    subr-lltostr:End  ");
 }
 
+static void
+dt_cg_subr_rand(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
+{
+	TRACE_REGSET("    subr-rand:Begin");
+
+	dnp->dn_reg = dt_regset_alloc(drp);
+	if (dnp->dn_reg == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+	if (dt_regset_xalloc_args(drp) == -1)
+		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
+	dt_regset_xalloc(drp, BPF_REG_0);
+	emit(dlp,  BPF_CALL_HELPER(BPF_FUNC_get_prandom_u32));
+	dt_regset_free_args(drp);
+	emit(dlp,  BPF_MOV_REG(dnp->dn_reg, BPF_REG_0));
+	dt_regset_free(drp, BPF_REG_0);
+	emit(dlp,  BPF_ALU64_IMM(BPF_AND, dnp->dn_reg, 0xffffffff));
+
+	TRACE_REGSET("    subr-rand:End  ");
+}
+
 static void
 dt_cg_subr_rindex(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 {
@@ -3790,7 +3810,7 @@ dt_cg_subr_htonll(dt_node_t *dnp, dt_irlist_t *dlp, dt_regset_t *drp)
 typedef void dt_cg_subr_f(dt_node_t *, dt_irlist_t *, dt_regset_t *);
 
 static dt_cg_subr_f *_dt_cg_subr[DIF_SUBR_MAX + 1] = {
-	[DIF_SUBR_RAND]			= NULL,
+	[DIF_SUBR_RAND]			= &dt_cg_subr_rand,
 	[DIF_SUBR_MUTEX_OWNED]		= NULL,
 	[DIF_SUBR_MUTEX_OWNER]		= NULL,
 	[DIF_SUBR_MUTEX_TYPE_ADAPTIVE]	= NULL,
diff --git a/test/unittest/dif/rand.d b/test/unittest/dif/rand.d
index 5c8fb441..9746b58c 100644
--- a/test/unittest/dif/rand.d
+++ b/test/unittest/dif/rand.d
@@ -1,4 +1,3 @@
-/* @@xfail: dtv2 */
 BEGIN
 {
 	trace(rand());
diff --git a/test/unittest/funcs/tst.rand.d b/test/unittest/funcs/tst.rand.d
index 0a9356a7..88bd8510 100644
--- a/test/unittest/funcs/tst.rand.d
+++ b/test/unittest/funcs/tst.rand.d
@@ -1,10 +1,9 @@
 /*
  * Oracle Linux DTrace.
- * Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2021, Oracle and/or its affiliates. All rights reserved.
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 /*
  * ASSERTION:  Test rand()
@@ -12,8 +11,6 @@
  * SECTION: Actions and Subroutines/rand()
  */
 
-
-
 BEGIN
 {
 	i = 0;
diff --git a/test/unittest/funcs/tst.rand_inter.sh b/test/unittest/funcs/tst.rand_inter.sh
new file mode 100755
index 00000000..ac3f318a
--- /dev/null
+++ b/test/unittest/funcs/tst.rand_inter.sh
@@ -0,0 +1,176 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+
+dtrace=$1
+tmpfile=$tmpdir/tst.rand_inter.$$
+
+# Sanity test of rand().  Do inter-word correlation checks.  That
+# is, use lquantize to look at the distribution of 4-bit blocks,
+# 2 bits from two consecutive words at arbitrary locations.
+
+$dtrace $dt_flags -q -o $tmpfile -n '
+BEGIN
+{
+	n = 0;
+	x = rand();
+}
+tick-200us
+{
+	y = rand();
+
+	/* glue 2 bits from x to 2 bits from y */
+
+	xbits = (x >> 30) & 3;
+	ybits = (y >> 30) & 3;
+	@a30 = lquantize((xbits << 2) | ybits, 0, 16, 1);
+
+	xbits = (x >> 28) & 3;
+	ybits = (y >> 28) & 3;
+	@a28 = lquantize((xbits << 2) | ybits, 0, 16, 1);
+
+	xbits = (x >> 15) & 3;
+	ybits = (y >> 15) & 3;
+	@a15 = lquantize((xbits << 2) | ybits, 0, 16, 1);
+
+	xbits = (x >> 02) & 3;
+	ybits = (y >> 02) & 3;
+	@a02 = lquantize((xbits << 2) | ybits, 0, 16, 1);
+
+	xbits = (x >> 00) & 3;
+	ybits = (y >> 00) & 3;
+	@a00 = lquantize((xbits << 2) | ybits, 0, 16, 1);
+
+	x = y;
+	n++;
+}
+tick-5sec
+{
+	printf("number of iterations: %d\n", n);
+	exit(0);
+}'
+
+if [ $? -ne 0 ]; then
+	echo "DTrace error"
+	cat $tmpfile
+	exit 1
+fi
+
+# Now the postprocessing.
+
+awk '
+    BEGIN {
+        nDistributions = noutlier2 = noutlier3 = noutlier4 = 0;
+        nbins = 16;
+    }
+
+    # process line: "number of iterations: ..."
+    /number of iterations:/ {
+        n = int($4);
+        if (n < 400) {
+            # tick-* can underfire, but require some minimum data
+            print "ERROR: insufficient data";
+            exit 1;
+        }
+        avg = n / nbins;     # how many to expect per bin
+        std = sqrt(avg);     # standard deviation
+        lo2 = avg - 2 * std; # 2 sigma
+        hi2 = avg + 2 * std;
+        lo3 = avg - 3 * std; # 3 sigma
+        hi3 = avg + 3 * std;
+        lo4 = avg - 4 * std; # 4 sigma
+        hi4 = avg + 4 * std;
+        next;
+    }
+
+    # skip blank lines
+    NF == 0 { next }
+
+    # process line: "value  ------------- Distribution ------------- count"
+    /value/ && /Distribution/ && /count/ {
+        # process a distribution (lquantize)
+        nDistributions++;
+
+        # process line: "< 0 | 0"
+        getline;
+        if ($1 != "<" || $2 != "0" || $3 != "|" || $4 != "0") {
+            print "ERROR: corrupt underflow bin?";
+            exit 1;
+        }
+
+        # process lines:
+        #      0 |@@@                      ...
+        #      1 |@@                       ...
+        #      2 |@@                       ...
+        #      3 |@@@                      ...
+        for (v = 0; v < nbins; v++) {
+            getline;
+            if (int($1) != v || substr($2, 1, 2) != "|@") {
+                print "ERROR: corrupt bin?";
+                exit 1;
+            }
+            c = int($3);
+            if (c < lo2 || c > hi2) { noutlier2++ };
+            if (c < lo3 || c > hi3) { noutlier3++ };
+            if (c < lo4 || c > hi4) { noutlier4++ };
+        }
+
+        # process line: ">= 16 | 0"
+        getline;
+        if ($1 != ">=" || int($2) != nbins || $3 != "|" || $4 != "0") {
+            print "ERROR: corrupt overflow bin?";
+            exit 1;
+        }
+
+        next;
+    }
+
+    # anything else is unexpected
+    {
+        print "ERROR: unexpected line";
+        print;
+        exit 1;
+    }
+
+    # reporting
+    END {
+        if (nDistributions != 5) {
+            print "ERROR: found unexpected number of distributions";
+            exit 1;
+        }
+
+        # due to statistical fluctuations, must guess sensible bounds
+        if (noutlier2 > nDistributions * nbins / 2) {
+            print "ERROR: found too many bins outside two sigma";
+            exit 1;
+        }
+        if (noutlier3 > 2) {
+            print "ERROR: found too many bins outside three sigma";
+            exit 1;
+        }
+        if (noutlier4 > 0) {
+            print "ERROR: found too many bins outside four sigma";
+            exit 1;
+        }
+        exit 0;
+    }
+' $tmpfile > $tmpfile.summary
+
+if [ $? -ne 0 ]; then
+	echo "postprocessing error"
+	echo "DTrace output"
+	cat $tmpfile
+	echo "postprocessing output"
+	cat $tmpfile.summary
+	rm -f $tmpfile $tmpfile.summary
+	exit 1
+fi
+
+n=`awk '/number of iterations/ { print $4 }' $tmpfile`
+echo inter-word correlations tested for $n random numbers
+echo success
+rm -f $tmpfile $tmpfile.summary
+exit 0
diff --git a/test/unittest/funcs/tst.rand_intra.sh b/test/unittest/funcs/tst.rand_intra.sh
new file mode 100755
index 00000000..3fcf8c42
--- /dev/null
+++ b/test/unittest/funcs/tst.rand_intra.sh
@@ -0,0 +1,162 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
+# Licensed under the Universal Permissive License v 1.0 as shown at
+# http://oss.oracle.com/licenses/upl.
+
+dtrace=$1
+tmpfile=$tmpdir/tst.rand_intra.$$
+
+# Sanity test of rand().  Do intra-word correlation checks.  That
+# is, use lquantize to look at the distribution of 4-bit blocks.
+
+$dtrace $dt_flags -q -o $tmpfile -n '
+BEGIN { nuperr = n = 0 }
+tick-200us
+{
+	x = rand();
+
+	@a = lquantize((x      ) & 0xf, 0, 16, 1);
+	@b = lquantize((x >>  4) & 0xf, 0, 16, 1);
+	@c = lquantize((x >>  8) & 0xf, 0, 16, 1);
+	@d = lquantize((x >> 12) & 0xf, 0, 16, 1);
+	@e = lquantize((x >> 16) & 0xf, 0, 16, 1);
+	@f = lquantize((x >> 20) & 0xf, 0, 16, 1);
+	@g = lquantize((x >> 24) & 0xf, 0, 16, 1);
+	@h = lquantize((x >> 28) & 0xf, 0, 16, 1);
+
+	nuperr += (x & 0xffffffff00000000) ? 1 : 0;
+	n++;
+}
+tick-5sec
+{
+	printf("# of upper-bit errors: %d out of %d\n", nuperr, n);
+	exit(0);
+}'
+
+if [ $? -ne 0 ]; then
+	echo "DTrace error"
+	cat $tmpfile
+	exit 1
+fi
+
+# Now the postprocessing.
+
+awk '
+    BEGIN {
+        nDistributions = noutlier2 = noutlier3 = noutlier4 = 0;
+        nbins = 16;
+    }
+
+    # process line: "# of upper-bit errors: 0 out of ..."
+    /upper-bit errors/ {
+        if (int($5) != 0) {
+            print "ERROR: found some upper-bit errors";
+            exit 1;
+        }
+        n = int($8);
+        if (n < 400) {
+            # tick-* can underfire, but require some minimum data
+            print "ERROR: insufficient data";
+            exit 1;
+        }
+        avg = n / nbins;     # how many to expect per bin
+        std = sqrt(avg);     # standard deviation
+        lo2 = avg - 2 * std; # 2 sigma
+        hi2 = avg + 2 * std;
+        lo3 = avg - 3 * std; # 3 sigma
+        hi3 = avg + 3 * std;
+        lo4 = avg - 4 * std; # 4 sigma
+        hi4 = avg + 4 * std;
+        next;
+    }
+
+    # skip blank lines
+    NF == 0 { next }
+
+    # process line: "value  ------------- Distribution ------------- count"
+    /value/ && /Distribution/ && /count/ {
+        # process a distribution (lquantize)
+        nDistributions++;
+
+        # process line: "< 0 | 0"
+        getline;
+        if ($1 != "<" || $2 != "0" || $3 != "|" || $4 != "0") {
+            print "ERROR: corrupt underflow bin?";
+            exit 1;
+        }
+
+        # process lines:
+        #      0 |@@@                      ...
+        #      1 |@@                       ...
+        #      2 |@@                       ...
+        #      3 |@@@                      ...
+        for (v = 0; v < nbins; v++) {
+            getline;
+            if (int($1) != v || substr($2, 1, 2) != "|@") {
+                print "ERROR: corrupt bin?";
+                exit 1;
+            }
+            c = int($3);
+            if (c < lo2 || c > hi2) { noutlier2++ };
+            if (c < lo3 || c > hi3) { noutlier3++ };
+            if (c < lo4 || c > hi4) { noutlier4++ };
+        }
+
+        # process line: ">= 16 | 0"
+        getline;
+        if ($1 != ">=" || int($2) != nbins || $3 != "|" || $4 != "0") {
+            print "ERROR: corrupt overflow bin?";
+            exit 1;
+        }
+
+        next;
+    }
+
+    # anything else is unexpected
+    {
+        print "ERROR: unexpected line";
+        print;
+        exit 1;
+    }
+
+    # reporting
+    END {
+        if (nDistributions != 8) {
+            print "ERROR: found unexpected number of distributions";
+            exit 1;
+        }
+
+        # due to statistical fluctuations, must guess sensible bounds
+        if (noutlier2 > nDistributions * nbins / 2) {
+            print "ERROR: found too many bins outside two sigma";
+            exit 1;
+        }
+        if (noutlier3 > 2) {
+            print "ERROR: found too many bins outside three sigma";
+            exit 1;
+        }
+        if (noutlier4 > 0) {
+            print "ERROR: found too many bins outside four sigma";
+            exit 1;
+        }
+        exit 0;
+    }
+' $tmpfile > $tmpfile.summary
+
+if [ $? -ne 0 ]; then
+	echo "postprocessing error"
+	echo "DTrace output"
+	cat $tmpfile
+	echo "postprocessing output"
+	cat $tmpfile.summary
+	rm -f $tmpfile $tmpfile.summary
+	exit 1
+fi
+
+n=`awk '/upper-bit errors/ { print $8 }' $tmpfile`
+echo intra-word correlations tested for $n random numbers
+echo success
+rm -f $tmpfile $tmpfile.summary
+exit 0
-- 
2.18.4




More information about the DTrace-devel mailing list