[DTrace-devel] [PATCH v4] Implement the lockstat provider

Kris Van Hees kris.van.hees at oracle.com
Wed May 24 21:56:30 UTC 2023


Not all probes are supported yet in all possible proving locations due
to limitations in the kernel tracing framework and due to compiler
optimization of the kernel code.  Improvements will be added in an
incremental fashion.

Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
Reviewed-by: Nick Alcock <nick.alcock at oracle.com>
---
 libdtrace/Build                               |   2 +
 libdtrace/dt_bpf_maps.h                       |   8 +-
 libdtrace/dt_open.c                           |   1 +
 libdtrace/dt_prov_lockstat.c                  | 384 ++++++++++++++++++
 libdtrace/dt_provider.h                       |   1 +
 test/demo/lockstat/whatlock.d                 |   1 -
 test/unittest/lockstat/test.x                 |   9 -
 .../lockstat/tst.lv-adaptive-acquire-error.r  |  16 +
 .../tst.lv-adaptive-acquire-error.r.p         |   6 +
 .../lockstat/tst.lv-adaptive-acquire-error.sh |  11 +
 .../lockstat/tst.lv-adaptive-acquire.r        |  15 +
 .../lockstat/tst.lv-adaptive-acquire.r.p      |   1 +
 .../lockstat/tst.lv-adaptive-acquire.sh       |  11 +
 .../unittest/lockstat/tst.lv-adaptive-block.r |  16 +
 .../lockstat/tst.lv-adaptive-block.r.p        |   1 +
 .../lockstat/tst.lv-adaptive-block.sh         |  11 +
 .../lockstat/tst.lv-adaptive-release.r        |  15 +
 .../lockstat/tst.lv-adaptive-release.r.p      |   1 +
 .../lockstat/tst.lv-adaptive-release.sh       |  11 +
 test/unittest/lockstat/tst.lv-adaptive-spin.r |  16 +
 .../lockstat/tst.lv-adaptive-spin.r.p         |   1 +
 .../unittest/lockstat/tst.lv-adaptive-spin.sh |  11 +
 test/unittest/lockstat/tst.lv-rw-acquire.r    |  16 +
 test/unittest/lockstat/tst.lv-rw-acquire.r.p  |   1 +
 test/unittest/lockstat/tst.lv-rw-acquire.sh   |  11 +
 test/unittest/lockstat/tst.lv-rw-release.r    |  16 +
 test/unittest/lockstat/tst.lv-rw-release.r.p  |   1 +
 test/unittest/lockstat/tst.lv-rw-release.sh   |  11 +
 test/unittest/lockstat/tst.lv-rw-spin.r       |  17 +
 test/unittest/lockstat/tst.lv-rw-spin.r.p     |   1 +
 test/unittest/lockstat/tst.lv-rw-spin.sh      |  11 +
 test/unittest/lockstat/tst.lv-spin-acquire.r  |  15 +
 .../unittest/lockstat/tst.lv-spin-acquire.r.p |   1 +
 test/unittest/lockstat/tst.lv-spin-acquire.sh |  11 +
 test/unittest/lockstat/tst.lv-spin-release.r  |  15 +
 .../unittest/lockstat/tst.lv-spin-release.r.p |   1 +
 test/unittest/lockstat/tst.lv-spin-release.sh |  11 +
 test/unittest/lockstat/tst.lv-spin-spin.r     |  16 +
 test/unittest/lockstat/tst.lv-spin-spin.r.p   |   1 +
 test/unittest/lockstat/tst.lv-spin-spin.sh    |  11 +
 40 files changed, 704 insertions(+), 12 deletions(-)
 create mode 100644 libdtrace/dt_prov_lockstat.c
 delete mode 100755 test/unittest/lockstat/test.x
 create mode 100644 test/unittest/lockstat/tst.lv-adaptive-acquire-error.r
 create mode 100755 test/unittest/lockstat/tst.lv-adaptive-acquire-error.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-adaptive-acquire-error.sh
 create mode 100644 test/unittest/lockstat/tst.lv-adaptive-acquire.r
 create mode 120000 test/unittest/lockstat/tst.lv-adaptive-acquire.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-adaptive-acquire.sh
 create mode 100644 test/unittest/lockstat/tst.lv-adaptive-block.r
 create mode 120000 test/unittest/lockstat/tst.lv-adaptive-block.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-adaptive-block.sh
 create mode 100644 test/unittest/lockstat/tst.lv-adaptive-release.r
 create mode 120000 test/unittest/lockstat/tst.lv-adaptive-release.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-adaptive-release.sh
 create mode 100644 test/unittest/lockstat/tst.lv-adaptive-spin.r
 create mode 120000 test/unittest/lockstat/tst.lv-adaptive-spin.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-adaptive-spin.sh
 create mode 100644 test/unittest/lockstat/tst.lv-rw-acquire.r
 create mode 120000 test/unittest/lockstat/tst.lv-rw-acquire.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-rw-acquire.sh
 create mode 100644 test/unittest/lockstat/tst.lv-rw-release.r
 create mode 120000 test/unittest/lockstat/tst.lv-rw-release.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-rw-release.sh
 create mode 100644 test/unittest/lockstat/tst.lv-rw-spin.r
 create mode 120000 test/unittest/lockstat/tst.lv-rw-spin.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-rw-spin.sh
 create mode 100644 test/unittest/lockstat/tst.lv-spin-acquire.r
 create mode 120000 test/unittest/lockstat/tst.lv-spin-acquire.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-spin-acquire.sh
 create mode 100644 test/unittest/lockstat/tst.lv-spin-release.r
 create mode 120000 test/unittest/lockstat/tst.lv-spin-release.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-spin-release.sh
 create mode 100644 test/unittest/lockstat/tst.lv-spin-spin.r
 create mode 120000 test/unittest/lockstat/tst.lv-spin-spin.r.p
 create mode 100755 test/unittest/lockstat/tst.lv-spin-spin.sh

