online-merging.c
4.58 KB
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
// REQUIRES: darwin
// Test the online merging mode (%m) along with continuous mode (%c).
//
// Create & cd into a temporary directory.
// RUN: rm -rf %t.dir && mkdir -p %t.dir && cd %t.dir
//
// Create two DSOs and a driver program that uses them.
// RUN: echo "void dso1(void) {}" > dso1.c
// RUN: echo "void dso2(void) {}" > dso2.c
// RUN: %clang_pgogen -dynamiclib -o %t.dir/dso1.dylib dso1.c -mllvm -instrprof-atomic-counter-update-all=1
// RUN: %clang_pgogen -dynamiclib -o %t.dir/dso2.dylib dso2.c -mllvm -instrprof-atomic-counter-update-all=1
// RUN: %clang_pgogen -o main.exe %s %t.dir/dso1.dylib %t.dir/dso2.dylib -mllvm -instrprof-atomic-counter-update-all=1
//
// === Round 1 ===
// Test merging+continuous mode without any file contention.
//
// RUN: env LLVM_PROFILE_FILE="%t.dir/profdir/%m%c.profraw" %run %t.dir/main.exe nospawn
// RUN: llvm-profdata merge -o %t.profdata %t.dir/profdir
// RUN: llvm-profdata show --counts --all-functions %t.profdata | FileCheck %s -check-prefix=ROUND1
// ROUND1-LABEL: Counters:
// ROUND1-DAG: dso1:
// ROUND1-DAG: Hash: 0x{{.*}}
// ROUND1-DAG: Counters: 1
// ROUND1-DAG: Block counts: [1]
// ROUND1-DAG: dso2:
// ROUND1-DAG: Hash: 0x{{.*}}
// ROUND1-DAG: Counters: 1
// ROUND1-DAG: Block counts: [1]
// ROUND1-DAG: main:
// ROUND1-DAG: Hash: 0x{{.*}}
// ROUND1-LABEL: Instrumentation level: IR
// ROUND1-NEXT: Functions shown: 3
// ROUND1-NEXT: Total functions: 3
// ROUND1-NEXT: Maximum function count: 1
// ROUND1-NEXT: Maximum internal block count: 1
//
// === Round 2 ===
// Test merging+continuous mode with some file contention.
//
// RUN: env LLVM_PROFILE_FILE="%t.dir/profdir/%m%c.profraw" %run %t.dir/main.exe spawn 'LLVM_PROFILE_FILE=%t.dir/profdir/%m%c.profraw'
// RUN: llvm-profdata merge -o %t.profdata %t.dir/profdir
// RUN: llvm-profdata show --counts --all-functions %t.profdata | FileCheck %s -check-prefix=ROUND2
// ROUND2-LABEL: Counters:
// ROUND2-DAG: dso1:
// ROUND2-DAG: Hash: 0x{{.*}}
// ROUND2-DAG: Counters: 1
// ROUND2-DAG: Block counts: [97]
// ROUND2-DAG: dso2:
// ROUND2-DAG: Hash: 0x{{.*}}
// ROUND2-DAG: Counters: 1
// ROUND2-DAG: Block counts: [97]
// ROUND2-DAG: main:
// ROUND2-DAG: Hash: 0x{{.*}}
// ROUND2-LABEL: Instrumentation level: IR
// ROUND2-NEXT: Functions shown: 3
// ROUND2-NEXT: Total functions: 3
// ROUND2-NEXT: Maximum function count: 97
// ROUND2-NEXT: Maximum internal block count: 33
#include <spawn.h>
#include <sys/wait.h>
#include <sys/errno.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
const int num_child_procs_to_spawn = 32;
extern int __llvm_profile_is_continuous_mode_enabled(void);
extern char *__llvm_profile_get_filename(void);
void dso1(void);
void dso2(void);
// Change to "#define" for debug output.
#undef DEBUG_TEST
#ifdef DEBUG_TEST
#define DEBUG(...) fprintf(stderr, __VA_ARGS__);
#else
#define DEBUG(...)
#endif
int main(int argc, char *const argv[]) {
if (strcmp(argv[1], "nospawn") == 0) {
DEBUG("Hello from child (pid = %d, cont-mode-enabled = %d, profile = %s).\n",
getpid(), __llvm_profile_is_continuous_mode_enabled(), __llvm_profile_get_filename());
dso1();
dso2();
return 0;
} else if (strcmp(argv[1], "spawn") == 0) {
// This is the start of Round 2.
// Expect Counts[dsoX] = 1, as this was the state at the end of Round 1.
int I;
pid_t child_pids[num_child_procs_to_spawn];
char *const child_argv[] = {argv[0], "nospawn", NULL};
char *const child_envp[] = {argv[2], NULL};
for (I = 0; I < num_child_procs_to_spawn; ++I) {
dso1(); // Counts[dsoX] += 2 * num_child_procs_to_spawn
dso2();
DEBUG("Spawning child with argv = {%s, %s, NULL} and envp = {%s, NULL}\n",
child_argv[0], child_argv[1], child_envp[0]);
int ret = posix_spawn(&child_pids[I], argv[0], NULL, NULL, child_argv,
child_envp);
if (ret != 0) {
fprintf(stderr, "Child %d could not be spawned: ret = %d, msg = %s\n",
I, ret, strerror(ret));
return 1;
}
DEBUG("Spawned child %d (pid = %d).\n", I, child_pids[I]);
}
for (I = 0; I < num_child_procs_to_spawn; ++I) {
dso1(); // Counts[dsoX] += num_child_procs_to_spawn
dso2();
int status;
waitpid(child_pids[I], &status, 0);
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
fprintf(stderr, "Child %d did not exit with code 0.\n", I);
return 1;
}
}
// At the end of Round 2, we have:
// Counts[dsoX] = 1 + (2 * num_child_procs_to_spawn) + num_child_procs_to_spawn
// = 97
return 0;
}
return 1;
}