1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 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
*/
|