[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