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 0000000000000..6e98e86d236a4 Binary files /dev/null and b/llvm/test/tools/llvm-profgen/Inputs/multi-process-cs-probe.perfbin differ 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 0000000000000..b7859ec8d6794 Binary files /dev/null and b/llvm/test/tools/llvm-profgen/Inputs/multi-process-nocs-noprobe.perfbin differ 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..a652008b857c1 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,35 @@ 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 +1263,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);