-
Notifications
You must be signed in to change notification settings - Fork 11.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[BOLT][Instrumentation] Add test for append-pid option
Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D154121
- Loading branch information
Showing
3 changed files
with
219 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 | ||
*/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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" |