| 1 | // REQUIRES: target={{.*(darwin|linux|solaris|aix).*}} |
| 2 | |
| 3 | // Test using __llvm_profile_set_file_object in continuous mode (%c). |
| 4 | // Create & cd into a temporary directory. |
| 5 | // RUN: rm -rf %t.dir && mkdir -p %t.dir && cd %t.dir |
| 6 | |
| 7 | // RUN: %clang_profgen -fprofile-continuous -fcoverage-mapping -fprofile-update=atomic -o main.exe %s |
| 8 | |
| 9 | // Test continuous mode with __llvm_profile_set_file_object with mergin disabled. |
| 10 | // RUN: env LLVM_PROFILE_FILE="%t.dir/profdir/%c%mprofraw.old" %run %t.dir/main.exe nomerge %t.dir/profdir/profraw.new 2>&1 | FileCheck %s -check-prefix=WARN |
| 11 | // WARN: LLVM Profile Warning: __llvm_profile_set_file_object(fd={{[0-9]+}}) not supported in continuous sync mode when merging is disabled |
| 12 | |
| 13 | // Test continuous mode with __llvm_profile_set_file_object with mergin enabled. |
| 14 | // RUN: rm -rf %t.dir/profdir/ |
| 15 | // RUN: env LLVM_PROFILE_FILE="%t.dir/profdir/%c%mprofraw.old" %run %t.dir/main.exe merge %t.dir/profdir/profraw.new 'LLVM_PROFILE_FILE=%t.dir/profdir/%c%m.profraw' |
| 16 | // RUN: llvm-profdata merge -o %t.dir/profdir/profdata %t.dir/profdir/profraw.new |
| 17 | // RUN: llvm-profdata show --counts --all-functions %t.dir/profdir/profdata | FileCheck %s -check-prefix=MERGE |
| 18 | // RUN: llvm-profdata show --counts --all-functions %t.dir/profdir/*profraw.old | FileCheck %s -check-prefix=ZERO |
| 19 | |
| 20 | // Test __llvm_profile_set_file_object with mergin enabled and continuous mode disabled. |
| 21 | // RUN: rm -rf %t.dir/profdir/ |
| 22 | // RUN: env LLVM_PROFILE_FILE="%t.dir/profdir/%mprofraw.old" %run %t.dir/main.exe merge %t.dir/profdir/profraw.new 'LLVM_PROFILE_FILE=%t.dir/profdir/%m.profraw' |
| 23 | // RUN: llvm-profdata merge -o %t.dir/profdir/profdata %t.dir/profdir/profraw.new |
| 24 | // RUN: llvm-profdata show --counts --all-functions %t.dir/profdir/profdata | FileCheck %s -check-prefix=MERGE |
| 25 | // RUN: llvm-profdata show --counts --all-functions %t.dir/profdir/*profraw.old | FileCheck %s -check-prefix=ZERO |
| 26 | |
| 27 | // MERGE: Counters: |
| 28 | // MERGE: coverage_test: |
| 29 | // MERGE: Hash: {{.*}} |
| 30 | // MERGE: Counters: 1 |
| 31 | // MERGE: Function count: 32 |
| 32 | // MERGE: Block counts: [] |
| 33 | // MERGE: Instrumentation level: Front-end |
| 34 | |
| 35 | // ZERO: Counters: |
| 36 | // ZERO: coverage_test: |
| 37 | // ZERO: Hash: {{.*}} |
| 38 | // ZERO: Counters: 1 |
| 39 | // ZERO: Function count: 0 |
| 40 | // ZERO: Block counts: [] |
| 41 | // ZERO: Instrumentation level: Front-end |
| 42 | |
| 43 | #include <spawn.h> |
| 44 | #include <stdio.h> |
| 45 | #include <string.h> |
| 46 | |
| 47 | #include <sys/types.h> |
| 48 | #include <sys/wait.h> |
| 49 | |
| 50 | const int num_child_procs_to_spawn = 32; |
| 51 | |
| 52 | extern int __llvm_profile_is_continuous_mode_enabled(void); |
| 53 | extern int __llvm_profile_set_file_object(FILE *, int); |
| 54 | |
| 55 | int coverage_test() { |
| 56 | return 0; |
| 57 | } |
| 58 | |
| 59 | int main(int argc, char **argv) { |
| 60 | char *file_name = argv[2]; |
| 61 | FILE *file = NULL; |
| 62 | if (strcmp(s1: argv[1], s2: "nomerge" ) == 0) { |
| 63 | file = fopen(filename: file_name, modes: "a+b" ); |
| 64 | __llvm_profile_set_file_object(file, 0); |
| 65 | } |
| 66 | else if (strcmp(s1: argv[1], s2: "merge" ) == 0) { |
| 67 | // Parent process. |
| 68 | int I; |
| 69 | pid_t child_pids[num_child_procs_to_spawn]; |
| 70 | char *const child_argv[] = {argv[0], "set" , file_name, NULL}; |
| 71 | char *const child_envp[] = {argv[3], NULL}; |
| 72 | FILE *file = fopen(filename: file_name, modes: "w+" ); |
| 73 | fclose(stream: file); |
| 74 | for (I = 0; I < num_child_procs_to_spawn; ++I) { |
| 75 | int ret = |
| 76 | posix_spawn(pid: &child_pids[I], path: argv[0], NULL, NULL, argv: child_argv, envp: child_envp); |
| 77 | if (ret != 0) { |
| 78 | fprintf(stderr, format: "Child %d could not be spawned: ret = %d, msg = %s\n" , |
| 79 | I, ret, strerror(errnum: ret)); |
| 80 | return 1; |
| 81 | } |
| 82 | } |
| 83 | for (I = 0; I < num_child_procs_to_spawn; ++I) { |
| 84 | int status; |
| 85 | pid_t waited_pid = waitpid(pid: child_pids[I], stat_loc: &status, options: 0); |
| 86 | if (waited_pid != child_pids[I]) { |
| 87 | fprintf(stderr, format: "Failed to wait on child %d\n" , I); |
| 88 | return 1; |
| 89 | } |
| 90 | if (!WIFEXITED(status)) { |
| 91 | fprintf(stderr, format: "Child %d did not terminate normally\n" , I); |
| 92 | return 1; |
| 93 | } |
| 94 | int return_status = WEXITSTATUS(status); |
| 95 | if (return_status != 0) { |
| 96 | fprintf(stderr, format: "Child %d exited with non zero status %d\n" , I, |
| 97 | return_status); |
| 98 | return 1; |
| 99 | } |
| 100 | } |
| 101 | } else if (strcmp(s1: argv[1], s2: "set" ) == 0) { |
| 102 | // Child processes. |
| 103 | file = fopen(filename: file_name, modes: "r+b" ); |
| 104 | if (__llvm_profile_set_file_object(file, 1)) { |
| 105 | fprintf(stderr, format: "Call to __llvm_profile_set_file_object failed\n" ); |
| 106 | return 1; |
| 107 | } |
| 108 | // After set file object, counter should be written into new file. |
| 109 | coverage_test(); |
| 110 | } |
| 111 | return 0; |
| 112 | } |
| 113 | |