From: Dmitrii Dolgov <9erthalion6@gmail.com>
To: linux-perf-users@vger.kernel.org,
Namhyung Kim <namhyung@kernel.org>,
Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Dmitrii Dolgov <9erthalion6@gmail.com>
Subject: [RFC PATCH v1] perf tests: Test annotate with data type profiling and rust
Date: Tue, 27 Jan 2026 09:30:27 +0100 [thread overview]
Message-ID: <20260127083030.5909-1-9erthalion6@gmail.com> (raw)
Exercise the annotate command with data type profiling feature on the
rust runtime:
* Add a new type of workload code_with_type, which has a dummy rust
library linked with it. It's recommended that for such scenarios rust
library is statically linked [1].
* Add a new shell test, which will profile the new workload, then
annotate the result expecting to see some data structures from the
rust code.
[1]: https://doc.rust-lang.org/reference/linkage.html#mixed-rust-and-foreign-codebases
Signed-off-by: Dmitrii Dolgov <9erthalion6@gmail.com>
---
tools/build/Makefile.build | 14 ++++
tools/perf/Makefile.perf | 2 +-
tools/perf/tests/builtin-test.c | 1 +
tools/perf/tests/shell/data_type_profiling.sh | 69 +++++++++++++++++++
tools/perf/tests/tests.h | 1 +
tools/perf/tests/workloads/Build | 2 +
tools/perf/tests/workloads/code_with_type.c | 46 +++++++++++++
tools/perf/tests/workloads/code_with_type.rs | 23 +++++++
tools/scripts/Makefile.include | 2 +
9 files changed, 159 insertions(+), 1 deletion(-)
create mode 100755 tools/perf/tests/shell/data_type_profiling.sh
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 3584ff30860..672ddbe2f4d 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/ \
+ --out-dir $(dir $@) --emit=dep-info=$(depfile),link
+
+quiet_cmd_rustc_a_rs = $(RUSTC) $(quiet_modtag) $@
+ cmd_rustc_a_rs = $(rust_common_cmd) -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)lib%.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 45d5a59a02c..87762694315 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -273,7 +273,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 e2490652f03..183ccfe55a8 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -154,6 +154,7 @@ static struct test_workload *workloads[] = {
&workload__landlock,
&workload__traploop,
&workload__inlineloop,
+ &workload__code_with_type,
};
#define workloads__for_each(workload) \
diff --git a/tools/perf/tests/shell/data_type_profiling.sh b/tools/perf/tests/shell/data_type_profiling.sh
new file mode 100755
index 00000000000..33fc1ae6b26
--- /dev/null
+++ b/tools/perf/tests/shell/data_type_profiling.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+# perf data type profiling tests
+# SPDX-License-Identifier: GPL-2.0
+
+set -e
+
+# The logic below follows the same line as the annotate test, but looks for a
+# data type profiling manifestation
+testtype="# data-type: struct Buf"
+
+err=0
+perfdata=$(mktemp /tmp/__perf_test.perf.data.XXXXX)
+perfout=$(mktemp /tmp/__perf_test.perf.out.XXXXX)
+testprog="perf test -w code_with_type"
+
+cleanup() {
+ rm -rf "${perfdata}" "${perfout}"
+ rm -rf "${perfdata}".old
+
+ trap - EXIT TERM INT
+}
+
+trap_cleanup() {
+ echo "Unexpected signal in ${FUNCNAME[1]}"
+ cleanup
+ exit 1
+}
+trap trap_cleanup EXIT TERM INT
+
+test_basic_annotate() {
+ mode=$1
+ echo "${mode} perf annotate test"
+ if [ "x${mode}" == "xBasic" ]
+ then
+ perf record -o "${perfdata}" ${testprog} 2> /dev/null
+ else
+ perf record -o - ${testprog} 2> /dev/null > "${perfdata}"
+ fi
+ if [ "x$?" != "x0" ]
+ then
+ echo "${mode} annotate [Failed: perf record]"
+ err=1
+ return
+ fi
+
+ # Generate the annotated output file
+ if [ "x${mode}" == "xBasic" ]
+ then
+ perf annotate --code-with-type -i "${perfdata}" --stdio --percent-limit 10 2> /dev/null > "${perfout}"
+ else
+ perf annotate --code-with-type -i - --stdio 2> /dev/null --percent-limit 10 < "${perfdata}" > "${perfout}"
+ fi
+
+ # check if it has the target data type
+ if ! grep -q "${testtype}" "${perfout}"
+ then
+ echo "${mode} annotate [Failed: missing target data type]"
+ cat "${perfout}"
+ err=1
+ return
+ fi
+ echo "${mode} annotate test [Success]"
+}
+
+test_basic_annotate Basic
+test_basic_annotate Pipe
+
+cleanup
+exit $err
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index 1f0f8b267fb..cfa3a4562e9 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -241,6 +241,7 @@ DECLARE_WORKLOAD(datasym);
DECLARE_WORKLOAD(landlock);
DECLARE_WORKLOAD(traploop);
DECLARE_WORKLOAD(inlineloop);
+DECLARE_WORKLOAD(code_with_type);
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 866a00bd14a..cc9a938948e 100644
--- a/tools/perf/tests/workloads/Build
+++ b/tools/perf/tests/workloads/Build
@@ -9,6 +9,8 @@ perf-test-y += datasym.o
perf-test-y += landlock.o
perf-test-y += traploop.o
perf-test-y += inlineloop.o
+perf-test-y += code_with_type.o
+perf-test-y += libcode_with_type.a
CFLAGS_sqrtloop.o = -g -O0 -fno-inline -U_FORTIFY_SOURCE
CFLAGS_leafloop.o = -g -O0 -fno-inline -fno-omit-frame-pointer -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 00000000000..65d7be7dac2
--- /dev/null
+++ b/tools/perf/tests/workloads/code_with_type.c
@@ -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
index 00000000000..3b91e51919d
--- /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 ded48263dd5..b5ecf137feb 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
base-commit: 571d29baa07e83e637075239f379f91353c24ec9
--
2.49.0
next reply other threads:[~2026-01-27 8:30 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-01-27 8:30 Dmitrii Dolgov [this message]
2026-01-27 17:00 ` [RFC PATCH v1] perf tests: Test annotate with data type profiling and rust Arnaldo Carvalho de Melo
2026-01-30 8:44 ` Dmitry Dolgov
2026-02-01 10:33 ` Dmitry Dolgov
2026-02-03 14:45 ` Arnaldo Carvalho de Melo
2026-02-03 18:15 ` Ian Rogers
2026-02-04 21:52 ` Namhyung Kim
2026-02-04 22:18 ` Ian Rogers
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260127083030.5909-1-9erthalion6@gmail.com \
--to=9erthalion6@gmail.com \
--cc=acme@kernel.org \
--cc=linux-perf-users@vger.kernel.org \
--cc=namhyung@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox