161 lines · c
1// REQUIRES: target={{.*windows-msvc.*}}2// REQUIRES: lld-available3 4// Fails on Windows on Arm for unknown reasons.5// UNSUPPORTED: target=aarch64-pc-windows-msvc6 7// Test the online merging mode (%m) along with continuous mode (%c).8//9// Split files & cd into a temporary directory.10// RUN: rm -rf %t.dir && split-file %s %t.dir && cd %t.dir11//12// Create two DLLs and a driver program that uses them.13// RUN: %clang_pgogen=%t.dir/profdir -fprofile-continuous -fprofile-update=atomic foo.c -fuse-ld=lld -Wl,-dll -o %t.dir/foo.dll14// RUN: %clang_pgogen=%t.dir/profdir -fprofile-continuous -fprofile-update=atomic bar.c -fuse-ld=lld -Wl,-dll -o %t.dir/bar.dll15// RUN: %clang_pgogen=%t.dir/profdir -fprofile-continuous -fprofile-update=atomic main.c -o main.exe %t.dir/foo.lib %t.dir/bar.lib -fuse-ld=lld16//17// === Round 1 ===18// Test merging+continuous mode without any file contention.19//20// RUN: %run %t.dir/main.exe nospawn21// RUN: llvm-profdata merge -o %t.profdata %t.dir/profdir22// RUN: llvm-profdata show --counts --all-functions %t.profdata | FileCheck %s -check-prefix=ROUND123 24// ROUND1-LABEL: Counters:25// ROUND1-DAG: foo:26// ROUND1-DAG: Hash: 0x{{.*}}27// ROUND1-DAG: Counters: 128// ROUND1-DAG: Block counts: [1]29// ROUND1-DAG: bar:30// ROUND1-DAG: Hash: 0x{{.*}}31// ROUND1-DAG: Counters: 132// ROUND1-DAG: Block counts: [1]33// ROUND1-DAG: main:34// ROUND1-DAG: Hash: 0x{{.*}}35// ROUND1-LABEL: Instrumentation level: IR36//37// === Round 2 ===38// Test merging+continuous mode with some file contention.39//40// RUN: %run %t.dir/main.exe spawn41// RUN: llvm-profdata merge -o %t.profdata %t.dir/profdir42// RUN: llvm-profdata show --counts --all-functions %t.profdata | FileCheck %s -check-prefix=ROUND243 44// ROUND2-LABEL: Counters:45// ROUND2-DAG: foo:46// ROUND2-DAG: Hash: 0x{{.*}}47// ROUND2-DAG: Counters: 148// ROUND2-DAG: Block counts: [97]49// ROUND2-DAG: bar:50// ROUND2-DAG: Hash: 0x{{.*}}51// ROUND2-DAG: Counters: 152// ROUND2-DAG: Block counts: [97]53// ROUND2-DAG: main:54// ROUND2-DAG: Hash: 0x{{.*}}55// ROUND2-LABEL: Instrumentation level: IR56 57//--- foo.c58__declspec(dllexport) void foo(void) {}59 60//--- bar.c61__declspec(dllexport) void bar(void) {}62 63//--- main.c64#include <stdio.h>65#include <string.h>66#include <windows.h>67 68 69const int num_child_procs_to_spawn = 32;70 71extern int __llvm_profile_is_continuous_mode_enabled(void);72extern char *__llvm_profile_get_filename(void);73 74__declspec(dllimport) void foo(void);75__declspec(dllimport) void bar(void);76 77// Change to "#define" for debug output.78#undef DEBUG_TEST79 80#ifdef DEBUG_TEST81# define DEBUG(...) fprintf(stderr, __VA_ARGS__);82#else83# define DEBUG(...)84#endif85 86int main(int argc, char *const argv[]) {87 if (argc < 2) {88 DEBUG("Requires at least one argument.\n");89 return 1;90 }91 if (strcmp(argv[1], "nospawn") == 0) {92 DEBUG(93 "Hello from child (pid = %lu, cont-mode-enabled = %d, profile = %s).\n",94 GetCurrentProcessId(), __llvm_profile_is_continuous_mode_enabled(),95 __llvm_profile_get_filename());96 97 foo();98 bar();99 return 0;100 } else if (strcmp(argv[1], "spawn") == 0) {101 // This is the start of Round 2.102 // Expect Counts[dsoX] = 1, as this was the state at the end of Round 1.103 int I;104 HANDLE child_pids[num_child_procs_to_spawn];105 for (I = 0; I < num_child_procs_to_spawn; ++I) {106 foo(); // Counts[dsoX] += 2 * num_child_procs_to_spawn107 bar();108 109 DEBUG("Spawning child with argv = {%s, %s, NULL} and envp = {%s, NULL}\n",110 child_argv[0], child_argv[1], child_envp[0]);111 112 // Start the child process.113 STARTUPINFO si;114 ZeroMemory(&si, sizeof(si));115 PROCESS_INFORMATION pi;116 ZeroMemory(&pi, sizeof(pi));117 if (!CreateProcess(NULL, // No module name (use command line)118 "main.exe nospawn", // Command line119 NULL, // Process handle not inheritable120 NULL, // Thread handle not inheritable121 FALSE, // Set handle inheritance to FALSE122 0, // No creation flags123 NULL, // Use parent's environment block124 NULL, // Use parent's starting directory125 &si, // Pointer to STARTUPINFO structure126 &pi) // Pointer to PROCESS_INFORMATION structure127 ) {128 fprintf(stderr, "Child %d could not be spawned: %lu\n", I,129 GetLastError());130 return 1;131 }132 child_pids[I] = pi.hProcess;133 134 DEBUG("Spawned child %d (pid = %zu).\n", I, pi.dwProcessId);135 }136 for (I = 0; I < num_child_procs_to_spawn; ++I) {137 foo(); // Counts[dsoX] += num_child_procs_to_spawn138 bar();139 140 DWORD exit_code;141 WaitForSingleObject(child_pids[I], INFINITE);142 if (!GetExitCodeProcess(child_pids[I], &exit_code)) {143 fprintf(stderr, "Failed to get exit code of child %d.\n", I);144 return 1;145 }146 if (exit_code != 0) {147 fprintf(stderr, "Child %d did not exit with code 0.\n", I);148 return 1;149 }150 }151 152 // At the end of Round 2, we have:153 // Counts[dsoX] = 1 + (2 * num_child_procs_to_spawn) + num_child_procs_to_spawn154 // = 97155 156 return 0;157 }158 159 return 1;160}161