diff --git a/libdtrace/Build b/libdtrace/Build
index 89972c66..a392c5f3 100644
--- a/libdtrace/Build
+++ b/libdtrace/Build
@@ -49,6 +49,7 @@ libdtrace-build_SOURCES = dt_aggregate.c \
 			  dt_prov_cpc.c \
 			  dt_prov_dtrace.c \
 			  dt_prov_fbt.c \
+			  dt_prov_lockstat.c \
 			  dt_prov_proc.c \
 			  dt_prov_profile.c \
 			  dt_prov_rawtp.c \
@@ -95,6 +96,7 @@ dt_prov_cpc.c_CFLAGS := -Wno-pedantic
 dt_prov_dtrace.c_CFLAGS := -Wno-pedantic
 dt_prov_fbt.c_CFLAGS := -Wno-pedantic
 dt_prov_proc.c_CFLAGS := -Wno-pedantic
+dt_prov_lockstat.c_CFLAGS := -Wno-pedantic
 dt_prov_profile.c_CFLAGS := -Wno-pedantic
 dt_prov_rawtp.c_CFLAGS := -Wno-pedantic
 dt_prov_sched.c_CFLAGS := -Wno-pedantic
diff --git a/libdtrace/dt_bpf_maps.h b/libdtrace/dt_bpf_maps.h
index 68b34b82..0dd36b16 100644
--- a/libdtrace/dt_bpf_maps.h
+++ b/libdtrace/dt_bpf_maps.h
@@ -34,8 +34,12 @@ struct dt_bpf_specs {
 typedef struct dt_bpf_cpuinfo	dt_bpf_cpuinfo_t;
 struct dt_bpf_cpuinfo {
 	cpuinfo_t	ci;
-	uint64_t	buf_drops;
-	uint64_t	agg_drops;
+	uint64_t	buf_drops;	/* CPU principal drop counter */
+	uint64_t	agg_drops;	/* CPU aggregation drop counter */
+	uint64_t	lockstat_lock;	/* lockstat: lock being traced */
+	uint64_t	lockstat_bfrom;	/* lockstat: block time start */
+	uint64_t	lockstat_btime;	/* lockstat: block time */
+	uint64_t	lockstat_stime;	/* lockstat: spin time */
 };
 
 #ifdef  __cplusplus
diff --git a/libdtrace/dt_open.c b/libdtrace/dt_open.c
index 110d45bc..b6a0b623 100644
--- a/libdtrace/dt_open.c
+++ b/libdtrace/dt_open.c
@@ -68,6 +68,7 @@ static const dt_provimpl_t *dt_providers[] = {
 	&dt_dtrace,		/* list dt_dtrace first */
 	&dt_cpc,
 	&dt_fbt,
+	&dt_lockstat,
 	&dt_proc,
 	&dt_profile,
 	&dt_rawtp,
diff --git a/libdtrace/dt_prov_lockstat.c b/libdtrace/dt_prov_lockstat.c
new file mode 100644
index 00000000..cc827660
--- /dev/null
+++ b/libdtrace/dt_prov_lockstat.c
@@ -0,0 +1,384 @@
+/*
+ * Oracle Linux DTrace.
+ * Copyright (c) 2023, 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.
+ *
+ * The 'lockstat' SDT provider for DTrace-specific probes.
+ */
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "dt_dctx.h"
+#include "dt_cg.h"
+#include "dt_provider_sdt.h"
+#include "dt_probe.h"
+
+static const char		prvname[] = "lockstat";
+static const char		modname[] = "vmlinux";
+
+static probe_dep_t	probes[] = {
+	{ "adaptive-acquire",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::mutex_lock" },
+	{ "adaptive-acquire-error",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::*mutex_lock_killable" },
+	{ "adaptive-acquire-error",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::*mutex_lock_interruptible" },
+	{ "adaptive-block",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::mutex_lock" },
+	{ "adaptive-block",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::schedule_preempt_disabled" },
+	{ "adaptive-release",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::mutex_unlock" },
+	{ "adaptive-spin",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::mutex_lock" },
+	{ "adaptive-spin",
+	   DTRACE_PROBESPEC_NAME,	"fbt::_raw_spin_lock:entry" },
+	{ "rw-acquire",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_read_lock*" },
+	{ "rw-acquire",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_read_trylock*" },
+	{ "rw-acquire",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_write_lock*" },
+	{ "rw-acquire",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_write_trylock*" },
+	{ "rw-release",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_read_unlock*" },
+	{ "rw-release",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_write_unlock*" },
+	{ "rw-spin",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::queued_read_lock_slowpath" },
+	{ "rw-spin",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::queued_write_lock_slowpath" },
+	{ "spin-acquire",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_spin_lock*" },
+	{ "spin-acquire",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_spin_trylock*" },
+	{ "spin-release",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::_raw_spin_unlock*" },
+	{ "spin-spin",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::queued_spin_lock_*" },
+	{ "spin-spin",
+	   DTRACE_PROBESPEC_FUNC,	"fbt::native_queued_spin_lock_*" },
+	{ NULL, }
+};
+
+static probe_arg_t probe_args[] = {
+	{ "adaptive-acquire", 0, { 0, 0, "struct mutex *" } },
+	{ "adaptive-acquire-error", 0, { 0, 0, "struct mutex *" } },
+	{ "adaptive-acquire-error", 1, { 1, 0, "int" } },
+	{ "adaptive-block", 0, { 0, 0, "struct mutex *" } },
+	{ "adaptive-block", 1, { 1, 0, "uint64_t" } },
+	{ "adaptive-release", 0, { 0, 0, "struct mutex *" } },
+	{ "adaptive-spin", 0, { 0, 0, "struct mutex *" } },
+	{ "adaptive-spin", 1, { 1, 0, "uint64_t" } },
+	{ "rw-acquire", 0, { 0, 0, "struct rwlock *" } },
+	{ "rw-acquire", 1, { 1, 0, "int" } },
+	{ "rw-release", 0, { 0, 0, "struct rwlock *" } },
+	{ "rw-release", 1, { 1, 0, "int" } },
+	{ "rw-spin", 0, { 0, 0, "struct rwlock *" } },
+	{ "rw-spin", 1, { 1, 0, "uint64_t" } },
+	{ "rw-spin", 2, { 2, 0, "int" } },
+	{ "spin-acquire", 0, { 0, 0, "spinlock_t *" } },
+	{ "spin-release", 0, { 0, 0, "spinlock_t *" } },
+	{ "spin-spin", 0, { 0, 0, "spinlock_t *" } },
+	{ "spin-spin", 1, { 1, 0, "uint64_t" } },
+	{ NULL, }
+};
+
+static const dtrace_pattr_t	pattr = {
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+{ DTRACE_STABILITY_EVOLVING, DTRACE_STABILITY_EVOLVING, DTRACE_CLASS_ISA },
+};
+
+/*
+ * Provide all the "lockstat" SDT probes.
+ */
+static int populate(dtrace_hdl_t *dtp)
+{
+	return dt_sdt_populate(dtp, prvname, modname, &dt_lockstat, &pattr,
+			       probe_args, probes);
+}
+
+/*
+ * Get a reference to the cpuinfo structure for the current CPU.
+ *
+ * Clobbers %r0 through %r5
+ * Stores pointer to cpuinfo struct in %r6
+ */
+static void get_cpuinfo(dtrace_hdl_t *dtp, dt_irlist_t *dlp, uint_t exitlbl)
+{
+	dt_ident_t	*idp = dt_dlib_get_map(dtp, "cpuinfo");
+
+	assert(idp != NULL);
+	dt_cg_xsetx(dlp, idp, DT_LBL_NONE, BPF_REG_1, idp->di_id);
+	emit(dlp, BPF_MOV_REG(BPF_REG_2, BPF_REG_FP));
+	emit(dlp, BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, DT_TRAMP_SP_BASE));
+	emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_2, 0, 0));
+	emit(dlp, BPF_CALL_HELPER(BPF_FUNC_map_lookup_elem));
+	emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_0, 0, exitlbl));
+	emit(dlp, BPF_MOV_REG(BPF_REG_6, BPF_REG_0));
+}
+
+/*
+ * Copy the lock address from args[n] into the per-CPU cpuinfo structure
+ * referenced by %r6.
+ *
+ * Clobbers %r1
+ */
+static void copy_lockaddr_into_cpuinfo(dt_irlist_t *dlp, int n)
+{
+	emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(n)));
+	emit(dlp, BPF_STORE(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_lock), BPF_REG_1));
+}
+
+/*
+ * Copy the lock address from the per-CPU cpuinfo structure referenced by %r6
+ * into args[n], and reset the lock address in the per-CPU cpuinfo structure
+ * to 0.  If lbl is not DT_LBL_NONE, it will be used to label the instruction
+ * that resets the lock address in cpuinfo.
+ *
+ * Clobbers %r1
+ */
+static void copy_lockaddr_from_cpuinfo(dt_irlist_t *dlp, int n, uint_t lbl)
+{
+	emit(dlp,  BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_lock)));
+	emit(dlp,  BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(n), BPF_REG_1));
+
+	emitl(dlp, lbl,
+		   BPF_STORE_IMM(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_lock), 0));
+}
+
+/*
+ * Generate a BPF trampoline for a SDT probe.
+ *
+ * The trampoline function is called when a SDT probe triggers, and it must
+ * satisfy the following prototype:
+ *
+ *	int dt_lockstat(void *data)
+ *
+ * The trampoline will populate a dt_dctx_t struct and then call the function
+ * that implements the compiled D clause.  It returns the value that it gets
+ * back from that function.
+ */
+static int trampoline(dt_pcb_t *pcb, uint_t exitlbl)
+{
+	dtrace_hdl_t	*dtp = pcb->pcb_hdl;
+	dt_irlist_t	*dlp = &pcb->pcb_ir;
+	dt_probe_t	*prp = pcb->pcb_probe;
+	dt_probe_t	*uprp = pcb->pcb_parent_probe;
+
+	assert(uprp != NULL);
+
+	get_cpuinfo(dtp, dlp, exitlbl);
+
+	if (strcmp(prp->desc->prb, "adaptive-acquire") == 0 ||
+	    strcmp(prp->desc->prb, "adaptive-release") == 0) {
+		if (strcmp(uprp->desc->prb, "entry") == 0) {
+			copy_lockaddr_into_cpuinfo(dlp, 0);
+			return 1;
+		} else {
+			copy_lockaddr_from_cpuinfo(dlp, 0, DT_LBL_NONE);
+			return 0;
+		}
+	} else if (strcmp(prp->desc->prb, "adaptive-acquire-error") == 0) {
+		if (strcmp(uprp->desc->prb, "entry") == 0) {
+			copy_lockaddr_into_cpuinfo(dlp, 0);
+			return 1;
+		} else {
+			/*
+			 * args[1] is already set by the underlying probe, but
+			 * we only report the adaptive-acquire-error probe if
+			 * the value is not 0.
+			 */
+			emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(1)));
+			emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_1, 0, exitlbl));
+			copy_lockaddr_from_cpuinfo(dlp, 0, DT_LBL_NONE);
+			return 0;
+		}
+	} else if (strcmp(prp->desc->prb, "adaptive-block") == 0) {
+		/*
+		 * - mutex_lock:entry inits lockstat_btime (0) and stores lock.
+		 * - schedule_preempt_disabled:entry sets lockstat_bfrom
+		 * - schedule_preempt_disabled:return increments lockstat_bfrom
+		 * - mutex_lock:return sets the adaptive-block arguments
+		 */
+		if (strcmp(uprp->desc->prb, "entry") == 0) {
+			if (strcmp(uprp->desc->fun, "mutex_lock") == 0) {
+				copy_lockaddr_into_cpuinfo(dlp, 0);
+
+				/* Initialize lockstat_btime. */
+				emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_btime), 0));
+			} else {
+				/* Store the start time. */
+				emit(dlp, BPF_CALL_HELPER(BPF_FUNC_ktime_get_ns));
+				emit(dlp, BPF_STORE(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_bfrom), BPF_REG_0));
+			}
+
+			return 1;
+		} else {
+			if (strcmp(uprp->desc->fun, "mutex_lock") != 0) {
+				/* Increment the block time. */
+				emit(dlp, BPF_CALL_HELPER(BPF_FUNC_ktime_get_ns));
+				emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_bfrom)));
+				emit(dlp, BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1));
+				emit(dlp, BPF_XADD_REG(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_btime), BPF_REG_0));
+
+				return 1;
+			} else {
+				/*
+				 * If lockstat_btime = 0, bail.
+				 * Otherwise arg1 = lockstat_btime.
+				 */
+				emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_btime)));
+				emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_1, 0, exitlbl));
+				emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_1));
+
+				copy_lockaddr_from_cpuinfo(dlp, 0, DT_LBL_NONE);
+				return 0;
+			}
+		}
+	} else if (strcmp(prp->desc->prb, "adaptive-spin") == 0) {
+		/*
+		 * - mutex_lock:entry stores lock and inits lockstat_stime (0).
+		 * - _raw_spin_lock:entry sets lockstat_stime
+		 * - mutex_lock:return sets the adaptive-spin arguments
+		 */
+		if (strcmp(uprp->desc->prb, "entry") == 0) {
+			if (strcmp(uprp->desc->fun, "mutex_lock") == 0) {
+				copy_lockaddr_into_cpuinfo(dlp, 0);
+
+				/* Initialize lockstat_stime. */
+				emit(dlp, BPF_STORE_IMM(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_stime), 0));
+			} else {
+				/* Store the start time in lockstat_stime. */
+				emit(dlp, BPF_CALL_HELPER(BPF_FUNC_ktime_get_ns));
+				emit(dlp, BPF_STORE(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_stime), BPF_REG_0));
+			}
+
+			return 1;
+		} else {
+			/*
+			 * If lockstat_stime is 0, bail.
+			 * Otherwise, arg1 = time - lockstat_stime.
+			 */
+			emit(dlp, BPF_CALL_HELPER(BPF_FUNC_ktime_get_ns));
+			emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_stime)));
+			emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_1, 0, exitlbl));
+			emit(dlp, BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1));
+			emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_0));
+
+			copy_lockaddr_from_cpuinfo(dlp, 0, DT_LBL_NONE);
+			return 0;
+		}
+	} else if (strcmp(prp->desc->prb, "rw-acquire") == 0) {
+		if (strcmp(uprp->desc->prb, "entry") == 0) {
+			copy_lockaddr_into_cpuinfo(dlp, 0);
+			return 1;
+		} else {
+			int	kind = 1;	/* reader (default) */
+			uint_t	lbl_reset = dt_irlist_label(dlp);;
+
+			if (strstr(uprp->desc->fun, "_write_") != NULL)
+				kind = 0;	/* writer */
+
+			if (strstr(uprp->desc->fun, "_trylock") != NULL) {
+				/* The return value (arg1) must be 1. */
+				emit(dlp,  BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(1)));
+				emit(dlp,  BPF_BRANCH_IMM(BPF_JNE, BPF_REG_1, 1, lbl_reset));
+			}
+
+			/* Set arg1 = kind. */
+			emit(dlp,  BPF_STORE_IMM(BPF_DW, BPF_REG_7, DMST_ARG(1), kind));
+
+			copy_lockaddr_from_cpuinfo(dlp, 0, lbl_reset);
+			return 0;
+		}
+	} else if (strcmp(prp->desc->prb, "rw-spin") == 0) {
+		/*
+		 * - *_lock_slowpath:entry stores lock and sets lockstat_stime
+		 * - *_lock_slowpath:return sets the rw-spin arguments
+		 */
+		if (strcmp(uprp->desc->prb, "entry") == 0) {
+			copy_lockaddr_into_cpuinfo(dlp, 0);
+
+			/* Store the start time in lockstat_stime. */
+			emit(dlp, BPF_CALL_HELPER(BPF_FUNC_ktime_get_ns));
+			emit(dlp, BPF_STORE(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_stime), BPF_REG_0));
+
+			return 1;
+		} else {
+			/*
+			 * If lockstat_stime is 0, bail.
+			 * Otherwise, arg1 = time - lockstat_stime.
+			 */
+			emit(dlp, BPF_CALL_HELPER(BPF_FUNC_ktime_get_ns));
+			emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_stime)));
+			emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_1, 0, exitlbl));
+			emit(dlp, BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1));
+			emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_0));
+
+			copy_lockaddr_from_cpuinfo(dlp, 0, DT_LBL_NONE);
+			return 0;
+		}
+	} else if (strcmp(prp->desc->prb, "spin-acquire") == 0) {
+		if (strcmp(uprp->desc->prb, "entry") == 0) {
+			copy_lockaddr_into_cpuinfo(dlp, 0);
+			return 1;
+		} else {
+			uint_t	lbl_reset = dt_irlist_label(dlp);;
+
+			if (strstr(uprp->desc->fun, "_trylock") != NULL) {
+				/* The return value (arg1) must be 1. */
+				emit(dlp,  BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_7, DMST_ARG(1)));
+				emit(dlp,  BPF_BRANCH_IMM(BPF_JNE, BPF_REG_1, 1, lbl_reset));
+			}
+
+			copy_lockaddr_from_cpuinfo(dlp, 0, lbl_reset);
+			return 0;
+		}
+	} else if (strcmp(prp->desc->prb, "spin-spin") == 0) {
+		/*
+		 * - *_lock_slowpath:entry stores lock and sets lockstat_stime
+		 * - *_lock_slowpath:return sets the rw-spin arguments
+		 */
+		if (strcmp(uprp->desc->prb, "entry") == 0) {
+			copy_lockaddr_into_cpuinfo(dlp, 0);
+
+			/* Store the start time in lockstat_stime. */
+			emit(dlp, BPF_CALL_HELPER(BPF_FUNC_ktime_get_ns));
+			emit(dlp, BPF_STORE(BPF_DW, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_stime), BPF_REG_0));
+
+			return 1;
+		} else {
+			/*
+			 * If lockstat_stime is 0, bail.
+			 * Otherwise, arg1 = time - lockstat_stime.
+			 */
+			emit(dlp, BPF_CALL_HELPER(BPF_FUNC_ktime_get_ns));
+			emit(dlp, BPF_LOAD(BPF_DW, BPF_REG_1, BPF_REG_6, offsetof(dt_bpf_cpuinfo_t, lockstat_stime)));
+			emit(dlp, BPF_BRANCH_IMM(BPF_JEQ, BPF_REG_1, 0, exitlbl));
+			emit(dlp, BPF_ALU64_REG(BPF_SUB, BPF_REG_0, BPF_REG_1));
+			emit(dlp, BPF_STORE(BPF_DW, BPF_REG_7, DMST_ARG(1), BPF_REG_0));
+
+			copy_lockaddr_from_cpuinfo(dlp, 0, DT_LBL_NONE);
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+dt_provimpl_t	dt_lockstat = {
+	.name		= prvname,
+	.prog_type	= BPF_PROG_TYPE_UNSPEC,
+	.populate	= &populate,
+	.enable		= &dt_sdt_enable,
+	.trampoline	= &trampoline,
+	.probe_info	= &dt_sdt_probe_info,
+	.destroy	= &dt_sdt_destroy,
+};
diff --git a/libdtrace/dt_provider.h b/libdtrace/dt_provider.h
index 252a73d4..8face769 100644
--- a/libdtrace/dt_provider.h
+++ b/libdtrace/dt_provider.h
@@ -70,6 +70,7 @@ typedef struct dt_provimpl {
 extern dt_provimpl_t dt_dtrace;
 extern dt_provimpl_t dt_cpc;
 extern dt_provimpl_t dt_fbt;
+extern dt_provimpl_t dt_lockstat;
 extern dt_provimpl_t dt_proc;
 extern dt_provimpl_t dt_profile;
 extern dt_provimpl_t dt_rawtp;
diff --git a/test/demo/lockstat/whatlock.d b/test/demo/lockstat/whatlock.d
index a7c2bbe4..552ec758 100644
--- a/test/demo/lockstat/whatlock.d
+++ b/test/demo/lockstat/whatlock.d
@@ -4,7 +4,6 @@
  * Licensed under the Universal Permissive License v 1.0 as shown at
  * http://oss.oracle.com/licenses/upl.
  */
-/* @@xfail: dtv2 */
 
 lockstat:::adaptive-acquire
 /execname == "date"/
diff --git a/test/unittest/lockstat/test.x b/test/unittest/lockstat/test.x
deleted file mode 100755
index 4f096dec..00000000
--- a/test/unittest/lockstat/test.x
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/bash
-# Licensed under the Universal Permissive License v 1.0 as shown at
-# http://oss.oracle.com/licenses/upl.
-#
-if ! check_provider lockstat; then
-        echo "Could not load lockstat provider"
-        exit 1
-fi
-exit 0
diff --git a/test/unittest/lockstat/tst.lv-adaptive-acquire-error.r b/test/unittest/lockstat/tst.lv-adaptive-acquire-error.r
new file mode 100644
index 00000000..26ab394c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-acquire-error.r
@@ -0,0 +1,16 @@
+PROBE lockstat vmlinux adaptive-acquire-error
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: struct mutex *
+		args[1]: int
+
diff --git a/test/unittest/lockstat/tst.lv-adaptive-acquire-error.r.p b/test/unittest/lockstat/tst.lv-adaptive-acquire-error.r.p
new file mode 100755
index 00000000..20978428
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-acquire-error.r.p
@@ -0,0 +1,6 @@
+#!/usr/bin/awk -f
+NR == 1 { next; }
+NR == 2 && NF == 5 { $1 = "PROBE"; $4 = ""; gsub(/  +/, " "); print; next; }
+NR == 2 && NF == 4 { $1 = "PROBE"; gsub(/  +/, " "); print; next; }
+/^ *[0-9]+/ { exit; }
+{ print; }
diff --git a/test/unittest/lockstat/tst.lv-adaptive-acquire-error.sh b/test/unittest/lockstat/tst.lv-adaptive-acquire-error.sh
new file mode 100755
index 00000000..725b5fe5
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-acquire-error.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::adaptive-acquire-error
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-adaptive-acquire.r b/test/unittest/lockstat/tst.lv-adaptive-acquire.r
new file mode 100644
index 00000000..3abfd74d
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-acquire.r
@@ -0,0 +1,15 @@
+PROBE lockstat vmlinux adaptive-acquire
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: struct mutex *
+
diff --git a/test/unittest/lockstat/tst.lv-adaptive-acquire.r.p b/test/unittest/lockstat/tst.lv-adaptive-acquire.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-acquire.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-adaptive-acquire.sh b/test/unittest/lockstat/tst.lv-adaptive-acquire.sh
new file mode 100755
index 00000000..a4097f0a
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-acquire.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::adaptive-acquire
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-adaptive-block.r b/test/unittest/lockstat/tst.lv-adaptive-block.r
new file mode 100644
index 00000000..fb86f9b2
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-block.r
@@ -0,0 +1,16 @@
+PROBE lockstat vmlinux adaptive-block
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: struct mutex *
+		args[1]: uint64_t
+
diff --git a/test/unittest/lockstat/tst.lv-adaptive-block.r.p b/test/unittest/lockstat/tst.lv-adaptive-block.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-block.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-adaptive-block.sh b/test/unittest/lockstat/tst.lv-adaptive-block.sh
new file mode 100755
index 00000000..857e049b
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-block.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::adaptive-block
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-adaptive-release.r b/test/unittest/lockstat/tst.lv-adaptive-release.r
new file mode 100644
index 00000000..ae9faf4e
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-release.r
@@ -0,0 +1,15 @@
+PROBE lockstat vmlinux adaptive-release
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: struct mutex *
+
diff --git a/test/unittest/lockstat/tst.lv-adaptive-release.r.p b/test/unittest/lockstat/tst.lv-adaptive-release.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-release.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-adaptive-release.sh b/test/unittest/lockstat/tst.lv-adaptive-release.sh
new file mode 100755
index 00000000..017b45f5
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-release.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::adaptive-release
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-adaptive-spin.r b/test/unittest/lockstat/tst.lv-adaptive-spin.r
new file mode 100644
index 00000000..664bc6fb
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-spin.r
@@ -0,0 +1,16 @@
+PROBE lockstat vmlinux adaptive-spin
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: struct mutex *
+		args[1]: uint64_t
+
diff --git a/test/unittest/lockstat/tst.lv-adaptive-spin.r.p b/test/unittest/lockstat/tst.lv-adaptive-spin.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-spin.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-adaptive-spin.sh b/test/unittest/lockstat/tst.lv-adaptive-spin.sh
new file mode 100755
index 00000000..335c4b4b
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-adaptive-spin.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::adaptive-spin
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-rw-acquire.r b/test/unittest/lockstat/tst.lv-rw-acquire.r
new file mode 100644
index 00000000..9b6c938e
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-acquire.r
@@ -0,0 +1,16 @@
+PROBE lockstat vmlinux rw-acquire
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: struct rwlock *
+		args[1]: int
+
diff --git a/test/unittest/lockstat/tst.lv-rw-acquire.r.p b/test/unittest/lockstat/tst.lv-rw-acquire.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-acquire.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-rw-acquire.sh b/test/unittest/lockstat/tst.lv-rw-acquire.sh
new file mode 100755
index 00000000..16ffcab7
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-acquire.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::rw-acquire
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-rw-release.r b/test/unittest/lockstat/tst.lv-rw-release.r
new file mode 100644
index 00000000..15a7a884
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-release.r
@@ -0,0 +1,16 @@
+PROBE lockstat vmlinux rw-release
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: struct rwlock *
+		args[1]: int
+
diff --git a/test/unittest/lockstat/tst.lv-rw-release.r.p b/test/unittest/lockstat/tst.lv-rw-release.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-release.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-rw-release.sh b/test/unittest/lockstat/tst.lv-rw-release.sh
new file mode 100755
index 00000000..6cf7529b
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-release.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::rw-release
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-rw-spin.r b/test/unittest/lockstat/tst.lv-rw-spin.r
new file mode 100644
index 00000000..c5a2ddc0
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-spin.r
@@ -0,0 +1,17 @@
+PROBE lockstat vmlinux rw-spin
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: struct rwlock *
+		args[1]: uint64_t
+		args[2]: int
+
diff --git a/test/unittest/lockstat/tst.lv-rw-spin.r.p b/test/unittest/lockstat/tst.lv-rw-spin.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-spin.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-rw-spin.sh b/test/unittest/lockstat/tst.lv-rw-spin.sh
new file mode 100755
index 00000000..328d33c2
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-rw-spin.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::rw-spin
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-spin-acquire.r b/test/unittest/lockstat/tst.lv-spin-acquire.r
new file mode 100644
index 00000000..e22d8362
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-acquire.r
@@ -0,0 +1,15 @@
+PROBE lockstat vmlinux spin-acquire
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: spinlock_t *
+
diff --git a/test/unittest/lockstat/tst.lv-spin-acquire.r.p b/test/unittest/lockstat/tst.lv-spin-acquire.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-acquire.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-spin-acquire.sh b/test/unittest/lockstat/tst.lv-spin-acquire.sh
new file mode 100755
index 00000000..fe618217
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-acquire.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::spin-acquire
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-spin-release.r b/test/unittest/lockstat/tst.lv-spin-release.r
new file mode 100644
index 00000000..93957999
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-release.r
@@ -0,0 +1,15 @@
+PROBE lockstat vmlinux spin-release
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: spinlock_t *
+
diff --git a/test/unittest/lockstat/tst.lv-spin-release.r.p b/test/unittest/lockstat/tst.lv-spin-release.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-release.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-spin-release.sh b/test/unittest/lockstat/tst.lv-spin-release.sh
new file mode 100755
index 00000000..4330ecdf
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-release.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::spin-release
+exit $?
diff --git a/test/unittest/lockstat/tst.lv-spin-spin.r b/test/unittest/lockstat/tst.lv-spin-spin.r
new file mode 100644
index 00000000..b94ad870
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-spin.r
@@ -0,0 +1,16 @@
+PROBE lockstat vmlinux spin-spin
+
+	Probe Description Attributes
+		Identifier Names: Private
+		Data Semantics:   Private
+		Dependency Class: Unknown
+
+	Argument Attributes
+		Identifier Names: Evolving
+		Data Semantics:   Evolving
+		Dependency Class: ISA
+
+	Argument Types
+		args[0]: spinlock_t *
+		args[1]: uint64_t
+
diff --git a/test/unittest/lockstat/tst.lv-spin-spin.r.p b/test/unittest/lockstat/tst.lv-spin-spin.r.p
new file mode 120000
index 00000000..e655901c
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-spin.r.p
@@ -0,0 +1 @@
+tst.lv-adaptive-acquire-error.r.p
\ No newline at end of file
diff --git a/test/unittest/lockstat/tst.lv-spin-spin.sh b/test/unittest/lockstat/tst.lv-spin-spin.sh
new file mode 100755
index 00000000..9524f97b
--- /dev/null
+++ b/test/unittest/lockstat/tst.lv-spin-spin.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2023, 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
+
+$dtrace $dt_flags -lvn lockstat:::spin-spin
+exit $?
-- 
2.40.1




More information about the DTrace-devel mailing list