[DTrace-devel] [PATCH v2 2/5] Add -xcpu support to dtrace provider
Kris Van Hees
kris.van.hees at oracle.com
Wed Jan 17 16:42:07 UTC 2024
I think this will cause Valgrind not to work right with -xcpu. See below...
On Thu, Jan 11, 2024 at 12:13:30AM -0500, eugene.loh--- via DTrace-devel wrote:
> 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();
I believe this should be:
VALGRIND_NON_SIMD_CALL0(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();
I believe this should be:
VALGRIND_NON_SIMD_CALL0(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
>
>
> _______________________________________________
> 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