[compiler-rt] r253483 - [PGO] Runtime support for value profiling.

Betul Buyukkurt via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 18 10:12:35 PST 2015


Author: betulb
Date: Wed Nov 18 12:12:35 2015
New Revision: 253483

URL: http://llvm.org/viewvc/llvm-project?rev=253483&view=rev
Log:
[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.


Modified:
    compiler-rt/trunk/lib/profile/InstrProfiling.c
    compiler-rt/trunk/lib/profile/InstrProfiling.h
    compiler-rt/trunk/lib/profile/InstrProfilingBuffer.c
    compiler-rt/trunk/lib/profile/InstrProfilingFile.c

Modified: compiler-rt/trunk/lib/profile/InstrProfiling.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfiling.c?rev=253483&r1=253482&r2=253483&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfiling.c (original)
+++ compiler-rt/trunk/lib/profile/InstrProfiling.c Wed Nov 18 12:12:35 2015
@@ -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;
 }

Modified: compiler-rt/trunk/lib/profile/InstrProfiling.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfiling.h?rev=253483&r1=253482&r2=253483&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfiling.h (original)
+++ compiler-rt/trunk/lib/profile/InstrProfiling.h Wed Nov 18 12:12:35 2015
@@ -10,6 +10,14 @@
 #ifndef PROFILE_INSTRPROFILING_H_
 #define PROFILE_INSTRPROFILING_H_
 
+#ifdef _MSC_VER
+# define LLVM_ALIGNAS(x) __declspec(align(x))
+#elif __GNUC__ && !__has_feature(cxx_alignas)
+# define LLVM_ALIGNAS(x) __attribute__((aligned(x)))
+#else
+# define LLVM_ALIGNAS(x) alignas(x)
+#endif
+
 #if defined(__FreeBSD__) && defined(__i386__)
 
 /* System headers define 'size_t' incorrectly on x64 FreeBSD (prior to
@@ -27,13 +35,31 @@ typedef uint32_t uintptr_t;
 
 #endif /* defined(__FreeBSD__) && defined(__i386__) */
 
+typedef enum ValueKind {
+  VK_IndirectCallTarget = 0,
+  VK_FIRST = VK_IndirectCallTarget,
+  VK_LAST = VK_IndirectCallTarget
+} __llvm_profile_value_kind;
+
+typedef struct __llvm_profile_value_data {
+  uint64_t TargetValue;
+  uint64_t NumTaken;
+} __llvm_profile_value_data;
+
+typedef struct __llvm_profile_value_node {
+  __llvm_profile_value_data VData;
+  struct __llvm_profile_value_node *Next;
+} __llvm_profile_value_node;
 
