]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
perf test workload: Add code_with_type test workload
authorDmitrii Dolgov <9erthalion6@gmail.com>
Sun, 8 Feb 2026 12:22:24 +0000 (13:22 +0100)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Sun, 8 Feb 2026 22:16:24 +0000 (19:16 -0300)
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 <acme@redhat.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/build/Makefile.build
tools/perf/Makefile.perf
tools/perf/tests/builtin-test.c
tools/perf/tests/tests.h
tools/perf/tests/workloads/Build
tools/perf/tests/workloads/code_with_type.c [new file with mode: 0644]
tools/perf/tests/workloads/code_with_type.rs [new file with mode: 0644]
tools/scripts/Makefile.include

index 3584ff30860786a848cdca684c636f916e2ed56e..60e65870eae145b33b80b972d5b3cc2f4bfcef74 100644 (file)
@@ -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
index 2a7e5814b159c5e4c597adc9d6f20190839b21a2..a6d8ca3e92338afa941121ffeb7bac4af23b86a4 100644 (file)
@@ -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
index e2490652f0308196e92cf17b5ec1c9026331ea7f..06507066213b10bd783d1a5580c23aa770262631 100644 (file)
@@ -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) \
index 1f0f8b267fb1a2fbc64761a75366020a959b34ef..f5f1238d1f7f23b5ad532874544392e205769591 100644 (file)
@@ -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;
 
index 866a00bd14a0cf89e612266d45941d66b2b88caf..2ef97f7affce4941612e106b4ac7df4980d57bf1 100644 (file)
@@ -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 (file)
index 0000000..65d7be7
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <pthread.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <unistd.h>
+#include <linux/compiler.h>
+#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 (file)
index 0000000..3b91e51
--- /dev/null
@@ -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;
+    }
+}
index ded48263dd5e05e174316eda7b309804923e9711..b5ecf137febcae59f506e107a7f2e2ad72f4bef4 100644 (file)
@@ -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