mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-28 08:02:08 +00:00
[BOLT][Instrumentation] Add test for append-pid option
Reviewed By: rafauler Differential Revision: https://reviews.llvm.org/D154121
This commit is contained in:
parent
a86dd9ae60
commit
dfc7599296
@ -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
|
||||
|
168
bolt/test/runtime/instrumentation-indirect-2.c
Normal file
168
bolt/test/runtime/instrumentation-indirect-2.c
Normal file
@ -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
|
||||
|
||||
*/
|
48
bolt/test/runtime/wait_file.sh
Normal file
48
bolt/test/runtime/wait_file.sh
Normal file
@ -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"
|
Loading…
Reference in New Issue
Block a user