From 2e05bb52a12d3cdb81f3b6f5de5cb3905d383552 Mon Sep 17 00:00:00 2001 From: Dmitrii Dolgov <9erthalion6@gmail.com> Date: Sun, 8 Feb 2026 13:22:24 +0100 Subject: [PATCH] perf test workload: Add code_with_type test workload The purpose of the workload is to gather samples of rust runtime. To achieve that it has a dummy rust library linked with it. Per recommendations for such scenarios [1], the rust library is statically linked. An example: $ perf record perf test -w code_with_type [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.160 MB perf.data (4074 samples) ] $ perf report --stdio --dso perf -s srcfile,srcline 45.16% ub_checks.rs ub_checks.rs:72 6.72% code_with_type.rs code_with_type.rs:15 6.64% range.rs range.rs:767 4.26% code_with_type.rs code_with_type.rs:21 4.23% range.rs range.rs:0 3.99% code_with_type.rs code_with_type.rs:16 [...] [1]: https://doc.rust-lang.org/reference/linkage.html#mixed-rust-and-foreign-codebases Signed-off-by: Dmitrii Dolgov <9erthalion6@gmail.com> Tested-by: Arnaldo Carvalho de Melo Cc: Ian Rogers Cc: Namhyung Kim Signed-off-by: Arnaldo Carvalho de Melo --- tools/build/Makefile.build | 14 ++++++ tools/perf/Makefile.perf | 2 +- tools/perf/tests/builtin-test.c | 4 ++ tools/perf/tests/tests.h | 4 ++ tools/perf/tests/workloads/Build | 5 +++ tools/perf/tests/workloads/code_with_type.c | 46 ++++++++++++++++++++ tools/perf/tests/workloads/code_with_type.rs | 23 ++++++++++ tools/scripts/Makefile.include | 2 + 8 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 tools/perf/tests/workloads/code_with_type.c create mode 100644 tools/perf/tests/workloads/code_with_type.rs diff --git a/tools/build/Makefile.build b/tools/build/Makefile.build index 3584ff308607..60e65870eae1 100644 --- a/tools/build/Makefile.build +++ b/tools/build/Makefile.build @@ -76,6 +76,14 @@ quiet_cmd_host_ld_multi = HOSTLD $@ cmd_host_ld_multi = $(if $(strip $(obj-y)),\ $(HOSTLD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(HOSTAR) rcs $@) +rust_common_cmd = \ + $(RUSTC) $(rust_flags) \ + --crate-type staticlib -L $(objtree)/rust/ \ + --emit=dep-info=$(depfile),link + +quiet_cmd_rustc_a_rs = $(RUSTC) $(quiet_modtag) $@ + cmd_rustc_a_rs = $(rust_common_cmd) -o $@ -g $< $(cmd_objtool) + ifneq ($(filter $(obj),$(hostprogs)),) host = host_ endif @@ -105,6 +113,12 @@ $(OUTPUT)%.s: %.c FORCE $(call rule_mkdir) $(call if_changed_dep,cc_s_c) +# it's recommended to build a static rust library, when a foreight (to rust) +# linker is used. +$(OUTPUT)%.a: %.rs FORCE + $(call rule_mkdir) + $(call if_changed_dep,rustc_a_rs) + # bison and flex files are generated in the OUTPUT directory # so it needs a separate rule to depend on them properly $(OUTPUT)%-bison.o: $(OUTPUT)%-bison.c FORCE diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 2a7e5814b159..a6d8ca3e9233 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf @@ -271,7 +271,7 @@ ifeq ($(PYLINT),1) PYLINT := $(shell which pylint 2> /dev/null) endif -export srctree OUTPUT RM CC CXX LD AR CFLAGS CXXFLAGS V BISON FLEX AWK +export srctree OUTPUT RM CC CXX RUSTC LD AR CFLAGS CXXFLAGS V BISON FLEX AWK export HOSTCC HOSTLD HOSTAR HOSTCFLAGS SHELLCHECK MYPY PYLINT include $(srctree)/tools/build/Makefile.include diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index e2490652f030..06507066213b 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c @@ -154,6 +154,10 @@ static struct test_workload *workloads[] = { &workload__landlock, &workload__traploop, &workload__inlineloop, + +#ifdef HAVE_RUST_SUPPORT + &workload__code_with_type, +#endif }; #define workloads__for_each(workload) \ diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 1f0f8b267fb1..f5f1238d1f7f 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h @@ -242,6 +242,10 @@ DECLARE_WORKLOAD(landlock); DECLARE_WORKLOAD(traploop); DECLARE_WORKLOAD(inlineloop); +#ifdef HAVE_RUST_SUPPORT +DECLARE_WORKLOAD(code_with_type); +#endif + extern const char *dso_to_test; extern const char *test_objdump_path; diff --git a/tools/perf/tests/workloads/Build b/tools/perf/tests/workloads/Build index 866a00bd14a0..2ef97f7affce 100644 --- a/tools/perf/tests/workloads/Build +++ b/tools/perf/tests/workloads/Build @@ -10,6 +10,11 @@ perf-test-y += landlock.o perf-test-y += traploop.o perf-test-y += inlineloop.o +ifeq ($(CONFIG_RUST_SUPPORT),y) + perf-test-y += code_with_type.o + perf-test-y += code_with_type.a +endif + CFLAGS_sqrtloop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE CFLAGS_leafloop.o = -g -O0 -fno-inline -fno-omit-frame-pointer -U_FORTIFY_SOURCE CFLAGS_brstack.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE diff --git a/tools/perf/tests/workloads/code_with_type.c b/tools/perf/tests/workloads/code_with_type.c new file mode 100644 index 000000000000..65d7be7dac24 --- /dev/null +++ b/tools/perf/tests/workloads/code_with_type.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include "../tests.h" + +extern void test_rs(uint count); + +static volatile sig_atomic_t done; + +static void sighandler(int sig __maybe_unused) +{ + done = 1; +} + +static int code_with_type(int argc, const char **argv) +{ + int sec = 1, num_loops = 100; + + pthread_setname_np(pthread_self(), "perf-code-with-type"); + if (argc > 0) + sec = atoi(argv[0]); + + if (argc > 1) + num_loops = atoi(argv[1]); + + signal(SIGINT, sighandler); + signal(SIGALRM, sighandler); + alarm(sec); + + /* + * Rust doesn't have signal management in the standard library. To + * not deal with any external crates, offload signal handling to the + * outside code. + */ + while (!done) { + test_rs(num_loops); + continue; + } + + return 0; +} + +DEFINE_WORKLOAD(code_with_type); diff --git a/tools/perf/tests/workloads/code_with_type.rs b/tools/perf/tests/workloads/code_with_type.rs new file mode 100644 index 000000000000..3b91e51919dd --- /dev/null +++ b/tools/perf/tests/workloads/code_with_type.rs @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: GPL-2.0 + +// We're going to look for this structure in the data type profiling report +#[allow(dead_code)] +struct Buf { + data1: u64, + data2: String, + data3: u64, +} + +#[no_mangle] +pub extern "C" fn test_rs(count: u32) { + let mut b = Buf { data1: 0, data2: String::from("data"), data3: 0}; + + for _ in 1..count { + b.data1 += 1; + if b.data1 == 123 { + b.data1 += 1; + } + + b.data3 += b.data1; + } +} diff --git a/tools/scripts/Makefile.include b/tools/scripts/Makefile.include index ded48263dd5e..b5ecf137febc 100644 --- a/tools/scripts/Makefile.include +++ b/tools/scripts/Makefile.include @@ -94,6 +94,8 @@ LLVM_STRIP ?= llvm-strip # Some tools require bpftool SYSTEM_BPFTOOL ?= bpftool +RUSTC ?= rustc + ifeq ($(CC_NO_CLANG), 1) EXTRA_WARNINGS += -Wstrict-aliasing=3 -- 2.30.2