summaryrefslogtreecommitdiff
path: root/lib/profile/InstrProfiling.c
diff options
context:
space:
mode:
authorBetul Buyukkurt <betulb@codeaurora.org>2015-11-18 18:12:35 +0000
committerBetul Buyukkurt <betulb@codeaurora.org>2015-11-18 18:12:35 +0000
commit70aaff4fae73a7e4317ccc4fa99fd6fc4790c61a (patch)
tree574825499a999f5eda6e6095cc46eb164524d1ab /lib/profile/InstrProfiling.c
parent8b80397af93ddfd07561e8d9c56681a49006d44a (diff)
[PGO] Runtime support for value profiling.
This change adds extends the data structures and adds in the routines for handling runtime calls for value profiling. The profile data format is modified and the version number is incremented. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@253483 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/profile/InstrProfiling.c')
-rw-r--r--lib/profile/InstrProfiling.c148
1 files changed, 147 insertions, 1 deletions
diff --git a/lib/profile/InstrProfiling.c b/lib/profile/InstrProfiling.c
index 8d010df28..42779acc7 100644
--- a/lib/profile/InstrProfiling.c
+++ b/lib/profile/InstrProfiling.c
@@ -8,6 +8,8 @@
\*===----------------------------------------------------------------------===*/
#include "InstrProfiling.h"
+#include <limits.h>
+#include <stdlib.h>
#include <string.h>
__attribute__((visibility("hidden")))
@@ -34,9 +36,14 @@ uint64_t __llvm_profile_get_magic(void) {
}
__attribute__((visibility("hidden")))
+uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes) {
+ return 7 & (sizeof(uint64_t) - SizeInBytes % sizeof(uint64_t));
+}
+
+__attribute__((visibility("hidden")))
uint64_t __llvm_profile_get_version(void) {
/* This should be bumped any time the output format changes. */
- return 1;
+ return 2;
}
__attribute__((visibility("hidden")))
@@ -45,4 +52,143 @@ void __llvm_profile_reset_counters(void) {
uint64_t *E = __llvm_profile_end_counters();
memset(I, 0, sizeof(uint64_t)*(E - I));
+
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ for (const __llvm_profile_data *DI = DataBegin; DI != DataEnd; ++DI) {
+ if (!DI->ValueCounters)
+ continue;
+
+ uint64_t CurrentVSiteCount = 0;
+ for (uint32_t VKI = VK_FIRST; VKI <= VK_LAST; ++VKI)
+ CurrentVSiteCount += DI->NumValueSites[VKI];
+
+ for (uint32_t i = 0; i < CurrentVSiteCount; ++i) {
+ __llvm_profile_value_node *CurrentVNode = DI->ValueCounters[i];
+
+ while (CurrentVNode) {
+ CurrentVNode->VData.NumTaken = 0;
+ CurrentVNode = CurrentVNode->Next;
+ }
+ }
+ }
+}
+
+static uint64_t TotalValueDataSize = 0;
+
+__attribute__((visibility("hidden")))
+void __llvm_profile_instrument_target(uint64_t TargetValue, void *Data_,
+ uint32_t CounterIndex) {
+
+ __llvm_profile_data *Data = (__llvm_profile_data*)Data_;
+ if (!Data)
+ return;
+
+ if (!Data->ValueCounters) {
+ uint64_t NumVSites = 0;
+ for (uint32_t VKI = VK_FIRST; VKI <= VK_LAST; ++VKI)
+ NumVSites += Data->NumValueSites[VKI];
+
+ __llvm_profile_value_node** Mem = (__llvm_profile_value_node**)
+ calloc(NumVSites, sizeof(__llvm_profile_value_node*));
+ if (!Mem)
+ return;
+ if (!__sync_bool_compare_and_swap(&Data->ValueCounters, 0, Mem)) {
+ free(Mem);
+ return;
+ }
+ // Acccount for padding during write out.
+ uint8_t Padding = __llvm_profile_get_num_padding_bytes(NumVSites);
+ __sync_fetch_and_add(&TotalValueDataSize, NumVSites + Padding);
+ }
+
+ __llvm_profile_value_node *PrevVNode = NULL;
+ __llvm_profile_value_node *CurrentVNode = Data->ValueCounters[CounterIndex];
+
+ uint8_t VDataCount = 0;
+ while (CurrentVNode) {
+ if (TargetValue == CurrentVNode->VData.TargetValue) {
+ CurrentVNode->VData.NumTaken++;
+ return;
+ }
+ PrevVNode = CurrentVNode;
+ CurrentVNode = CurrentVNode->Next;
+ ++VDataCount;
+ }
+
+ if (VDataCount >= UCHAR_MAX)
+ return;
+
+ CurrentVNode = (__llvm_profile_value_node*)
+ calloc(1, sizeof(__llvm_profile_value_node));
+ if (!CurrentVNode)
+ return;
+
+ CurrentVNode->VData.TargetValue = TargetValue;
+ CurrentVNode->VData.NumTaken++;
+
+ uint32_t Success = 0;
+ if (!Data->ValueCounters[CounterIndex])
+ Success = __sync_bool_compare_and_swap(
+ &(Data->ValueCounters[CounterIndex]), 0, CurrentVNode);
+ else if (PrevVNode && !PrevVNode->Next)
+ Success = __sync_bool_compare_and_swap(&(PrevVNode->Next), 0, CurrentVNode);
+
+ if (!Success) {
+ free(CurrentVNode);
+ return;
+ }
+ __sync_fetch_and_add(&TotalValueDataSize,
+ Success * sizeof(__llvm_profile_value_data));
+}
+
+__attribute__((visibility("hidden")))
+uint64_t __llvm_profile_gather_value_data(uint8_t **VDataArray) {
+
+ if (!VDataArray || 0 == TotalValueDataSize)
+ return 0;
+
+ uint64_t NumData = TotalValueDataSize;
+ *VDataArray = (uint8_t*) calloc(NumData, sizeof(uint8_t));
+ if (!*VDataArray)
+ return 0;
+
+ uint8_t *VDataEnd = *VDataArray + NumData;
+ uint8_t *PerSiteCountsHead = *VDataArray;
+ const __llvm_profile_data *DataEnd = __llvm_profile_end_data();
+ const __llvm_profile_data *DataBegin = __llvm_profile_begin_data();
+ for (__llvm_profile_data *I = (__llvm_profile_data *)DataBegin;
+ I != DataEnd; ++I) {
+
+ if (!I->ValueCounters)
+ continue;
+
+ uint64_t NumVSites = 0;
+ for (uint32_t VKI = VK_FIRST; VKI <= VK_LAST; ++VKI)
+ NumVSites += I->NumValueSites[VKI];
+ uint8_t Padding = __llvm_profile_get_num_padding_bytes(NumVSites);
+
+ uint8_t *PerSiteCountPtr = PerSiteCountsHead;
+ __llvm_profile_value_data *VDataPtr =
+ (__llvm_profile_value_data *)(PerSiteCountPtr + NumVSites + Padding);
+
+ for (uint32_t i = 0; i < NumVSites; ++i) {
+
+ __llvm_profile_value_node *VNode = I->ValueCounters[i];
+
+ uint8_t VDataCount = 0;
+ while (VNode && ((uint8_t*)(VDataPtr + 1) <= VDataEnd)) {
+ *VDataPtr = VNode->VData;
+ VNode = VNode->Next;
+ ++VDataPtr;
+ if (++VDataCount == UCHAR_MAX)
+ break;
+ }
+ *PerSiteCountPtr = VDataCount;
+ ++PerSiteCountPtr;
+ }
+ I->ValueCounters = (void *)PerSiteCountsHead;
+ PerSiteCountsHead = (uint8_t *)VDataPtr;
+ }
+ return PerSiteCountsHead - *VDataArray;
}