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 <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>
This commit is contained in:
Dmitrii Dolgov 2026-02-08 13:22:24 +01:00 committed by Arnaldo Carvalho de Melo
parent 6a32fa5ccd
commit 2e05bb52a1
8 changed files with 99 additions and 1 deletions

View 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

View 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

View 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) \

View 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;

View 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

View file

@ -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);

View file

@ -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;
}
}

View 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