[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