From 7c1e0811cb15bd4be1e9c0200d44f3075fe1ef3a Mon Sep 17 00:00:00 2001 From: Heath Mitchell Date: Mon, 24 Nov 2025 15:27:09 +0000 Subject: [PATCH 1/2] [llvm-profgen][SPGO] Support profiles with multiple concurrent processes --- .../Inputs/multi-process-cs-probe.perfbin | Bin 0 -> 17704 bytes .../Inputs/multi-process-cs-probe.perfscript | 30 +++ .../Inputs/multi-process-nocs-noprobe.perfbin | Bin 0 -> 17424 bytes .../multi-process-nocs-noprobe.perfscript | 12 ++ .../Inputs/multi-process-warning.perfscript | 12 ++ .../tools/llvm-profgen/multi-pid-filter.test | 39 ++++ .../llvm-profgen/multi-process-cs-probe.test | 46 +++++ .../multi-process-nocs-noprobe.test | 40 ++++ .../llvm-profgen/multi-process-warning.test | 10 + llvm/tools/llvm-profgen/PerfReader.cpp | 172 ++++++++++++++---- llvm/tools/llvm-profgen/PerfReader.h | 33 ++-- llvm/tools/llvm-profgen/ProfiledBinary.h | 28 ++- llvm/tools/llvm-profgen/llvm-profgen.cpp | 17 +- 13 files changed, 374 insertions(+), 65 deletions(-) create mode 100755 llvm/test/tools/llvm-profgen/Inputs/multi-process-cs-probe.perfbin create mode 100644 llvm/test/tools/llvm-profgen/Inputs/multi-process-cs-probe.perfscript create mode 100755 llvm/test/tools/llvm-profgen/Inputs/multi-process-nocs-noprobe.perfbin create mode 100644 llvm/test/tools/llvm-profgen/Inputs/multi-process-nocs-noprobe.perfscript create mode 100644 llvm/test/tools/llvm-profgen/Inputs/multi-process-warning.perfscript create mode 100644 llvm/test/tools/llvm-profgen/multi-pid-filter.test create mode 100644 llvm/test/tools/llvm-profgen/multi-process-cs-probe.test create mode 100644 llvm/test/tools/llvm-profgen/multi-process-nocs-noprobe.test create mode 100644 llvm/test/tools/llvm-profgen/multi-process-warning.test diff --git a/llvm/test/tools/llvm-profgen/Inputs/multi-process-cs-probe.perfbin b/llvm/test/tools/llvm-profgen/Inputs/multi-process-cs-probe.perfbin new file mode 100755 index 0000000000000000000000000000000000000000..6e98e86d236a442ff8d978ebe811ffa4f5ec0f7f GIT binary patch literal 17704 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 literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-profgen/Inputs/multi-process-cs-probe.perfscript b/llvm/test/tools/llvm-profgen/Inputs/multi-process-cs-probe.perfscript new file mode 100644 index 0000000000000..1e23ed3f81fde --- /dev/null +++ b/llvm/test/tools/llvm-profgen/Inputs/multi-process-cs-probe.perfscript @@ -0,0 +1,30 @@ +; Load first process + 262511 PERF_RECORD_MMAP2 262511/262511: [0x61f3acfa8000(0x1000) @ 0x1000 103:02 13931513 3957944494]: r-xp /home/multi-process-cs-probe.perfbin + +; Samples from first process + 262511 + 61f3acfa8155 + 61f3acfa81e9 + 78d7ee62a1ca + 78d7ee62a28b + 61f3acfa8065 + 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- + +; Load second process + 262512 PERF_RECORD_MMAP2 262512/262512: [0x5b3c4c631000(0x1000) @ 0x1000 103:02 13931513 3957944494]: r-xp /home/multi-process-cs-probe.perfbin + +; Samples from both processes + 262512 + 5b3c4c631195 + 5b3c4c63120c + 73bf70e2a1ca + 73bf70e2a28b + 5b3c4c631065 + 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/5/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/4/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/5/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/5/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/5/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/5/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/5/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- 0x5b3c4c631190/0x5b3c4c631195/P/-/-/1/UNCOND/- 0x5b3c4c6311a1/0x5b3c4c63117c/P/-/-/1/UNCOND/- + 262511 + 61f3acfa813c + 61f3acfa81e9 + 78d7ee62a1ca + 78d7ee62a28b + 61f3acfa8065 + 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/4/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- 0x61f3acfa8161/0x61f3acfa813c/P/-/-/1/UNCOND/- 0x61f3acfa8150/0x61f3acfa8155/P/-/-/1/UNCOND/- diff --git a/llvm/test/tools/llvm-profgen/Inputs/multi-process-nocs-noprobe.perfbin b/llvm/test/tools/llvm-profgen/Inputs/multi-process-nocs-noprobe.perfbin new file mode 100755 index 0000000000000000000000000000000000000000..b7859ec8d679442adf150a78e7b19c073e2958b9 GIT binary patch literal 17424 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 literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-profgen/Inputs/multi-process-nocs-noprobe.perfscript b/llvm/test/tools/llvm-profgen/Inputs/multi-process-nocs-noprobe.perfscript new file mode 100644 index 0000000000000..2ec2975cf07af --- /dev/null +++ b/llvm/test/tools/llvm-profgen/Inputs/multi-process-nocs-noprobe.perfscript @@ -0,0 +1,12 @@ +; Load first process + 149754 PERF_RECORD_MMAP2 149754/149754: [0x5ffeb3637000(0x1000) @ 0x1000 103:02 16291238 2733047042]: r-xp /home/multi-process-nocs-noprobe.perfbin + +; Samples from first process + 149754 5ffeb3637150 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- + +; Load second process + 149755 PERF_RECORD_MMAP2 149755/149755: [0x5caa46c41000(0x1000) @ 0x1000 103:02 16291238 2733047042]: r-xp /home/multi-process-nocs-noprobe.perfbin + +; Samples from both processes + 149755 5caa46c41190 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- + 149754 5ffeb3637161 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- diff --git a/llvm/test/tools/llvm-profgen/Inputs/multi-process-warning.perfscript b/llvm/test/tools/llvm-profgen/Inputs/multi-process-warning.perfscript new file mode 100644 index 0000000000000..bfca95dd26307 --- /dev/null +++ b/llvm/test/tools/llvm-profgen/Inputs/multi-process-warning.perfscript @@ -0,0 +1,12 @@ +; Load first process +PERF_RECORD_MMAP2 149754/149754: [0x5ffeb3637000(0x1000) @ 0x1000 103:02 16291238 2733047042]: r-xp /home/multi-process-nocs-noprobe.perfbin + +; Samples from first process + 5ffeb3637150 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- + +; Load second process +PERF_RECORD_MMAP2 149755/149755: [0x5caa46c41000(0x1000) @ 0x1000 103:02 16291238 2733047042]: r-xp /home/multi-process-nocs-noprobe.perfbin + +; Samples from both processes + 5caa46c41190 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- 0x5caa46c41190/0x5caa46c41195/P/-/-/1/UNCOND/- 0x5caa46c411a1/0x5caa46c4117c/P/-/-/1/UNCOND/- + 5ffeb3637161 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- 0x5ffeb3637161/0x5ffeb363713c/P/-/-/1/UNCOND/- 0x5ffeb3637150/0x5ffeb3637155/P/-/-/1/UNCOND/- diff --git a/llvm/test/tools/llvm-profgen/multi-pid-filter.test b/llvm/test/tools/llvm-profgen/multi-pid-filter.test new file mode 100644 index 0000000000000..0802a6b545555 --- /dev/null +++ b/llvm/test/tools/llvm-profgen/multi-pid-filter.test @@ -0,0 +1,39 @@ +; Test that the --pid argument works, including when passing multiple PIDs + +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/multi-process-nocs-noprobe.perfscript --binary=%S/Inputs/multi-process-nocs-noprobe.perfbin --output=%t --profile-summary-cold-count=0 --multi-process-profile --pid=149754 +; RUN: FileCheck %s --input-file %t --check-prefix=CHECK-FIRST-ONLY + +CHECK-FIRST-ONLY-NOT: loop2 + +CHECK-FIRST-ONLY: loop1:1302:0 +CHECK-FIRST-ONLY-NEXT: 0: 0 +CHECK-FIRST-ONLY-NEXT: 1: 31 +CHECK-FIRST-ONLY-NEXT: 2: 0 + +CHECK-FIRST-ONLY-NOT: loop2 + +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/multi-process-nocs-noprobe.perfscript --binary=%S/Inputs/multi-process-nocs-noprobe.perfbin --output=%t --profile-summary-cold-count=0 --multi-process-profile --pid=149755 +; RUN: FileCheck %s --input-file %t --check-prefix=CHECK-SECOND-ONLY + +CHECK-SECOND-ONLY-NOT: loop1 + +CHECK-SECOND-ONLY:loop2:655:0 +CHECK-SECOND-ONLY-NEXT: 0: 0 +CHECK-SECOND-ONLY-NEXT: 1: 16 +CHECK-SECOND-ONLY-NEXT: 2: 0 + +CHECK-SECOND-ONLY-NOT: loop1 + +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/multi-process-nocs-noprobe.perfscript --binary=%S/Inputs/multi-process-nocs-noprobe.perfbin --output=%t --profile-summary-cold-count=0 --multi-process-profile --pid=149754,149755 +; RUN: FileCheck %s --input-file %t --check-prefix=CHECK-BOTH + +CHECK-BOTH: loop1:1302:0 +CHECK-BOTH-NEXT: 0: 0 +CHECK-BOTH-NEXT: 1: 31 +CHECK-BOTH-NEXT: 2: 0 +CHECK-BOTH-NEXT:loop2:655:0 +CHECK-BOTH-NEXT: 0: 0 +CHECK-BOTH-NEXT: 1: 16 +CHECK-BOTH-NEXT: 2: 0 + +; original code can be found in multi-process-nocs-noprobe.test diff --git a/llvm/test/tools/llvm-profgen/multi-process-cs-probe.test b/llvm/test/tools/llvm-profgen/multi-process-cs-probe.test new file mode 100644 index 0000000000000..adc28040349ff --- /dev/null +++ b/llvm/test/tools/llvm-profgen/multi-process-cs-probe.test @@ -0,0 +1,46 @@ +; Check that we can handle profiles with multiple processes, using pseudo probes +; and a context-senstive profile + +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/multi-process-cs-probe.perfscript --binary=%S/Inputs/multi-process-cs-probe.perfbin --output=%t --profile-summary-cold-count=0 --multi-process-profile +; RUN: FileCheck %s --input-file %t + +CHECK: loop1:93:0 +CHECK-NEXT: 1: 0 +CHECK-NEXT: 2: 31 +CHECK-NEXT: 3: 31 +CHECK-NEXT: 4: 31 +CHECK-NEXT: 5: 0 +CHECK-NEXT: !CFGChecksum: 88680961901 +CHECK-NEXT:loop2:47:0 +CHECK-NEXT: 1: 0 +CHECK-NEXT: 2: 16 +CHECK-NEXT: 3: 16 +CHECK-NEXT: 4: 15 +CHECK-NEXT: 5: 0 +CHECK-NEXT: !CFGChecksum: 88680961901 + +; original code: +; clang -g -fpseudo-probe-for-profiling -fno-omit-frame-pointer test.c -o multi-process-cs-probe.perfbin +#include + +// Loop for a while so we see samples in the function (compiled at -O0) +void loop1() { + for (uint64_t i = 0; i < 10000000000; i++) {} +} + +// Slightly modified to make sure there isn't any kind of linker merging +void loop2() { + for (uint64_t i = 1; i < 10000000001; i++) {} +} + +int main(int argc, char *argv[]) { + // Use CLI argument to choose which loop to run, so we can distinguish which + // process samples were collected from + + if (argc >= 2 && argv[1][0] == '1') { + loop1(); + } + if (argc >= 2 && argv[1][0] == '2') { + loop2(); + } +} diff --git a/llvm/test/tools/llvm-profgen/multi-process-nocs-noprobe.test b/llvm/test/tools/llvm-profgen/multi-process-nocs-noprobe.test new file mode 100644 index 0000000000000..3886f116798cb --- /dev/null +++ b/llvm/test/tools/llvm-profgen/multi-process-nocs-noprobe.test @@ -0,0 +1,40 @@ +; Check that we can handle profiles with multiple processes, without +; pseudo probes or a context-senstive profile + +; RUN: llvm-profgen --format=text --perfscript=%S/Inputs/multi-process-nocs-noprobe.perfscript --binary=%S/Inputs/multi-process-nocs-noprobe.perfbin --output=%t --profile-summary-cold-count=0 --multi-process-profile +; RUN: FileCheck %s --input-file %t + +CHECK: loop1:1302:0 +CHECK-NEXT: 0: 0 +CHECK-NEXT: 1: 31 +CHECK-NEXT: 2: 0 +CHECK-NEXT:loop2:655:0 +CHECK-NEXT: 0: 0 +CHECK-NEXT: 1: 16 +CHECK-NEXT: 2: 0 + +; original code: +; clang -g test.c -o multi-process.perfbin +#include + +// Loop for a while so we see samples in the function (compiled at -O0) +void loop1() { + for (uint64_t i = 0; i < 10000000000; i++) {} +} + +// Slightly modified to make sure there isn't any kind of linker merging +void loop2() { + for (uint64_t i = 1; i < 10000000001; i++) {} +} + +int main(int argc, char *argv[]) { + // Use CLI argument to choose which loop to run, so we can distinguish which + // process samples were collected from + + if (argc >= 2 && argv[1][0] == '1') { + loop1(); + } + if (argc >= 2 && argv[1][0] == '2') { + loop2(); + } +} diff --git a/llvm/test/tools/llvm-profgen/multi-process-warning.test b/llvm/test/tools/llvm-profgen/multi-process-warning.test new file mode 100644 index 0000000000000..26858d583c48b --- /dev/null +++ b/llvm/test/tools/llvm-profgen/multi-process-warning.test @@ -0,0 +1,10 @@ +; Check that we get a warning when processing a multi-process profile without +; the relevant flag +RUN: llvm-profgen --format=text --perfscript=%S/Inputs/multi-process-warning.perfscript --binary=%S/Inputs/multi-process-nocs-noprobe.perfbin --output=%t --profile-summary-cold-count=0 2>&1 | FileCheck %s +CHECK: warning: Binary previously loaded in process ID 149754 at 0x5ffeb3637000 was reloaded in process ID 149755 at 0x5caa46c41000. If profiling multiple processes running concurrently, use --multi-process-profile to prevent loss of samples. + +; Make sure we don't get the warning if using the multi process flag +; Just test that there's no warning, other tests will check the validity of the +; output +RUN: llvm-profgen --format=text --perfscript=%S/Inputs/multi-process-nocs-noprobe.perfscript --binary=%S/Inputs/multi-process-nocs-noprobe.perfbin --output=%t --profile-summary-cold-count=0 --multi-process-profile 2>&1 | FileCheck %s --check-prefix=CHECK-NOWARN +CHECK-NOWARN-NOT: warning: Binary previously loaded diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp index 183b248a72320..1ea3f89f8c078 100644 --- a/llvm/tools/llvm-profgen/PerfReader.cpp +++ b/llvm/tools/llvm-profgen/PerfReader.cpp @@ -60,6 +60,13 @@ static cl::opt CSProfMaxUnsymbolizedCtxDepth( "means no depth limit."), cl::cat(ProfGenCategory)); +static cl::opt MultiProcessProfile( + "multi-process-profile", + cl::desc("Handle multiple instances of the binary loaded in different " + "processes as if they came from one process, effectively summing " + "their samples. perf script input must include the PID field."), + cl::cat(ProfGenCategory)); + namespace sampleprof { void VirtualUnwinder::unwindCall(UnwindState &State) { @@ -345,7 +352,7 @@ bool VirtualUnwinder::unwind(const PerfSample *Sample, uint64_t Repeat) { std::unique_ptr PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput, - std::optional PIDFilter) { + SmallSet &PIDFilter) { std::unique_ptr PerfReader; if (PerfInput.Format == PerfFormat::UnsymbolizedProfile) { @@ -378,7 +385,7 @@ PerfReaderBase::create(ProfiledBinary *Binary, PerfInputFile &PerfInput, } Error PerfReaderBase::parseDataAccessPerfTraces( - StringRef DataAccessPerfTraceFile, std::optional PIDFilter) { + StringRef DataAccessPerfTraceFile, SmallSet &PIDFilter) { // A perf_record_sample line is like // . 1282514022939813 0x87b0 [0x60]: PERF_RECORD_SAMPLE(IP, 0x4002): // 3446532/3446532: 0x2608a2 period: 233 addr: 0x3b3fb0 @@ -423,7 +430,7 @@ Error PerfReaderBase::parseDataAccessPerfTraces( "Failed to parse PID from perf trace line: " + Line, inconvertibleErrorCode()); - if (PIDFilter.has_value() && *PIDFilter != PID) { + if (!PIDFilter.empty() && !PIDFilter.contains(PID)) { continue; } @@ -440,8 +447,10 @@ Error PerfReaderBase::parseDataAccessPerfTraces( if (DataSymbol.starts_with("_ZTV")) { uint64_t IP = 0; Fields[2].getAsInteger(16, IP); - Counter.recordDataAccessCount(Binary->canonicalizeVirtualAddress(IP), - DataSymbol, 1); + // If no PID is in the profile's samples, we treat everything as PID 0 + int32_t LookupPID = MultiProcessProfile ? PID : 0; + Counter.recordDataAccessCount( + Binary->canonicalizeVirtualAddress(LookupPID, IP), DataSymbol, 1); } } } @@ -451,7 +460,7 @@ Error PerfReaderBase::parseDataAccessPerfTraces( PerfInputFile PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary, bool SkipPID, PerfInputFile &File, - std::optional PIDFilter) { + SmallSet &PIDFilter) { StringRef PerfData = File.InputFile; // Run perf script to retrieve PIDs matching binary we're interested in. auto PerfExecutable = sys::Process::FindInEnvPath("PATH", "perf"); @@ -484,7 +493,7 @@ PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary, bool SkipPID, if (isMMapEvent(TraceIt.getCurrentLine()) && extractMMapEventForBinary(Binary, TraceIt.getCurrentLine(), MMap)) { auto It = PIDSet.emplace(MMap.PID); - if (It.second && (!PIDFilter || MMap.PID == *PIDFilter)) { + if (It.second && (PIDFilter.empty() || PIDFilter.contains(MMap.PID))) { if (!PIDs.empty()) { PIDs.append(","); } @@ -505,7 +514,11 @@ PerfScriptReader::convertPerfDataToTrace(ProfiledBinary *Binary, bool SkipPID, ScriptSampleArgs.push_back("script"); ScriptSampleArgs.push_back("--show-mmap-events"); ScriptSampleArgs.push_back("-F"); - ScriptSampleArgs.push_back("ip,brstack"); + if (MultiProcessProfile) { + ScriptSampleArgs.push_back("pid,ip,brstack"); + } else { + ScriptSampleArgs.push_back("ip,brstack"); + } ScriptSampleArgs.push_back("-i"); ScriptSampleArgs.push_back(PerfData); if (!PIDs.empty()) { @@ -541,22 +554,40 @@ void PerfScriptReader::updateBinaryAddress(const MMapEvent &Event) { return; // Drop the event if process does not match pid filter - if (PIDFilter && Event.PID != *PIDFilter) + if (!PIDFilter.empty() && !PIDFilter.contains(Event.PID)) return; + // If no PID is in the profile's samples, we treat everything as PID 0 + int32_t LookupPID = MultiProcessProfile ? Event.PID : 0; + // Drop the event if its image is loaded at the same address - if (Event.Address == Binary->getBaseAddress()) { + if (Event.Address == Binary->getPIDBaseAddress(LookupPID)) { Binary->setIsLoadedByMMap(true); return; } + std::optional LastSeenPID = Binary->getLastSeenPID(); + if (!MultiProcessProfile && LastSeenPID.has_value() && + LastSeenPID.value() != Event.PID) { + WithColor::warning() << "Binary previously loaded in process ID " + << LastSeenPID.value() << " at " + << format("0x%" PRIx64, + Binary->getPIDBaseAddress(LookupPID)) + << " was reloaded in process ID " << Event.PID + << " at " << format("0x%" PRIx64, Event.Address) + << ". If profiling multiple processes running " + << "concurrently, use --multi-process-profile to " + << "prevent loss of samples.\n"; + } + Binary->setLastSeenPID(Event.PID); + if (IsKernel || Event.Offset == Binary->getTextSegmentOffset()) { // A binary image could be unloaded and then reloaded at different // place, so update binary load address. // Only update for the first executable segment and assume all other // segments are loaded at consecutive memory addresses, which is the case on // X64. - Binary->setBaseAddress(Event.Address); + Binary->setPIDBaseAddress(LookupPID, Event.Address); Binary->setIsLoadedByMMap(true); } else { // Verify segments are loaded consecutively. @@ -567,7 +598,7 @@ void PerfScriptReader::updateBinaryAddress(const MMapEvent &Event) { auto I = std::distance(Offsets.begin(), It); const auto &PreferredAddrs = Binary->getPreferredTextSegmentAddresses(); if (PreferredAddrs[I] - Binary->getPreferredBaseAddress() != - Event.Address - Binary->getBaseAddress()) + Event.Address - Binary->getPIDBaseAddress(LookupPID)) exitWithError("Executable segments not loaded consecutively"); } else { if (It == Offsets.begin()) @@ -577,7 +608,8 @@ void PerfScriptReader::updateBinaryAddress(const MMapEvent &Event) { // via multiple mmap calls with consecutive memory addresses. --It; assert(*It < Event.Offset); - if (Event.Offset - *It != Event.Address - Binary->getBaseAddress()) + if (Event.Offset - *It != + Event.Address - Binary->getPIDBaseAddress(LookupPID)) exitWithError("Segment not loaded by consecutive mmaps"); } } @@ -654,14 +686,15 @@ void HybridPerfReader::unwindSamples() { "frame to match."); } -bool PerfScriptReader::extractLBRStack(TraceStream &TraceIt, +bool PerfScriptReader::extractLBRStack(std::optional PIDIfKnown, + TraceStream &TraceIt, SmallVectorImpl &LBRStack) { // The raw format of LBR stack is like: // 0x4005c8/0x4005dc/P/-/-/0 0x40062f/0x4005b0/P/-/-/0 ... // ... 0x4005c8/0x4005dc/P/-/-/0 // It's in FIFO order and separated by whitespace. SmallVector Records; - TraceIt.getCurrentLine().rtrim().split(Records, " ", -1, false); + TraceIt.getCurrentLine().trim().split(Records, " ", -1, false); auto WarnInvalidLBR = [](TraceStream &TraceIt) { WithColor::warning() << "Invalid address in LBR record at line " << TraceIt.getLineNumber() << ": " @@ -670,14 +703,37 @@ bool PerfScriptReader::extractLBRStack(TraceStream &TraceIt, // Skip the leading instruction pointer. size_t Index = 0; + // Default to PID 0 if not provided + int32_t PID = 0; uint64_t LeadingAddr; + + if (Records.size() < (MultiProcessProfile ? 2 : 1)) { + WarnInvalidLBR(TraceIt); + TraceIt.advance(); + return false; + } + + if (MultiProcessProfile) { + // If we read the PID elsewhere, use that instead of trying to read it here + if (PIDIfKnown.has_value()) { + PID = PIDIfKnown.value(); + } else { + if (Records[Index].getAsInteger(10, PID)) { + WarnInvalidLBR(TraceIt); + TraceIt.advance(); + return false; + } + Index++; + } + } + if (!Records.empty() && !Records[0].contains('/')) { - if (Records[0].getAsInteger(16, LeadingAddr)) { + if (Records[Index].getAsInteger(16, LeadingAddr)) { WarnInvalidLBR(TraceIt); TraceIt.advance(); return false; } - Index = 1; + Index++; } // Now extract LBR samples - note that we do not reverse the @@ -701,8 +757,8 @@ bool PerfScriptReader::extractLBRStack(TraceStream &TraceIt, } // Canonicalize to use preferred load address as base address. - Src = Binary->canonicalizeVirtualAddress(Src); - Dst = Binary->canonicalizeVirtualAddress(Dst); + Src = Binary->canonicalizeVirtualAddress(PID, Src); + Dst = Binary->canonicalizeVirtualAddress(PID, Dst); bool SrcIsInternal = Binary->addressIsCode(Src); bool DstIsInternal = Binary->addressIsCode(Dst); if (!SrcIsInternal) @@ -719,7 +775,7 @@ bool PerfScriptReader::extractLBRStack(TraceStream &TraceIt, return !LBRStack.empty(); } -bool PerfScriptReader::extractCallstack(TraceStream &TraceIt, +bool PerfScriptReader::extractCallstack(int32_t PID, TraceStream &TraceIt, SmallVectorImpl &CallStack) { // The raw format of call stack is like: // 4005dc # leaf frame @@ -739,7 +795,7 @@ bool PerfScriptReader::extractCallstack(TraceStream &TraceIt, } TraceIt.advance(); - FrameAddr = Binary->canonicalizeVirtualAddress(FrameAddr); + FrameAddr = Binary->canonicalizeVirtualAddress(PID, FrameAddr); // Currently intermixed frame from different binaries is not supported. if (!Binary->addressIsCode(FrameAddr)) { if (CallStack.empty()) @@ -818,8 +874,24 @@ void HybridPerfReader::parseSample(TraceStream &TraceIt, uint64_t Count) { #ifndef NDEBUG Sample->Linenum = TraceIt.getLineNumber(); #endif + // Default to PID 0 + int32_t PID = 0; + if (MultiProcessProfile) { + // Parse the PID at the beginning of the sample + StringRef FirstLine = TraceIt.getCurrentLine(); + if (FirstLine.trim().getAsInteger(10, PID)) { + // If there's an error reading the PID, treat this line as not part of the + // sample + // While this should usually not happen in a real perf script, this allows + // us to use comments and empty lines in test cases + TraceIt.advance(); + return; + } + TraceIt.advance(); + } + // Parsing call stack and populate into PerfSample.CallStack - if (!extractCallstack(TraceIt, Sample->CallStack)) { + if (!extractCallstack(PID, TraceIt, Sample->CallStack)) { // Skip the next LBR line matched current call stack if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().starts_with(" 0x")) TraceIt.advance(); @@ -830,7 +902,7 @@ void HybridPerfReader::parseSample(TraceStream &TraceIt, uint64_t Count) { if (!TraceIt.isAtEoF() && TraceIt.getCurrentLine().starts_with(" 0x")) { // Parsing LBR stack and populate into PerfSample.LBRStack - if (extractLBRStack(TraceIt, Sample->LBRStack)) { + if (extractLBRStack(PID, TraceIt, Sample->LBRStack)) { if (IgnoreStackSamples) { Sample->CallStack.clear(); } else { @@ -1022,7 +1094,7 @@ void PerfScriptReader::computeCounterFromLBR(const PerfSample *Sample, void LBRPerfReader::parseSample(TraceStream &TraceIt, uint64_t Count) { std::shared_ptr Sample = std::make_shared(); // Parsing LBR stack and populate into PerfSample.LBRStack - if (extractLBRStack(TraceIt, Sample->LBRStack)) { + if (extractLBRStack(std::nullopt, TraceIt, Sample->LBRStack)) { warnIfMissingMMap(); // Record LBR only samples by aggregation AggregatedSamples[Hashable(Sample)] += Count; @@ -1065,15 +1137,17 @@ bool PerfScriptReader::extractMMapEventForBinary(ProfiledBinary *Binary, // Parse a MMap2 line like: // PERF_RECORD_MMAP2 2113428/2113428: [0x7fd4efb57000(0x204000) @ 0 // 08:04 19532229 3585508847]: r-xp /usr/lib64/libdl-2.17.so + // It may be prefixed by a PID constexpr static const char *const MMap2Pattern = - "PERF_RECORD_MMAP2 (-?[0-9]+)/[0-9]+: " + " ?-?[0-9]* ?PERF_RECORD_MMAP2 (-?[0-9]+)/[0-9]+: " "\\[(0x[a-f0-9]+)\\((0x[a-f0-9]+)\\) @ " "(0x[a-f0-9]+|0) .*\\]: ([-a-z]+) (.*)"; // Parse a MMap line like // PERF_RECORD_MMAP -1/0: [0xffffffff81e00000(0x3e8fa000) @ \ // 0xffffffff81e00000]: x [kernel.kallsyms]_text + // It may be prefixed by a PID constexpr static const char *const MMapPattern = - "PERF_RECORD_MMAP (-?[0-9]+)/[0-9]+: " + " ?-?[0-9]* ?PERF_RECORD_MMAP (-?[0-9]+)/[0-9]+: " "\\[(0x[a-f0-9]+)\\((0x[a-f0-9]+)\\) @ " "(0x[a-f0-9]+|0)\\]: ([-a-z]+) (.*)"; // Field 0 - whole line @@ -1152,15 +1226,34 @@ void PerfScriptReader::parseAndAggregateTrace() { // A LBR sample is like: // 40062f 0x5c6313f/0x5c63170/P/-/-/0 0x5c630e7/0x5c63130/P/-/-/0 ... // A heuristic for fast detection by checking whether a -// leading " 0x" and the '/' exist. +// leading "0x" and the '/' exist. bool PerfScriptReader::isLBRSample(StringRef Line) { - // Skip the leading instruction pointer + // Skip the leading instruction pointer, and maybe PID + SmallVector Records; - Line.trim().split(Records, " ", 2, false); - if (Records.size() < 2) - return false; - if (Records[1].starts_with("0x") && Records[1].contains('/')) + + // Trim off the PID (and maybe part/all of the IP) + StringRef Trimmed = Line.ltrim().ltrim("0123456789").trim(); + + // Split by spaces, handling duplicate whitespace using ltrim + auto Temp = Trimmed.split(' '); + StringRef FirstPart = Temp.first.ltrim(); + StringRef Next = Temp.second.ltrim(); + + // If we trimmed off the IP, or it's a hybrid profile, there could be a record + // at the start + // The 0 at the start of the 0x may have been removed + if ((FirstPart.starts_with("x") || FirstPart.starts_with("0x")) && FirstPart.contains('/')) + return true; + + // Get the next part split by whitespace + Temp = Next.split(' '); + StringRef SecondPart = Temp.first.ltrim(); + + // Otherwise it should be the second entry + if (SecondPart.starts_with("0x") && SecondPart.contains('/')) return true; + return false; } @@ -1169,15 +1262,24 @@ bool PerfScriptReader::isMMapEvent(StringRef Line) { if (Line.empty() || Line.size() < 50) return false; - if (std::isdigit(Line[0])) - return false; + if (MultiProcessProfile) { + // Trim off the first numeric field, which is the PID. + // Make sure not to trim other numeric fields. + auto Trimmed = Line.ltrim().ltrim("0123456789").ltrim(); + + if (Trimmed.empty() || std::isdigit(Trimmed[0])) + return false; + } else { + if (std::isdigit(Line[0])) + return false; + } // PERF_RECORD_MMAP2 or PERF_RECORD_MMAP does not appear at the beginning of // the line for ` perf script --show-mmap-events -i ...` return Line.contains("PERF_RECORD_MMAP"); } -// The raw hybird sample is like +// The raw hybrid sample is like // e.g. // 4005dc # call stack leaf // 400634 diff --git a/llvm/tools/llvm-profgen/PerfReader.h b/llvm/tools/llvm-profgen/PerfReader.h index 6e233d17f8e62..91eec4405c48c 100644 --- a/llvm/tools/llvm-profgen/PerfReader.h +++ b/llvm/tools/llvm-profgen/PerfReader.h @@ -10,6 +10,7 @@ #define LLVM_TOOLS_LLVM_PROFGEN_PERFREADER_H #include "ErrorHandling.h" #include "ProfiledBinary.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Error.h" @@ -567,23 +568,19 @@ class VirtualUnwinder { class PerfReaderBase { public: PerfReaderBase(ProfiledBinary *B, StringRef PerfTrace) - : Binary(B), PerfTraceFile(PerfTrace) { - // Initialize the base address to preferred address. - Binary->setBaseAddress(Binary->getPreferredBaseAddress()); - }; + : Binary(B), PerfTraceFile(PerfTrace) {}; virtual ~PerfReaderBase() = default; static std::unique_ptr create(ProfiledBinary *Binary, PerfInputFile &PerfInput, - std::optional PIDFilter); + SmallSet &PIDFilter); // Entry of the reader to parse multiple perf traces virtual void parsePerfTraces() = 0; // Parse the from the data access perf trace file, // and accumulate the data access count for each pair. - Error - parseDataAccessPerfTraces(StringRef DataAccessPerfFile, - std::optional PIDFilter = std::nullopt); + Error parseDataAccessPerfTraces(StringRef DataAccessPerfFile, + SmallSet &PIDFilter); const ContextSampleCounterMap &getSampleCounters() const { return SampleCounters; @@ -606,8 +603,8 @@ class PerfReaderBase { class PerfScriptReader : public PerfReaderBase { public: PerfScriptReader(ProfiledBinary *B, StringRef PerfTrace, - std::optional PID) - : PerfReaderBase(B, PerfTrace), PIDFilter(PID) {}; + SmallSet &PIDFilter) + : PerfReaderBase(B, PerfTrace), PIDFilter(PIDFilter) {}; // Entry of the reader to parse multiple perf traces void parsePerfTraces() override; @@ -622,7 +619,7 @@ class PerfScriptReader : public PerfReaderBase { // Generate perf script from perf data static PerfInputFile convertPerfDataToTrace(ProfiledBinary *Binary, bool SkipPID, PerfInputFile &File, - std::optional PIDFilter); + SmallSet &PIDFilter); // Extract perf script type by peaking at the input static PerfContent checkPerfScriptType(StringRef FileName); @@ -651,10 +648,10 @@ class PerfScriptReader : public PerfReaderBase { // Warn if range is invalid. void warnInvalidRange(); // Extract call stack from the perf trace lines - bool extractCallstack(TraceStream &TraceIt, + bool extractCallstack(int32_t PID, TraceStream &TraceIt, SmallVectorImpl &CallStack); // Extract LBR stack from one perf trace line - bool extractLBRStack(TraceStream &TraceIt, + bool extractLBRStack(std::optional PIDIfKnown, TraceStream &TraceIt, SmallVectorImpl &LBRStack); uint64_t parseAggregatedCount(TraceStream &TraceIt); // Parse one sample from multiple perf lines, override this for different @@ -675,7 +672,7 @@ class PerfScriptReader : public PerfReaderBase { // Keep track of all invalid return addresses std::set InvalidReturnAddresses; // PID for the process of interest - std::optional PIDFilter; + SmallSet PIDFilter; }; /* @@ -687,8 +684,8 @@ class PerfScriptReader : public PerfReaderBase { class LBRPerfReader : public PerfScriptReader { public: LBRPerfReader(ProfiledBinary *Binary, StringRef PerfTrace, - std::optional PID) - : PerfScriptReader(Binary, PerfTrace, PID) {}; + SmallSet &PIDFilter) + : PerfScriptReader(Binary, PerfTrace, PIDFilter) {}; // Parse the LBR only sample. void parseSample(TraceStream &TraceIt, uint64_t Count) override; }; @@ -705,8 +702,8 @@ class LBRPerfReader : public PerfScriptReader { class HybridPerfReader : public PerfScriptReader { public: HybridPerfReader(ProfiledBinary *Binary, StringRef PerfTrace, - std::optional PID) - : PerfScriptReader(Binary, PerfTrace, PID) {}; + SmallSet &PIDFilter) + : PerfScriptReader(Binary, PerfTrace, PIDFilter) {}; // Parse the hybrid sample including the call and LBR line void parseSample(TraceStream &TraceIt, uint64_t Count) override; void generateUnsymbolizedProfile() override; diff --git a/llvm/tools/llvm-profgen/ProfiledBinary.h b/llvm/tools/llvm-profgen/ProfiledBinary.h index 5a814b7dbd52d..f42fb4239ef6c 100644 --- a/llvm/tools/llvm-profgen/ProfiledBinary.h +++ b/llvm/tools/llvm-profgen/ProfiledBinary.h @@ -198,7 +198,13 @@ class ProfiledBinary { // Options used to configure the symbolizer symbolize::LLVMSymbolizer::Options SymbolizerOpts; // The runtime base address that the first executable segment is loaded at. - uint64_t BaseAddress = 0; + // The binary may be loaded at different addresses in different processes, + // so we use a map to store base address by PID. + // If the profile doesn't contain PID info we use PID 0. + std::unordered_map BaseAddressByPID; + // The last PID we saw the binary loaded into. Used to warn the user if a + // binary is loaded in multiple processes without --multi-process-profile. + std::optional LastSeenPID = std::nullopt; // The runtime base address that the first loadabe segment is loaded at. uint64_t FirstLoadableAddress = 0; // The preferred load address of each executable segment. @@ -396,19 +402,31 @@ class ProfiledBinary { StringRef getPath() const { return Path; } StringRef getName() const { return llvm::sys::path::filename(Path); } - uint64_t getBaseAddress() const { return BaseAddress; } - void setBaseAddress(uint64_t Address) { BaseAddress = Address; } + uint64_t getPIDBaseAddress(int32_t PID) const { + auto Pos = BaseAddressByPID.find(PID); + if (Pos == BaseAddressByPID.end()) { + // Use preferred address as the default base address. + return getPreferredBaseAddress(); + } + + return Pos->second; + } + void setPIDBaseAddress(int32_t PID, uint64_t Address) { + BaseAddressByPID[PID] = Address; + } bool isCOFF() const { return IsCOFF; } // Canonicalize to use preferred load address as base address. - uint64_t canonicalizeVirtualAddress(uint64_t Address) { - return Address - BaseAddress + getPreferredBaseAddress(); + uint64_t canonicalizeVirtualAddress(int64_t PID, uint64_t Address) { + return Address - getPIDBaseAddress(PID) + getPreferredBaseAddress(); } // Return the preferred load address for the first executable segment. uint64_t getPreferredBaseAddress() const { return PreferredTextSegmentAddresses[0]; } + std::optional getLastSeenPID() { return LastSeenPID; } + void setLastSeenPID(std::optional PID) { LastSeenPID = PID; } // Return the preferred load address for the first loadable segment. uint64_t getFirstLoadableAddress() const { return FirstLoadableAddress; } // Return the file offset for the first executable segment. diff --git a/llvm/tools/llvm-profgen/llvm-profgen.cpp b/llvm/tools/llvm-profgen/llvm-profgen.cpp index 8d2ed2850e38a..1165338783b63 100644 --- a/llvm/tools/llvm-profgen/llvm-profgen.cpp +++ b/llvm/tools/llvm-profgen/llvm-profgen.cpp @@ -62,10 +62,10 @@ static cl::opt cl::desc("Path of profiled executable binary."), cl::cat(ProfGenCategory)); -static cl::opt - ProcessId("pid", cl::value_desc("process Id"), cl::init(0), - cl::desc("Process Id for the profiled executable binary."), - cl::cat(ProfGenCategory)); +static cl::list ProcessIds( + "pid", cl::CommaSeparated, cl::value_desc("process ID 1,process ID 2,..."), + cl::desc("Comma-separated process IDs for the profiled executable binary."), + cl::cat(ProfGenCategory)); static cl::opt DebugBinPath( "debug-binary", cl::value_desc("debug-binary"), @@ -177,9 +177,12 @@ int main(int argc, const char *argv[]) { Generator->generateProfile(); Generator->write(); } else { - std::optional PIDFilter; - if (ProcessId.getNumOccurrences()) - PIDFilter = ProcessId; + SmallSet PIDFilter; + + for (auto &PID : ProcessIds) { + PIDFilter.insert(PID); + } + PerfInputFile PerfFile = getPerfInputFile(); std::unique_ptr Reader = PerfReaderBase::create(Binary.get(), PerfFile, PIDFilter); From 9e5043a551f63744342d31b3b0004c69aca3e7fb Mon Sep 17 00:00:00 2001 From: Heath Mitchell Date: Mon, 24 Nov 2025 17:01:56 +0000 Subject: [PATCH 2/2] Fix formatting issues --- llvm/tools/llvm-profgen/PerfReader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/tools/llvm-profgen/PerfReader.cpp b/llvm/tools/llvm-profgen/PerfReader.cpp index 1ea3f89f8c078..a652008b857c1 100644 --- a/llvm/tools/llvm-profgen/PerfReader.cpp +++ b/llvm/tools/llvm-profgen/PerfReader.cpp @@ -1234,7 +1234,7 @@ bool PerfScriptReader::isLBRSample(StringRef Line) { // Trim off the PID (and maybe part/all of the IP) StringRef Trimmed = Line.ltrim().ltrim("0123456789").trim(); - + // Split by spaces, handling duplicate whitespace using ltrim auto Temp = Trimmed.split(' '); StringRef FirstPart = Temp.first.ltrim(); @@ -1243,7 +1243,8 @@ bool PerfScriptReader::isLBRSample(StringRef Line) { // If we trimmed off the IP, or it's a hybrid profile, there could be a record // at the start // The 0 at the start of the 0x may have been removed - if ((FirstPart.starts_with("x") || FirstPart.starts_with("0x")) && FirstPart.contains('/')) + if ((FirstPart.starts_with("x") || FirstPart.starts_with("0x")) && + FirstPart.contains('/')) return true; // Get the next part split by whitespace