[DTrace-devel] [PATCH] Add support for built-in variable walltimestamp

Kris Van Hees kris.van.hees at oracle.com
Sat Apr 24 19:07:40 PDT 2021


On Fri, Apr 23, 2021 at 09:50:39PM -0400, eugene.loh at oracle.com wrote:
> From: Eugene Loh <eugene.loh at oracle.com>
> 
> Use bpf_ktime_get_ns() to get the time (in nsec) since boot.  This
> value must be adjusted to POSIX time.  So, when we load a built-in
> variable, check if it is walltimestamp.  If so, add BPF instructions
> to add the adjustment.
> 
> It would be nice if the support for walltimestamp were more localized,
> but the BPF code that gets built-in variables is compiled at build
> time while the adjustment is determined at run time.

Why not store the adjustment as a value in the 'state' map as we already
do for some struct offsets that we need in get_bvar()?  That way you can
keep the walltimestamp handling all in the precompiler BPF code.  All you
need to do is populate an element in the 'state' map woth the correct
delta.

> A few more walltimestamp tests pass now, but existing walltimestamp
> tests are rather lenient.  Add a new, more stringent test.  In particular,
> timestamp is supposed to be fixed for an entire clause while walltimestamp
> is fresh with every call.

What about timezones?  Does the CLOCK_REALTIME provide a timespec in UTC or
in local tiemzone?  The walltimestamp D variable needs to report in UTC.

> Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
> ---
>  bpf/get_bvar.c                                |  2 +
>  libdtrace/dt_cg.c                             | 28 ++++++++++++-
>  test/demo/act/time.d                          |  3 +-
>  test/unittest/printa/tst.walltimestamp.sh     |  2 +-
>  .../variables/bvar/tst.walltimestamp.d        |  3 +-
>  .../variables/bvar/tst.walltimestamp2.d       | 29 ++++++++++++++
>  .../variables/bvar/tst.walltimestamp2.r       |  1 +
>  .../variables/bvar/tst.walltimestamp2.r.p     | 40 +++++++++++++++++++
>  8 files changed, 102 insertions(+), 6 deletions(-)
>  create mode 100644 test/unittest/variables/bvar/tst.walltimestamp2.d
>  create mode 100644 test/unittest/variables/bvar/tst.walltimestamp2.r
>  create mode 100755 test/unittest/variables/bvar/tst.walltimestamp2.r.p
> 
> diff --git a/bpf/get_bvar.c b/bpf/get_bvar.c
> index 971209ab..99eb1906 100644
> --- a/bpf/get_bvar.c
> +++ b/bpf/get_bvar.c
> @@ -62,6 +62,8 @@ noinline uint64_t dt_get_bvar(dt_dctx_t *dctx, uint32_t id)
>  
>  		return val & 0x00000000ffffffffUL;
>  	}
> +	case DIF_VAR_WALLTIMESTAMP:
> +		return bpf_ktime_get_ns();
>  	case DIF_VAR_PPID: {
>  		uint64_t	ptr;
>  		int32_t		val = -1;
> diff --git a/libdtrace/dt_cg.c b/libdtrace/dt_cg.c
> index 54c50d01..92781e64 100644
> --- a/libdtrace/dt_cg.c
> +++ b/libdtrace/dt_cg.c
> @@ -5,6 +5,7 @@
>   * http://oss.oracle.com/licenses/upl.
>   */
>  
> +#include <time.h>
>  #include <sys/types.h>
>  
>  #include <stdlib.h>
> @@ -25,6 +26,21 @@
>  
>  static void dt_cg_node(dt_node_t *, dt_irlist_t *, dt_regset_t *);
>  
> +static uint64_t walltimestamp_adjustment = 0;
> +static void get_walltimestamp_adjustment() {
> +	struct timespec t_real;
> +	struct timespec t_boot;
> +
> +	if (clock_gettime(CLOCK_REALTIME, &t_real))
> +		return;
> +	if (clock_gettime(CLOCK_MONOTONIC, &t_boot))
> +		return;
> +
> +	walltimestamp_adjustment = t_real.tv_sec - t_boot.tv_sec;
> +	walltimestamp_adjustment *= 1000000000;
> +	walltimestamp_adjustment += t_real.tv_nsec - t_boot.tv_nsec;
> +}
> +
>  /*
>   * Generate the generic prologue of the trampoline BPF program.
>   *
> @@ -1670,6 +1686,7 @@ dt_cg_load(dt_node_t *dnp, ctf_file_t *ctfp, ctf_id_t type)
>  static void
>  dt_cg_load_var(dt_node_t *dst, dt_irlist_t *dlp, dt_regset_t *drp)
>  {
> +	int		adjust_walltimestamp = 0;
>  	dt_ident_t	*idp = dt_ident_resolve(dst->dn_ident);
>  
>  	idp->di_flags |= DT_IDFLG_DIFR;
> @@ -1704,6 +1721,8 @@ dt_cg_load_var(dt_node_t *dst, dt_irlist_t *dlp, dt_regset_t *drp)
>  		emit(dlp, BPF_MOV_IMM(BPF_REG_1, idp->di_id - DIF_VAR_OTHER_UBASE));
>  		idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_tvar");
>  	} else if (idp->di_id < DIF_VAR_OTHER_UBASE) {	/* built-in var */
> +		if (idp->di_id == DIF_VAR_WALLTIMESTAMP)
> +			adjust_walltimestamp = 1;
>  		emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_FP, DT_STK_DCTX));
>  		emit(dlp, BPF_MOV_IMM(BPF_REG_2, idp->di_id));
>  		idp = dt_dlib_get_func(yypcb->pcb_hdl, "dt_get_bvar");
> @@ -1718,7 +1737,14 @@ dt_cg_load_var(dt_node_t *dst, dt_irlist_t *dlp, dt_regset_t *drp)
>  
>  	if ((dst->dn_reg = dt_regset_alloc(drp)) == -1)
>  		longjmp(yypcb->pcb_jmpbuf, EDT_NOREG);
> -	emit(dlp,  BPF_MOV_REG(dst->dn_reg, BPF_REG_0));
> +	if (adjust_walltimestamp) {
> +		if (walltimestamp_adjustment == 0)
> +			get_walltimestamp_adjustment();
> +		/* FIXME: should we set a fault if we cannot adjust? */
> +		dt_cg_setx(dlp, dst->dn_reg, walltimestamp_adjustment);
> +		emit(dlp, BPF_ALU64_REG(BPF_ADD, dst->dn_reg, BPF_REG_0));
> +	} else
> +		emit(dlp, BPF_MOV_REG(dst->dn_reg, BPF_REG_0));
>  	dt_regset_free(drp, BPF_REG_0);
>  }
>  
> diff --git a/test/demo/act/time.d b/test/demo/act/time.d
> index 61c97b30..76f2d22f 100644
> --- a/test/demo/act/time.d
> +++ b/test/demo/act/time.d
> @@ -1,11 +1,10 @@
>  /*
>   * Oracle Linux DTrace.
> - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2005, 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 */
>  /* @@trigger: none */
>  
>  #pragma D option quiet
> diff --git a/test/unittest/printa/tst.walltimestamp.sh b/test/unittest/printa/tst.walltimestamp.sh
> index aaa627bc..8037ccab 100755
> --- a/test/unittest/printa/tst.walltimestamp.sh
> +++ b/test/unittest/printa/tst.walltimestamp.sh
> @@ -5,7 +5,7 @@
>  # Licensed under the Universal Permissive License v 1.0 as shown at
>  # http://oss.oracle.com/licenses/upl.
>  #
> -# @@xfail: dtv2
> +
>  if [ $# != 1 ]; then
>  	echo expected one argument: '<'dtrace-path'>'
>  	exit 2
> diff --git a/test/unittest/variables/bvar/tst.walltimestamp.d b/test/unittest/variables/bvar/tst.walltimestamp.d
> index 9e3291c4..8abcddec 100644
> --- a/test/unittest/variables/bvar/tst.walltimestamp.d
> +++ b/test/unittest/variables/bvar/tst.walltimestamp.d
> @@ -1,10 +1,9 @@
>  /*
>   * Oracle Linux DTrace.
> - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
> + * Copyright (c) 2020, 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: The 'walltimestamp' variable can be accessed and is not -1.
> diff --git a/test/unittest/variables/bvar/tst.walltimestamp2.d b/test/unittest/variables/bvar/tst.walltimestamp2.d
> new file mode 100644
> index 00000000..98f142d9
> --- /dev/null
> +++ b/test/unittest/variables/bvar/tst.walltimestamp2.d
> @@ -0,0 +1,29 @@
> +/*
> + * 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.
> + */
> +
> +#pragma D option quiet
> +#pragma D option destructive
> +
> +BEGIN {
> +	/* baseline time stamp from system("date") */
> +	system("date +'%%s.%%N'");
> +
> +	/* get five consecutive time stamps from DTrace */
> +	t1 = walltimestamp;
> +	t2 = walltimestamp;
> +	t3 = walltimestamp;
> +	t4 = walltimestamp;
> +	t5 = walltimestamp;
> +
> +	/* report the first time stamp and the subsequent deltas */
> +	printf("%d\n", t1);
> +	printf("%d\n", t2 - t1);
> +	printf("%d\n", t3 - t2);
> +	printf("%d\n", t4 - t3);
> +	printf("%d\n", t5 - t4);
> +	exit(0);
> +}
> diff --git a/test/unittest/variables/bvar/tst.walltimestamp2.r b/test/unittest/variables/bvar/tst.walltimestamp2.r
> new file mode 100644
> index 00000000..2e9ba477
> --- /dev/null
> +++ b/test/unittest/variables/bvar/tst.walltimestamp2.r
> @@ -0,0 +1 @@
> +success
> diff --git a/test/unittest/variables/bvar/tst.walltimestamp2.r.p b/test/unittest/variables/bvar/tst.walltimestamp2.r.p
> new file mode 100755
> index 00000000..48652ded
> --- /dev/null
> +++ b/test/unittest/variables/bvar/tst.walltimestamp2.r.p
> @@ -0,0 +1,40 @@
> +#!/usr/bin/gawk -f
> +#
> +# 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.
> +
> +{
> +        # read the value generated by system("date")
> +        t0 = $1; getline;
> +
> +        # read a walltimestamp value from DTrace
> +        t1 = $1; getline;
> +
> +        # read a few walltimestamp deltas from DTrace
> +        d2 = $1; getline;
> +        d3 = $1; getline;
> +        d4 = $1; getline;
> +        d5 = $1;
> +
> +        # check that the deltas are all positive
> +        if (d2 <= 0 ||
> +            d3 <= 0 ||
> +            d4 <= 0 ||
> +            d5 <= 0) print "ERROR: walltimestamp did not advance.";
> +
> +        # check that the deltas are all under 0.2 seconds
> +        if (d2 > 200000000 ||
> +            d3 > 200000000 ||
> +            d4 > 200000000 ||
> +            d5 > 200000000) print "ERROR: walltimestamp delta is high.";
> +
> +        # check walltimestamp against system("date")
> +        t_error = 1.e-9 * t1 - t0;
> +        if (t_error < 0) t_error *= -1;
> +        if (t_error > 0.2) print "ERROR: walltimestamp and system(date) disagree.";
> +
> +        print "success";
> +        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