[DTrace-devel] [PATCH v2 2/5] Add -xcpu support to dtrace provider

eugene.loh at oracle.com eugene.loh at oracle.com
Thu Jan 11 05:13:30 UTC 2024


From: Eugene Loh <eugene.loh at oracle.com>

Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
 libdtrace/dt_impl.h                    |   1 +
 libdtrace/dt_work.c                    | 126 ++++++++++++++++++++++++-
 test/unittest/options/tst.cpu-BEGIN.sh |  22 +++++
 test/unittest/options/tst.cpu-END.sh   |  22 +++++
 4 files changed, 169 insertions(+), 2 deletions(-)
 create mode 100755 test/unittest/options/tst.cpu-BEGIN.sh
 create mode 100755 test/unittest/options/tst.cpu-END.sh

diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
index 6c261f69..9912ad65 100644
--- a/libdtrace/dt_impl.h
+++ b/libdtrace/dt_impl.h
@@ -414,6 +414,7 @@ struct dtrace_hdl {
 	uint_t dt_stopped;	/* boolean:  set once tracing is stopped */
 	processorid_t dt_beganon; /* CPU that executed BEGIN probe (if any) */
 	processorid_t dt_endedon; /* CPU that executed END probe (if any) */
+	void *dt_beginendargs;	/* args for child running BEGIN and END probes */
 	uint_t dt_oflags;	/* dtrace open-time options (see dtrace.h) */
 	uint_t dt_cflags;	/* dtrace compile-time options (see dtrace.h) */
 	uint_t dt_dflags;	/* dtrace link-time options (see dtrace.h) */
diff --git a/libdtrace/dt_work.c b/libdtrace/dt_work.c
index fe88a48e..9946f30e 100644
--- a/libdtrace/dt_work.c
+++ b/libdtrace/dt_work.c
@@ -131,6 +131,76 @@ dtrace_status(dtrace_hdl_t *dtp)
 	return DTRACE_STATUS_OKAY;
 }
 
