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

eugene.loh at oracle.com eugene.loh at oracle.com
Fri Apr 23 18:50:39 PDT 2021


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.

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.

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




More information about the DTrace-devel mailing list