-typedef struct __llvm_profile_data {
+typedef struct LLVM_ALIGNAS(8) __llvm_profile_data {
   const uint32_t NameSize;
   const uint32_t NumCounters;
   const uint64_t FuncHash;
   const char *const NamePtr;
   uint64_t *const CounterPtr;
+  const uint8_t *FunctionPointer;
+  __llvm_profile_value_node **ValueCounters;
+  const uint16_t NumValueSites[VK_LAST + 1];
 } __llvm_profile_data;
 
 typedef struct __llvm_profile_header {
@@ -44,8 +70,16 @@ typedef struct __llvm_profile_header {
   uint64_t NamesSize;
   uint64_t CountersDelta;
   uint64_t NamesDelta;
+  uint64_t ValueKindLast;
+  uint64_t ValueDataSize;
+  uint64_t ValueDataDelta;
 } __llvm_profile_header;
 
+/*!
+ * \brief Get number of bytes necessary to pad the argument to eight
+ * byte boundary.
+ */
+uint8_t __llvm_profile_get_num_padding_bytes(uint64_t SizeInBytes);
 
 /*!
  * \brief Get required size for profile buffer.
@@ -68,6 +102,23 @@ uint64_t *__llvm_profile_begin_counters(
 uint64_t *__llvm_profile_end_counters(void);
 
 /*!
+ * \brief Counts the number of times a target value is seen.
+ *
+ * Records the target value for the CounterIndex if not seen before. Otherwise,
+ * increments the counter associated w/ the target value.
+ */
+void __llvm_profile_instrument_target(uint64_t TargetValue,
+  void *Data_, uint32_t CounterIndex);
+
+/*!
+ * \brief Prepares the value profiling data for output.
+ *
+ * Prepares a single __llvm_profile_value_data array out of the many
+ * __llvm_profile_value_node trees (one per instrumented function).
+ */
+uint64_t __llvm_profile_gather_value_data(uint8_t **DataArray);
+
+/*!
  * \brief Write instrumentation data to the current file.
  *
  * Writes to the file with the last name given to \a __llvm_profile_set_filename(),

Modified: compiler-rt/trunk/lib/profile/InstrProfilingBuffer.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfilingBuffer.c?rev=253483&r1=253482&r2=253483&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfilingBuffer.c (original)
+++ compiler-rt/trunk/lib/profile/InstrProfilingBuffer.c Wed Nov 18 12:12:35 2015
@@ -35,7 +35,7 @@ uint64_t __llvm_profile_get_size_for_buf
         const char *NamesEnd) {
   /* Match logic in __llvm_profile_write_buffer(). */
   const uint64_t NamesSize = PROFILE_RANGE_SIZE(Names) * sizeof(char);
-  const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+  const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
   return sizeof(__llvm_profile_header) +
       PROFILE_RANGE_SIZE(Data) * sizeof(__llvm_profile_data) +
       PROFILE_RANGE_SIZE(Counters) * sizeof(uint64_t) +
@@ -72,7 +72,7 @@ int __llvm_profile_write_buffer_internal
   const uint64_t DataSize = DataEnd - DataBegin;
   const uint64_t CountersSize = CountersEnd - CountersBegin;
   const uint64_t NamesSize = NamesEnd - NamesBegin;
-  const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+  const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
 
   /* Enough zeroes for padding. */
   const char Zeroes[sizeof(uint64_t)] = {0};
@@ -90,6 +90,9 @@ int __llvm_profile_write_buffer_internal
   Header.NamesSize = NamesSize;
   Header.CountersDelta = (uintptr_t)CountersBegin;
   Header.NamesDelta = (uintptr_t)NamesBegin;
+  Header.ValueKindLast = VK_LAST;
+  Header.ValueDataSize = 0;
+  Header.ValueDataDelta = (uintptr_t)NULL;
 
   /* Write the data. */
 #define UPDATE_memcpy(Data, Size) \

Modified: compiler-rt/trunk/lib/profile/InstrProfilingFile.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/InstrProfilingFile.c?rev=253483&r1=253482&r2=253483&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/InstrProfilingFile.c (original)
+++ compiler-rt/trunk/lib/profile/InstrProfilingFile.c Wed Nov 18 12:12:35 2015
@@ -24,12 +24,15 @@ static int writeFile(FILE *File) {
   const uint64_t *CountersEnd   = __llvm_profile_end_counters();
   const char *NamesBegin = __llvm_profile_begin_names();
   const char *NamesEnd   = __llvm_profile_end_names();
+  uint8_t *ValueDataBegin = NULL;
 
   /* Calculate size of sections. */
   const uint64_t DataSize = DataEnd - DataBegin;
   const uint64_t CountersSize = CountersEnd - CountersBegin;
   const uint64_t NamesSize = NamesEnd - NamesBegin;
-  const uint64_t Padding = sizeof(uint64_t) - NamesSize % sizeof(uint64_t);
+  const uint8_t Padding = __llvm_profile_get_num_padding_bytes(NamesSize);
+  const uint64_t ValueDataSize =
+      __llvm_profile_gather_value_data(&ValueDataBegin);
 
   /* Enough zeroes for padding. */
   const char Zeroes[sizeof(uint64_t)] = {0};
@@ -47,17 +50,22 @@ static int writeFile(FILE *File) {
   Header.NamesSize = NamesSize;
   Header.CountersDelta = (uintptr_t)CountersBegin;
   Header.NamesDelta = (uintptr_t)NamesBegin;
+  Header.ValueKindLast = VK_LAST;
+  Header.ValueDataSize = ValueDataSize;
+  Header.ValueDataDelta = (uintptr_t)ValueDataBegin;
 
   /* Write the data. */
 #define CHECK_fwrite(Data, Size, Length, File) \
   do { if (fwrite(Data, Size, Length, File) != Length) return -1; } while (0)
-  CHECK_fwrite(&Header,        sizeof(__llvm_profile_header), 1, File);
+  CHECK_fwrite(&Header,       sizeof(__llvm_profile_header), 1, File);
   CHECK_fwrite(DataBegin,     sizeof(__llvm_profile_data), DataSize, File);
   CHECK_fwrite(CountersBegin, sizeof(uint64_t), CountersSize, File);
   CHECK_fwrite(NamesBegin,    sizeof(char), NamesSize, File);
   CHECK_fwrite(Zeroes,        sizeof(char), Padding, File);
+  CHECK_fwrite(ValueDataBegin,
+      sizeof(__llvm_profile_value_data), ValueDataSize, File);
 #undef CHECK_fwrite
-
+  free(ValueDataBegin);
   return 0;
 }
 




More information about the llvm-commits mailing list