+#define CMD_BEGIN	1234
+#define CMD_END		5678
+typedef struct dt_beginendargs {
+	pthread_t	thr;
+	processorid_t	cpu;
+	processorid_t	ncpus;
+	int	tochild[2];
+	int	frchild[2];
+} dt_beginendargs_t;
+
+static
+void bind_to_cpu(int cpu, int ncpus) {
+	cpu_set_t *mask;
+	size_t size;
+
+	/* Allocate the CPU mask and get its size. */
+	mask = CPU_ALLOC(ncpus);
+	if (mask == NULL)
+		exit(1);
+	size = CPU_ALLOC_SIZE(ncpus);
+
+	/* Set the CPU mask. */
+	CPU_ZERO_S(size, mask);
+	CPU_SET_S(cpu, size, mask);
+
+	/* Set my affinity. */
+	if (sched_setaffinity(0, size, mask) != 0) {
+		/* FIXME: some other failure mode? */
+		exit(1);
+	}
+
+	/* Free the mask. */
+	CPU_FREE(mask);
+}
+
+static unsigned long long
+elapsed_msecs() {
+	struct timespec tstruct;
+
+	clock_gettime(CLOCK_MONOTONIC, &tstruct);
+	return tstruct.tv_sec * 1000ull + tstruct.tv_nsec / 1000000;
+}
+
+static void *
+beginend_child(void *arg) {
+	dt_beginendargs_t *args = arg;
+	int cmd = 0;
+
+	/* Bind to requested CPU. */
+	bind_to_cpu(args->cpu, args->ncpus);
+
+	/* Wait for command, call BEGIN_probe(), and ack. */
+	read(args->tochild[0], &cmd, sizeof(cmd));
+	if (cmd != CMD_BEGIN)
+		exit(1);
+	BEGIN_probe();
+	cmd++;
+	write(args->frchild[1], &cmd, sizeof(cmd));
+
+	/* Wait for command, call END_probe(), and ack. */
+	read(args->tochild[0], &cmd, sizeof(cmd));
+	if (cmd != CMD_END)
+		exit(1);
+	END_probe();
+	cmd++;
+	write(args->frchild[1], &cmd, sizeof(cmd));
+
+	pthread_exit(0);
+}
+
 int
 dtrace_go(dtrace_hdl_t *dtp, uint_t cflags)
 {
@@ -140,6 +210,27 @@ dtrace_go(dtrace_hdl_t *dtp, uint_t cflags)
 	if (dtp->dt_active)
 		return dt_set_errno(dtp, EINVAL);
 
+	/*
+	 * Create a child for the BEGIN and END probes if -xcpu is used.
+	 */
+	if (dtp->dt_options[DTRACEOPT_CPU] != DTRACEOPT_UNSET) {
+		dt_beginendargs_t	*args;
+
+		args = dt_zalloc(dtp, sizeof(dt_beginendargs_t));
+		if (args == NULL)
+			return dt_set_errno(dtp, EDT_NOMEM);
+		pipe(args->tochild);
+		pipe2(args->frchild, O_NONBLOCK);
+		args->cpu = dtp->dt_options[DTRACEOPT_CPU];
+		args->ncpus = dtp->dt_conf.max_cpuid + 1;
+
+		if (pthread_create(&args->thr, NULL, &beginend_child, args)) {
+			printf("error pthread_create for -xcpu\n");
+			return -1;
+		}
+		dtp->dt_beginendargs = args;
+	}
+
 	/* Create the BPF programs. */
 	if (dt_bpf_make_progs(dtp, cflags) == -1)
 		return -1;
@@ -190,7 +281,22 @@ dtrace_go(dtrace_hdl_t *dtp, uint_t cflags)
 	if (dt_aggregate_go(dtp) == -1)
 		return -1;
 
-	if (RUNNING_ON_VALGRIND)
+	if (dtp->dt_beginendargs) {
+		/* Tell child running on a specific CPU to BEGIN. */
+		dt_beginendargs_t	*args = dtp->dt_beginendargs;
+		unsigned long long	timeout;
+		int			cmd = CMD_BEGIN;
+
+		write(args->tochild[1], &cmd, sizeof(cmd));
+		timeout = elapsed_msecs() + 2000;
+		while (read(args->frchild[0], &cmd, sizeof(cmd)) <= 0) {
+			usleep(100000);
+			if (elapsed_msecs() > timeout)
+				return -1;
+		}
+		if (cmd != CMD_BEGIN + 1)
+			return -1;
+	} else if (RUNNING_ON_VALGRIND)
 		VALGRIND_NON_SIMD_CALL0(BEGIN_probe);
 	else
 		BEGIN_probe();
@@ -223,7 +329,23 @@ dtrace_stop(dtrace_hdl_t *dtp)
 	if (dt_state_get_activity(dtp) < DT_ACTIVITY_DRAINING)
 		dt_state_set_activity(dtp, DT_ACTIVITY_DRAINING);
 
-	if (RUNNING_ON_VALGRIND)
+	if (dtp->dt_beginendargs) {
+		int			cmd = CMD_END;
+		dt_beginendargs_t	*args = dtp->dt_beginendargs;
+		unsigned long long	timeout;
+
+		write(args->tochild[1], &cmd, sizeof(cmd));
+		timeout = elapsed_msecs() + 2000;
+		while (read(args->frchild[0], &cmd, sizeof(cmd)) <= 0) {
+			usleep(100000);
+			if (elapsed_msecs() > timeout)
+				return -1;
+		}
+		if (cmd != CMD_END + 1)
+			return -1;
+		pthread_join(args->thr, NULL);
+		dt_free(dtp, args);
+	} else if (RUNNING_ON_VALGRIND)
 		VALGRIND_NON_SIMD_CALL0(END_probe);
 	else
 		END_probe();
diff --git a/test/unittest/options/tst.cpu-BEGIN.sh b/test/unittest/options/tst.cpu-BEGIN.sh
new file mode 100755
index 00000000..793ece8f
--- /dev/null
+++ b/test/unittest/options/tst.cpu-BEGIN.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2024, 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
+
+nerr=0
+for cpu0 in `awk '/^processor[ 	]*: [0-9]*$/ {print $3}' /proc/cpuinfo`; do
+	cpu=`$dtrace $dt_flags -xcpu=$cpu0 -qn 'BEGIN { trace(cpu); exit(0); }'`
+	echo expected cpu $cpu0 got cpu $cpu
+	if [ `echo $cpu | wc -w` -ne 1 ]; then
+		nerr=$(($nerr + 1))
+	elif [ $(($cpu + 0)) != $cpu0 ]; then
+		nerr=$(($nerr + 1))
+	fi
+done
+
+exit $nerr
diff --git a/test/unittest/options/tst.cpu-END.sh b/test/unittest/options/tst.cpu-END.sh
new file mode 100755
index 00000000..b77cbf3c
--- /dev/null
+++ b/test/unittest/options/tst.cpu-END.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Oracle Linux DTrace.
+# Copyright (c) 2024, 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
+
+nerr=0
+for cpu0 in `awk '/^processor[ 	]*: [0-9]*$/ {print $3}' /proc/cpuinfo`; do
+	cpu=`$dtrace $dt_flags -xcpu=$cpu0 -qn 'BEGIN { exit(0) } END { trace(cpu); }'`
+	echo expected cpu $cpu0 got cpu $cpu
+	if [ `echo $cpu | wc -w` -ne 1 ]; then
+		nerr=$(($nerr + 1))
+	elif [ $(($cpu + 0)) != $cpu0 ]; then
+		nerr=$(($nerr + 1))
+	fi
+done
+
+exit $nerr
-- 
2.18.4




More information about the DTrace-devel mailing list