diff options
author | Denis Revunov <revunov.denis@huawei-partners.com> | 2023-06-23 16:06:58 +0000 |
---|---|---|
committer | Tobias Hieta <tobias@hieta.se> | 2023-08-27 10:55:53 +0200 |
commit | 3670e6a5c8a5f6a7665572c9d90bab9192f713eb (patch) | |
tree | 1727df25ec0bf38df5bd19821faa5642ef8c1150 /bolt | |
parent | [BOLT][Instrumentation] Fix indirect call profile in PIE (diff) | |
download | llvm-project-3670e6a5c8a5f6a7665572c9d90bab9192f713eb.tar.gz llvm-project-3670e6a5c8a5f6a7665572c9d90bab9192f713eb.tar.bz2 llvm-project-3670e6a5c8a5f6a7665572c9d90bab9192f713eb.zip |
[BOLT][Instrumentation] Add test for append-pid option
Reviewed By: rafauler
Differential Revision: https://reviews.llvm.org/D154121
(cherry picked from commit dfc759929644ed1ea3224ab30e1086f7acc60da6)
Diffstat (limited to 'bolt')
-rw-r--r-- | bolt/test/lit.cfg.py | 3 | ||||
-rw-r--r-- | bolt/test/runtime/instrumentation-indirect-2.c | 168 | ||||
-rw-r--r-- | bolt/test/runtime/wait_file.sh | 48 |
3 files changed, 219 insertions, 0 deletions
diff --git a/bolt/test/lit.cfg.py b/bolt/test/lit.cfg.py index fe27af87f910..3a6da210e01f 100644 --- a/bolt/test/lit.cfg.py +++ b/bolt/test/lit.cfg.py @@ -72,6 +72,9 @@ if config.bolt_enable_runtime: if config.gnu_ld: config.available_features.add("gnu_ld") +if lit.util.which("fuser"): + config.available_features.add("fuser") + llvm_config.use_default_substitutions() llvm_config.config.environment["CLANG"] = config.bolt_clang diff --git a/bolt/test/runtime/instrumentation-indirect-2.c b/bolt/test/runtime/instrumentation-indirect-2.c new file mode 100644 index 000000000000..7d19db14b77f --- /dev/null +++ b/bolt/test/runtime/instrumentation-indirect-2.c @@ -0,0 +1,168 @@ +// Check that indirect call hash tables properly register multiple calls, +// and that calls from different processes don't get mixed up when using +// --instrumentation-file-append-pid. + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +__attribute__((noinline)) void funcA(int pid) { printf("funcA %d\n", pid); } +__attribute__((noinline)) void funcB(int pid) { printf("funcB %d\n", pid); } +__attribute__((noinline)) void funcC(int pid) { printf("funcC %d\n", pid); } +__attribute__((noinline)) void funcD(int pid) { printf("funcD %d\n", pid); } +__attribute__((noinline)) void funcE(int pid) { printf("funcE %d\n", pid); } +__attribute__((noinline)) void funcF(int pid) { printf("funcF %d\n", pid); } +__attribute__((noinline)) void funcG(int pid) { printf("funcG %d\n", pid); } +__attribute__((noinline)) void funcH(int pid) { printf("funcH %d\n", pid); } +__attribute__((noinline)) void funcI(int pid) { printf("funcI %d\n", pid); } +__attribute__((noinline)) void funcJ(int pid) { printf("funcJ %d\n", pid); } +__attribute__((noinline)) void funcK(int pid) { printf("funcK %d\n", pid); } +__attribute__((noinline)) void funcL(int pid) { printf("funcL %d\n", pid); } +__attribute__((noinline)) void funcM(int pid) { printf("funcM %d\n", pid); } +__attribute__((noinline)) void funcN(int pid) { printf("funcN %d\n", pid); } +__attribute__((noinline)) void funcO(int pid) { printf("funcO %d\n", pid); } +__attribute__((noinline)) void funcP(int pid) { printf("funcP %d\n", pid); } + +int main() { + + void (*funcs[])(int) = {funcA, funcB, funcC, funcD, funcE, funcF, + funcG, funcH, funcI, funcJ, funcK, funcL, + funcM, funcN, funcO, funcP}; + int i; + + switch (fork()) { + case -1: + printf("Failed to fork!\n"); + exit(-1); + break; + case 0: + i = 0; + break; + default: + i = 1; + break; + } + int pid = getpid(); + for (; i < sizeof(funcs) / sizeof(void *); i += 2) { + funcs[i](pid); + } + + return 0; +} +/* +REQUIRES: system-linux,shell,fuser + +RUN: %clang %cflags %s -o %t.exe -Wl,-q -pie -fpie + +RUN: llvm-bolt %t.exe --instrument --instrumentation-file=%t.fdata \ +RUN: --conservative-instrumentation -o %t.instrumented_conservative \ +RUN: --instrumentation-sleep-time=1 --instrumentation-no-counters-clear \ +RUN: --instrumentation-wait-forks + +# Instrumented program needs to finish returning zero +# Both output and profile must contain all 16 functions +RUN: %t.instrumented_conservative > %t.output +# Wait for profile and output to be fully written +RUN: bash %S/wait_file.sh %t.output +RUN: bash %S/wait_file.sh %t.fdata +RUN: cat %t.output | FileCheck %s --check-prefix=CHECK-OUTPUT +RUN: cat %t.fdata | FileCheck %s --check-prefix=CHECK-COMMON-PROF + +CHECK-OUTPUT-DAG: funcA +CHECK-OUTPUT-DAG: funcB +CHECK-OUTPUT-DAG: funcC +CHECK-OUTPUT-DAG: funcD +CHECK-OUTPUT-DAG: funcE +CHECK-OUTPUT-DAG: funcF +CHECK-OUTPUT-DAG: funcG +CHECK-OUTPUT-DAG: funcH +CHECK-OUTPUT-DAG: funcI +CHECK-OUTPUT-DAG: funcJ +CHECK-OUTPUT-DAG: funcK +CHECK-OUTPUT-DAG: funcL +CHECK-OUTPUT-DAG: funcM +CHECK-OUTPUT-DAG: funcN +CHECK-OUTPUT-DAG: funcO +CHECK-OUTPUT-DAG: funcP + +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcA 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcB 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcC 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcD 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcE 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcF 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcG 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcH 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcI 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcJ 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcK 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcL 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcM 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcN 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcO 0 0 1 +CHECK-COMMON-PROF-DAG: 1 main {{[0-9a-f]+}} 1 funcP 0 0 1 + +RUN: llvm-bolt %t.exe --instrument --instrumentation-file=%t \ +RUN: --instrumentation-file-append-pid \ +RUN: -o %t.instrumented + +RUN: %t.instrumented > %t.output +# Wait till output is fully written in case child outlives parent +RUN: bash %S/wait_file.sh %t.output +# Make sure all functions were called +RUN: cat %t.output | FileCheck %s --check-prefix=CHECK-OUTPUT + +RUN: child_pid=$(cat %t.output | grep funcA | awk '{print $2;}') +RUN: par_pid=$(cat %t.output | grep funcB | awk '{print $2;}') + +RUN: bash %S/wait_file.sh %t.$child_pid.fdata +RUN: bash %S/wait_file.sh %t.$par_pid.fdata + +RUN: mv %t.$child_pid.fdata %t.child.fdata +RUN: mv %t.$par_pid.fdata %t.parent.fdata + +# Instrumented binary must produce two profiles with only local calls +# recorded. Functions called only in child should not appear in parent's +# process and vice versa. +RUN: cat %t.child.fdata | FileCheck %s --check-prefix=CHECK-CHILD +RUN: cat %t.child.fdata | FileCheck %s --check-prefix=CHECK-NOCHILD +RUN: cat %t.parent.fdata | FileCheck %s --check-prefix=CHECK-PARENT +RUN: cat %t.parent.fdata | FileCheck %s --check-prefix=CHECK-NOPARENT + +CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcA 0 0 1 +CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcC 0 0 1 +CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcE 0 0 1 +CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcG 0 0 1 +CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcI 0 0 1 +CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcK 0 0 1 +CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcM 0 0 1 +CHECK-CHILD-DAG: 1 main {{[0-9a-f]+}} 1 funcO 0 0 1 + +CHECK-NOCHILD-NOT: funcB +CHECK-NOCHILD-NOT: funcD +CHECK-NOCHILD-NOT: funcF +CHECK-NOCHILD-NOT: funcH +CHECK-NOCHILD-NOT: funcJ +CHECK-NOCHILD-NOT: funcL +CHECK-NOCHILD-NOT: funcN +CHECK-NOCHILD-NOT: funcP + +CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcB 0 0 1 +CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcD 0 0 1 +CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcF 0 0 1 +CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcH 0 0 1 +CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcJ 0 0 1 +CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcL 0 0 1 +CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcN 0 0 1 +CHECK-PARENT-DAG: 1 main {{[0-9a-f]+}} 1 funcP 0 0 1 + +CHECK-NOPARENT-NOT: funcA +CHECK-NOPARENT-NOT: funcC +CHECK-NOPARENT-NOT: funcE +CHECK-NOPARENT-NOT: funcG +CHECK-NOPARENT-NOT: funcI +CHECK-NOPARENT-NOT: funcK +CHECK-NOPARENT-NOT: funcM +CHECK-NOPARENT-NOT: funcO + + */ diff --git a/bolt/test/runtime/wait_file.sh b/bolt/test/runtime/wait_file.sh new file mode 100644 index 000000000000..42d4c5b29e79 --- /dev/null +++ b/bolt/test/runtime/wait_file.sh @@ -0,0 +1,48 @@ +#!/bin/bash + +check_file() { + local file="$1" + if [ -z "$file" ]; then + echo "No file passed!" + exit 1 + fi + if [ ! -f "$file" ]; then + return 1 + fi + + fuser -s "$file" + local ret=$? + if [ $ret -eq 1 ]; then # noone has file open + return 0 + fi + if [ $ret -eq 0 ]; then # file open by some processes + return 1 + fi + if [ $ret -eq 127 ]; then + echo "fuser command not found!" + exit 1 + fi + + echo "Unexpected exit code $ret from fuser!" + exit 1 +} + +wait_file() { + local file="$1" + local max_sleep=10 + check_file "$file" + local ret=$? + while [ $ret -ne 0 ] && [ $max_sleep -ne 0 ]; do + sleep 1 + max_sleep=$((max_sleep - 1)) + check_file $file + ret=$? + done + if [ $max_sleep -eq 0 ]; then + echo "The file does not exist or the test hung!" + exit 1 + fi + +} +file="$1" +wait_file "$file" |