| 1 | // RUN: %clang_profgen -mllvm --enable-value-profiling=true -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=3 -O2 -o %t %s |
| 2 | // RUN: %run %t %t.profraw |
| 3 | // RUN: llvm-profdata merge -o %t.profdata %t.profraw |
| 4 | // RUN: llvm-profdata show --all-functions --counts --ic-targets %t.profdata > %t.profdump |
| 5 | // RUN: FileCheck --input-file %t.profdump %s --check-prefix=FOO |
| 6 | // RUN: FileCheck --input-file %t.profdump %s --check-prefix=BAR |
| 7 | |
| 8 | #include <stdint.h> |
| 9 | #include <stdio.h> |
| 10 | #include <stdlib.h> |
| 11 | #include <sys/types.h> |
| 12 | #include <unistd.h> |
| 13 | |
| 14 | int __llvm_profile_runtime = 0; |
| 15 | int __llvm_profile_write_file(); |
| 16 | void __llvm_profile_reset_counters(void); |
| 17 | int __llvm_profile_merge_from_buffer(const char *, uint64_t); |
| 18 | void __llvm_profile_set_filename(const char *); |
| 19 | struct __llvm_profile_data; |
| 20 | struct ValueProfData; |
| 21 | void lprofMergeValueProfData(struct ValueProfData *, struct __llvm_profile_data *); |
| 22 | /* Force the vp merger module to be linked in. */ |
| 23 | void *Dummy = &lprofMergeValueProfData; |
| 24 | |
| 25 | void callee1() {} |
| 26 | void callee2() {} |
| 27 | void callee3() {} |
| 28 | |
| 29 | typedef void (*FP)(void); |
| 30 | FP Fps[3] = {callee1, callee2, callee3}; |
| 31 | |
| 32 | void foo(int N) { |
| 33 | int I, J; |
| 34 | for (I = 0; I < 3; I++) |
| 35 | for (J = 0; J < I * 2 + 1; J++) |
| 36 | Fps[I](); |
| 37 | |
| 38 | if (N < 2) |
| 39 | return; |
| 40 | |
| 41 | for (I = 0; I < 3; I++) |
| 42 | for (J = 0; J < I * 2 + 1; J++) |
| 43 | Fps[2 - I](); |
| 44 | } |
| 45 | |
| 46 | /* This function is not profiled */ |
| 47 | void bar(void) { |
| 48 | int I; |
| 49 | for (I = 0; I < 20; I++) |
| 50 | Fps[I % 3](); |
| 51 | } |
| 52 | |
| 53 | int main(int argc, const char *argv[]) { |
| 54 | int i; |
| 55 | if (argc < 2) |
| 56 | return 1; |
| 57 | |
| 58 | const char *FileN = argv[1]; |
| 59 | __llvm_profile_set_filename(FileN); |
| 60 | /* Start profiling. */ |
| 61 | __llvm_profile_reset_counters(); |
| 62 | foo(N: 1); |
| 63 | /* End profiling by freezing counters and |
| 64 | * dump them to the file. */ |
| 65 | if (__llvm_profile_write_file()) |
| 66 | return 1; |
| 67 | |
| 68 | /* Read profile data into buffer. */ |
| 69 | FILE *File = fopen(filename: FileN, modes: "r" ); |
| 70 | if (!File) |
| 71 | return 1; |
| 72 | fseek(stream: File, off: 0, SEEK_END); |
| 73 | uint64_t Size = ftell(stream: File); |
| 74 | fseek(stream: File, off: 0, SEEK_SET); |
| 75 | char *Buffer = (char *)malloc(size: Size); |
| 76 | if (Size != fread(ptr: Buffer, size: 1, n: Size, stream: File)) |
| 77 | return 1; |
| 78 | fclose(stream: File); |
| 79 | |
| 80 | /* Its profile will be discarded. */ |
| 81 | for (i = 0; i < 10; i++) |
| 82 | bar(); |
| 83 | |
| 84 | /* Start profiling again and merge in previously |
| 85 | saved counters in buffer. */ |
| 86 | __llvm_profile_reset_counters(); |
| 87 | __llvm_profile_merge_from_buffer(Buffer, Size); |
| 88 | foo(N: 2); |
| 89 | /* End profiling. */ |
| 90 | truncate(file: FileN, length: 0); |
| 91 | if (__llvm_profile_write_file()) |
| 92 | return 1; |
| 93 | |
| 94 | /* Its profile will be discarded. */ |
| 95 | bar(); |
| 96 | |
| 97 | return 0; |
| 98 | } |
| 99 | |
| 100 | // FOO-LABEL: foo: |
| 101 | // FOO: Indirect Target Results: |
| 102 | // FOO-NEXT: [ 0, callee3, 10 ] |
| 103 | // FOO-NEXT: [ 0, callee2, 6 ] |
| 104 | // FOO-NEXT: [ 0, callee1, 2 ] |
| 105 | // FOO-NEXT: [ 1, callee1, 5 ] |
| 106 | // FOO-NEXT: [ 1, callee2, 3 ] |
| 107 | // FOO-NEXT: [ 1, callee3, 1 ] |
| 108 | |
| 109 | // BAR-LABEL: bar: |
| 110 | // BAR: [ 0, callee1, 0 ] |
| 111 | // BAR-NEXT: [ 0, callee2, 0 ] |
| 112 | // BAR-NEXT: [ 0, callee3, 0 ] |
| 113 | |
| 114 | |