[DTrace-devel] [PATCH] Add support for rand() subroutine
Kris Van Hees
kris.van.hees at oracle.com
Thu Nov 18 23:30:28 UTC 2021
On Fri, Oct 29, 2021 at 07:11:44PM -0400, eugene.loh at oracle.com wrote:
> From: Eugene Loh <eugene.loh at oracle.com>
>
> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
Reviewed-by: Kris Van Hees <kris.van.hees 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
>
>
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel
More information about the DTrace-devel
mailing list