| // RUN: %clang_profgen -mllvm --enable-value-profiling=true -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=3 -O2 -o %t %s |
| // RUN: %run %t %t.profraw |
| // RUN: llvm-profdata merge -o %t.profdata %t.profraw |
| // RUN: llvm-profdata show --all-functions --counts --ic-targets %t.profdata > %t.profdump |
| // RUN: FileCheck --input-file %t.profdump %s --check-prefix=FOO |
| // RUN: FileCheck --input-file %t.profdump %s --check-prefix=BAR |
| |
| #include <stdint.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| int __llvm_profile_runtime = 0; |
| int __llvm_profile_write_file(); |
| void __llvm_profile_reset_counters(void); |
| void __llvm_profile_merge_from_buffer(const char *, uint64_t); |
| void __llvm_profile_set_filename(const char *); |
| struct __llvm_profile_data; |
| struct ValueProfData; |
| void lprofMergeValueProfData(struct ValueProfData *, struct __llvm_profile_data *); |
| /* Force the vp merger module to be linked in. */ |
| void *Dummy = &lprofMergeValueProfData; |
| |
| void callee1() {} |
| void callee2() {} |
| void callee3() {} |
| |
| typedef void (*FP)(void); |
| FP Fps[3] = {callee1, callee2, callee3}; |
| |
| void foo(int N) { |
| int I, J; |
| for (I = 0; I < 3; I++) |
| for (J = 0; J < I * 2 + 1; J++) |
| Fps[I](); |
| |
| if (N < 2) |
| return; |
| |
| for (I = 0; I < 3; I++) |
| for (J = 0; J < I * 2 + 1; J++) |
| Fps[2 - I](); |
| } |
| |
| /* This function is not profiled */ |
| void bar(void) { |
| int I; |
| for (I = 0; I < 20; I++) |
| Fps[I % 3](); |
| } |
| |
| int main(int argc, const char *argv[]) { |
| int i; |
| if (argc < 2) |
| return 1; |
| |
| const char *FileN = argv[1]; |
| __llvm_profile_set_filename(FileN); |
| /* Start profiling. */ |
| __llvm_profile_reset_counters(); |
| foo(1); |
| /* End profiling by freezing counters and |
| * dump them to the file. */ |
| if (__llvm_profile_write_file()) |
| return 1; |
| |
| /* Read profile data into buffer. */ |
| FILE *File = fopen(FileN, "r"); |
| if (!File) |
| return 1; |
| fseek(File, 0, SEEK_END); |
| uint64_t Size = ftell(File); |
| fseek(File, 0, SEEK_SET); |
| char *Buffer = (char *)malloc(Size); |
| if (Size != fread(Buffer, 1, Size, File)) |
| return 1; |
| fclose(File); |
| |
| /* Its profile will be discarded. */ |
| for (i = 0; i < 10; i++) |
| bar(); |
| |
| /* Start profiling again and merge in previously |
| saved counters in buffer. */ |
| __llvm_profile_reset_counters(); |
| __llvm_profile_merge_from_buffer(Buffer, Size); |
| foo(2); |
| /* End profiling. */ |
| truncate(FileN, 0); |
| if (__llvm_profile_write_file()) |
| return 1; |
| |
| /* Its profile will be discarded. */ |
| bar(); |
| |
| return 0; |
| } |
| |
| // FOO-LABEL: foo: |
| // FOO: Indirect Target Results: |
| // FOO-NEXT: [ 0, callee3, 10 ] |
| // FOO-NEXT: [ 0, callee2, 6 ] |
| // FOO-NEXT: [ 0, callee1, 2 ] |
| // FOO-NEXT: [ 1, callee1, 5 ] |
| // FOO-NEXT: [ 1, callee2, 3 ] |
| // FOO-NEXT: [ 1, callee3, 1 ] |
| |
| // BAR-LABEL: bar: |
| // BAR: [ 0, callee1, 0 ] |
| // BAR-NEXT: [ 0, callee2, 0 ] |
| // BAR-NEXT: [ 0, callee3, 0 ] |
| |