Index: compiler-rt/trunk/lib/profile/CMakeLists.txt =================================================================== --- compiler-rt/trunk/lib/profile/CMakeLists.txt +++ compiler-rt/trunk/lib/profile/CMakeLists.txt @@ -30,6 +30,8 @@ InstrProfilingValue.c InstrProfilingBuffer.c InstrProfilingFile.c + InstrProfilingMerge.c + InstrProfilingMergeFile.c InstrProfilingWriter.c InstrProfilingPlatformDarwin.c InstrProfilingPlatformLinux.c Index: compiler-rt/trunk/lib/profile/InstrProfiling.h =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfiling.h +++ compiler-rt/trunk/lib/profile/InstrProfiling.h @@ -63,6 +63,15 @@ void __llvm_profile_reset_counters(void); /*! + * \brief Read profile data form buffer and merge with + * in-process profile counters. The client is expected to + * have checked or already knows the profile data in the + * buffer matches the in-process counter structure before + * calling it. + */ +void __llvm_profile_merge_from_buffer(const char *Profile, uint64_t Size); + +/*! * \brief Counts the number of times a target value is seen. * * Records the target value for the CounterIndex if not seen before. Otherwise, Index: compiler-rt/trunk/lib/profile/InstrProfilingInternal.h =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfilingInternal.h +++ compiler-rt/trunk/lib/profile/InstrProfilingInternal.h @@ -109,10 +109,15 @@ struct ValueProfData **ValueDataBeginArray, const uint64_t ValueDataSize, const char *NamesBegin, const char *NamesEnd); +/* Merge value profile data pointed to by SrcValueProfData into + * in-memory profile counters pointed by to DstData. */ +void mergeValueProfData(struct ValueProfData *SrcValueProfData, + __llvm_profile_data *DstData); extern char *(*GetEnvHook)(const char *); extern void (*FreeHook)(void *); -extern void* (*CallocHook)(size_t, size_t); +extern void *(*CallocHook)(size_t, size_t); +extern void (*VPMergeHook)(struct ValueProfData *, __llvm_profile_data *); extern uint32_t VPBufferSize; #endif Index: compiler-rt/trunk/lib/profile/InstrProfilingMerge.c =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfilingMerge.c +++ compiler-rt/trunk/lib/profile/InstrProfilingMerge.c @@ -0,0 +1,70 @@ +/*===- InstrProfilingMerge.c - Profile in-process Merging ---------------===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------===* +|* This file defines the API needed for in-process merging of profile data +|* stored in memory buffer. +\*===---------------------------------------------------------------------===*/ + +#include "InstrProfiling.h" +#include "InstrProfilingInternal.h" +#include "InstrProfilingUtil.h" + +#define INSTR_PROF_VALUE_PROF_DATA +#include "InstrProfData.inc" + +COMPILER_RT_WEAK void (*VPMergeHook)(ValueProfData *, + __llvm_profile_data *) = NULL; + +void __llvm_profile_merge_from_buffer(const char *ProfileData, + uint64_t ProfileSize) { + __llvm_profile_data *SrcDataStart, *SrcDataEnd, *SrcData, *DstData; + __llvm_profile_header *Header = (__llvm_profile_header *)ProfileData; + uint64_t *SrcCountersStart; + const char *SrcNameStart; + ValueProfData *SrcValueProfDataStart, *SrcValueProfData; + + SrcDataStart = + (__llvm_profile_data *)(ProfileData + sizeof(__llvm_profile_header)); + SrcDataEnd = SrcDataStart + Header->DataSize; + SrcCountersStart = (uint64_t *)SrcDataEnd; + SrcNameStart = (const char *)(SrcCountersStart + Header->CountersSize); + SrcValueProfDataStart = + (ValueProfData *)(SrcNameStart + Header->NamesSize + + __llvm_profile_get_num_padding_bytes( + Header->NamesSize)); + + for (SrcData = SrcDataStart, + DstData = (__llvm_profile_data *)__llvm_profile_begin_data(), + SrcValueProfData = SrcValueProfDataStart; + SrcData < SrcDataEnd; ++SrcData, ++DstData) { + uint64_t *SrcCounters; + uint64_t *DstCounters = (uint64_t *)DstData->CounterPtr; + unsigned I, NC, NVK = 0; + + NC = SrcData->NumCounters; + SrcCounters = SrcCountersStart + + ((size_t)SrcData->CounterPtr - Header->CountersDelta) / + sizeof(uint64_t); + for (I = 0; I < NC; I++) + DstCounters[I] += SrcCounters[I]; + + /* Now merge value profile data. */ + if (!VPMergeHook) + continue; + + for (I = 0; I <= IPVK_Last; I++) + NVK += (SrcData->NumValueSites[I] != 0); + + if (!NVK) + continue; + + VPMergeHook(SrcValueProfData, DstData); + SrcValueProfData = (ValueProfData *)((char *)SrcValueProfData + + SrcValueProfData->TotalSize); + } +} Index: compiler-rt/trunk/lib/profile/InstrProfilingMergeFile.c =================================================================== --- compiler-rt/trunk/lib/profile/InstrProfilingMergeFile.c +++ compiler-rt/trunk/lib/profile/InstrProfilingMergeFile.c @@ -0,0 +1,41 @@ +/*===- InstrProfilingMergeFile.c - Profile in-process Merging ------------===*\ +|* +|* The LLVM Compiler Infrastructure +|* +|* This file is distributed under the University of Illinois Open Source +|* License. See LICENSE.TXT for details. +|* +|*===----------------------------------------------------------------------=== +|* This file defines APIs needed to support in-process merging for profile data +|* stored in files. +\*===----------------------------------------------------------------------===*/ + +#include "InstrProfiling.h" +#include "InstrProfilingInternal.h" +#include "InstrProfilingUtil.h" + +#define INSTR_PROF_VALUE_PROF_DATA +#include "InstrProfData.inc" + +void (*VPMergeHook)(ValueProfData *, + __llvm_profile_data *) = &mergeValueProfData; + +/* Merge value profile data pointed to by SrcValueProfData into + * in-memory profile counters pointed by to DstData. */ +void mergeValueProfData(ValueProfData *SrcValueProfData, + __llvm_profile_data *DstData) { + unsigned I, S, V, C; + InstrProfValueData *VData; + ValueProfRecord *VR = getFirstValueProfRecord(SrcValueProfData); + for (I = 0; I < SrcValueProfData->NumValueKinds; I++) { + VData = getValueProfRecordValueData(VR); + for (S = 0; S < VR->NumValueSites; S++) { + uint8_t NV = VR->SiteCountArray[S]; + for (V = 0; V < NV; V++) { + for (C = 0; C < VData[V].Count; C++) + __llvm_profile_instrument_target(VData[V].Value, DstData, S); + } + } + VR = getValueProfRecordNext(VR); + } +} Index: compiler-rt/trunk/make/platform/clang_linux.mk =================================================================== --- compiler-rt/trunk/make/platform/clang_linux.mk +++ compiler-rt/trunk/make/platform/clang_linux.mk @@ -79,7 +79,8 @@ FUNCTIONS.profile-i386 := GCDAProfiling InstrProfiling InstrProfilingBuffer \ InstrProfilingFile InstrProfilingPlatformOther \ InstrProfilingRuntime InstrProfilingUtil \ - InstrProfilingWriter InstrProfilingValue + InstrProfilingWriter InstrProfilingValue \ + InstrProfilingMerge InstrProfilingMergeFile FUNCTIONS.profile-x86_64 := $(FUNCTIONS.profile-i386) # Always use optimized variants. Index: compiler-rt/trunk/test/profile/Linux/instrprof-merge-vp.c =================================================================== --- compiler-rt/trunk/test/profile/Linux/instrprof-merge-vp.c +++ compiler-rt/trunk/test/profile/Linux/instrprof-merge-vp.c @@ -0,0 +1,110 @@ +// RUN: %clang_profgen -mllvm --enable-value-profiling=true -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 | FileCheck %s + +#include +#include +#include +#include +#include + +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 mergeValueProfData(struct ValueProfData *, struct __llvm_profile_data *); +/* Force the vp merger module to be linked in. */ +void *Dummy = &mergeValueProfData; + +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; +} + +// CHECK-LABEL: foo: +// CHECK: Indirect Target Results: +// CHECK-NEXT: [ 0, callee3, 10 ] +// CHECK-NEXT: [ 0, callee2, 6 ] +// CHECK-NEXT: [ 0, callee1, 2 ] +// CHECK-NEXT: [ 1, callee1, 5 ] +// CHECK-NEXT: [ 1, callee2, 3 ] +// CHECK-NEXT: [ 1, callee3, 1 ] + +// CHECK-LABEL: bar: +// CHECK: [ 0, callee1, 0 ] +// CHECK-NEXT: [ 0, callee2, 0 ] +// CHECK-NEXT: [ 0, callee3, 0 ] Index: compiler-rt/trunk/test/profile/instrprof-merge.c =================================================================== --- compiler-rt/trunk/test/profile/instrprof-merge.c +++ compiler-rt/trunk/test/profile/instrprof-merge.c @@ -0,0 +1,96 @@ +// RUN: %clang_profgen -O2 -o %t %s +// RUN: %run %t %t.profraw 1 1 +// RUN: llvm-profdata show --all-functions --counts %t.profraw | FileCheck %s + +#include +#include +#include + +int __llvm_profile_runtime = 0; +uint64_t __llvm_profile_get_size_for_buffer(void); +int __llvm_profile_write_buffer(char *); +void __llvm_profile_reset_counters(void); +void __llvm_profile_merge_from_buffer(const char *, uint64_t); + +int dumpBuffer(const char *FileN, const char *Buffer, uint64_t Size) { + FILE *File = fopen(FileN, "w"); + if (!File) + return 1; + if (fwrite(Buffer, 1, Size, File) != Size) + return 1; + return fclose(File); +} + +int g = 0; +void foo(char c) { + if (c == '1') + g++; + else + g--; +} + +/* This function is not profiled */ +void bar(int M) { g += M; } + +int main(int argc, const char *argv[]) { + int i; + if (argc < 4) + return 1; + + const uint64_t MaxSize = 10000; + static char Buffer[MaxSize]; + + uint64_t Size = __llvm_profile_get_size_for_buffer(); + if (Size > MaxSize) + return 1; + + /* Start profiling. */ + __llvm_profile_reset_counters(); + foo(argv[2][0]); + /* End profiling by freezing counters. */ + if (__llvm_profile_write_buffer(Buffer)) + return 1; + + /* Its profile will be discarded. */ + for (i = 0; i < 10; i++) + bar(1); + + /* Start profiling again and merge in previously + saved counters in buffer. */ + __llvm_profile_reset_counters(); + __llvm_profile_merge_from_buffer(Buffer, Size); + foo(argv[3][0]); + /* End profiling */ + if (__llvm_profile_write_buffer(Buffer)) + return 1; + + /* Its profile will be discarded. */ + bar(2); + + /* Now it is time to dump the profile to file. */ + return dumpBuffer(argv[1], Buffer, Size); +} + +// Not profiled +// CHECK-LABEL: dumpBuffer: +// CHECK: Counters: 3 +// CHECK-NEXT: Function count: 0 +// CHECK-NEXT: Block counts: [0, 0] + +// Profiled with entry count == 2 +// CHECK-LABEL: foo: +// CHECK: Counters: 2 +// CHECK-NEXT: Function count: 2 +// CHECK-NEXT: Block counts: [2] + +// Not profiled +// CHECK-LABEL: bar: +// CHECK: Counters: 1 +// CHECK-NEXT Function count: 0 +// CHECK-NEXT Block counts: [] + +// Not profiled +// CHECK-LABEL: main: +// CHECK: Counters: 6 +// CHECK-NEXT: Function count: 0 +// CHECK-NEXT: Block counts: [0, 0, 0, 0, 0] Index: compiler-rt/trunk/test/profile/instrprof-without-libc.c =================================================================== --- compiler-rt/trunk/test/profile/instrprof-without-libc.c +++ compiler-rt/trunk/test/profile/instrprof-without-libc.c @@ -15,6 +15,8 @@ int __llvm_profile_runtime = 0; uint64_t __llvm_profile_get_size_for_buffer(void); int __llvm_profile_write_buffer(char *); +void __llvm_profile_merge_from_buffer(const char *, uint64_t Size); + int write_buffer(uint64_t, const char *); int main(int argc, const char *argv[]) { // CHECK-LABEL: define {{.*}} @main( @@ -35,6 +37,8 @@ #ifdef CHECK_SYMBOLS // Don't write it out. Since we're checking the symbols, we don't have libc // available. + // Call merge function to make sure it does not bring in libc deps: + __llvm_profile_merge_from_buffer(Buffer, Size); return 0; #else // Actually write it out so we can FileCheck the output.