[compiler-rt] r203710 - profile: Use a simple binary format for profiling

Justin Bogner mail at justinbogner.com
Wed Mar 12 13:52:34 PDT 2014


Author: bogner
Date: Wed Mar 12 15:52:34 2014
New Revision: 203710

URL: http://llvm.org/viewvc/llvm-project?rev=203710&view=rev
Log:
profile: Use a simple binary format for profiling

Modified:
    compiler-rt/trunk/lib/profile/PGOProfiling.c

Modified: compiler-rt/trunk/lib/profile/PGOProfiling.c
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/profile/PGOProfiling.c?rev=203710&r1=203709&r2=203710&view=diff
==============================================================================
--- compiler-rt/trunk/lib/profile/PGOProfiling.c (original)
+++ compiler-rt/trunk/lib/profile/PGOProfiling.c Wed Mar 12 15:52:34 2014
@@ -7,8 +7,10 @@
 |*
 \*===----------------------------------------------------------------------===*/
 
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
 
 #define I386_FREEBSD (defined(__FreeBSD__) && defined(__i386__))
 
@@ -35,65 +37,181 @@ typedef unsigned long long uint64_t;
 static FILE *OutputFile = NULL;
 
 /*
- * A list of functions to write out the data.
+ * A list of functions to register counters.
  */
-typedef void (*writeout_fn)();
+typedef void (*CounterFunc)();
 
-struct writeout_fn_node {
-  writeout_fn fn;
-  struct writeout_fn_node *next;
+struct CounterFuncNode {
+  CounterFunc Func;
+  struct CounterFuncNode *Next;
 };
 
-static struct writeout_fn_node *writeout_fn_head = NULL;
-static struct writeout_fn_node *writeout_fn_tail = NULL;
+static struct CounterFuncNode *CounterFuncHead = NULL;
+static struct CounterFuncNode *CounterFuncTail = NULL;
 
-void llvm_pgo_emit(const char *MangledName, uint32_t NumCounters,
-                   uint64_t *Counters) {
-  uint32_t i;
-  fprintf(OutputFile, "%s %u\n", MangledName, NumCounters);
-  for (i = 0; i < NumCounters; ++i)
-    fprintf(OutputFile, "%" PRIu64 "\n", Counters[i]);
-  fprintf(OutputFile, "\n");
-}
-
-void llvm_pgo_register_writeout_function(writeout_fn fn) {
-  struct writeout_fn_node *new_node = malloc(sizeof(struct writeout_fn_node));
-  new_node->fn = fn;
-  new_node->next = NULL;
+static uint64_t CounterBufSize;
+static uint64_t CounterNextIndex;
+static uint64_t *CounterData;
+
+struct __attribute__((packed)) ProfileDataHeader {
+  char     Magic[4];
+  uint32_t Version;
+  uint32_t DataStart;
+  uint32_t Padding;
+  uint64_t MaxFunctionCount;
+};
+
+static struct ProfileDataHeader ProfileDataHeader = {
+  .Magic = {'L', 'P', 'R', 'F'},
+  .Version = 1,
+  .DataStart = 0,
+  .Padding = 0,
+  .MaxFunctionCount = 0
+};
+
+static int write32(uint32_t Val) {
+  char Buf[4] = {Val >> 0, Val >> 8, Val >> 16, Val >> 24};
+  return fwrite(Buf, 1, 4, OutputFile) != 4;
+}
+
+static int write64(uint64_t Val) {
+  char Buf[8] = {Val >> 0,  Val >> 8,  Val >> 16, Val >> 24,
+                 Val >> 32, Val >> 40, Val >> 48, Val >> 56};
+  return fwrite(Buf, 1, 8, OutputFile) != 8;
+}
+
+static int writeChars(const char *Val, size_t Count) {
+  return fwrite(Val, 1, Count, OutputFile) != Count;
+}
+
+static int writeIndexEntry(const char *Name) {
+  uint32_t Len = strlen(Name);
+  if (write32(Len)) return 1;
+  if (writeChars(Name, Len)) return 1;
+  if (write32(CounterNextIndex * sizeof(uint64_t))) return 1;
+  return 0;
+}
+
+static int addCounters(uint64_t FunctionHash, uint32_t NumCounters,
+                       uint64_t *Counters) {
+  uint64_t Needed = sizeof(uint64_t) * (CounterNextIndex + NumCounters + 2);
+  if (CounterBufSize < Needed) {
+    while (CounterBufSize < Needed)
+      CounterBufSize *= 2;
+    uint64_t *PrevData = CounterData;
+    if (NULL == (CounterData = realloc(CounterData, CounterBufSize))) {
+      free(PrevData);
+      return 1;
+    }
+  }
+  CounterData[CounterNextIndex++] = FunctionHash;
+  CounterData[CounterNextIndex++] = NumCounters;
+  if (NumCounters > 0 && Counters[0] > ProfileDataHeader.MaxFunctionCount)
+    ProfileDataHeader.MaxFunctionCount = Counters[0];
+  for (uint32_t I = 0; I < NumCounters; ++I)
+    CounterData[CounterNextIndex++] = Counters[I];
+  return 0;
+}
+
+static int reserveHeader() {
+  return fseek(OutputFile, sizeof(struct ProfileDataHeader), SEEK_SET) != 0;
+}
 
-  if (!writeout_fn_head) {
-    writeout_fn_head = writeout_fn_tail = new_node;
+static int writeIndex() {
+  if (!CounterData) {
+    CounterBufSize = 4096;
+    if (NULL == (CounterData = malloc(CounterBufSize)))
+      return 1;
+  }
+  while (CounterFuncHead) {
+    struct CounterFuncNode *Node = CounterFuncHead;
+    CounterFuncHead = CounterFuncHead->Next;
+    Node->Func();
+    free(Node);
+  }
+  return 0;
+}
+
+static int writeCounterData() {
+  ProfileDataHeader.DataStart = ftell(OutputFile);
+  if (fseek(OutputFile,
+            sizeof(uint64_t) - ProfileDataHeader.DataStart % sizeof(uint64_t),
+            SEEK_CUR) != 0)
+    return 1;
+  for (uint32_t I = 0; I < CounterNextIndex; ++I)
+    if (write64(CounterData[I])) return 1;
+  return 0;
+}
+
+static int writeHeader() {
+  if (fseek(OutputFile, 0, SEEK_SET) != 0) return 1;
+  if (writeChars(ProfileDataHeader.Magic, 4)) return 1;
+  if (write32(ProfileDataHeader.Version)) return 1;
+  if (write32(ProfileDataHeader.DataStart)) return 1;
+  if (write32(ProfileDataHeader.Padding)) return 1;
+  if (write64(ProfileDataHeader.MaxFunctionCount)) return 1;
+  return 0;
+}
+
+void llvm_pgo_add_function(const char *MangledName, uint64_t FunctionHash,
+                           uint32_t NumCounters, uint64_t *Counters) {
+  if (!CounterData) return;
+  if (writeIndexEntry(MangledName)) {
+    fprintf(stderr, "profile: Failed to write index for %s\n", MangledName);
+    return;
+  }
+  if (addCounters(FunctionHash, NumCounters, Counters)) {
+    fprintf(stderr, "profile: Failed to add counters for %s\n", MangledName);
+    return;
+  }
+}
+
+void llvm_pgo_register_counter_function(CounterFunc Func) {
+  struct CounterFuncNode *NewNode = malloc(sizeof(struct CounterFuncNode));
+  if (!NewNode) {
+    fprintf(stderr, "profile: Failed to register counter function: %p\n",
+            Func);
+    return;
+  }
+  NewNode->Func = Func;
+  NewNode->Next = NULL;
+
+  if (!CounterFuncHead) {
+    CounterFuncHead = CounterFuncTail = NewNode;
   } else {
-    writeout_fn_tail->next = new_node;
-    writeout_fn_tail = new_node;
+    CounterFuncTail->Next = NewNode;
+    CounterFuncTail = NewNode;
   }
 }
 
-void llvm_pgo_writeout_files() {
+void llvm_pgo_write_file() {
   const char *OutputName = getenv("LLVM_PROFILE_FILE");
   if (OutputName == NULL || OutputName[0] == '\0')
     OutputName = "default.profdata";
   OutputFile = fopen(OutputName, "w");
-  if (!OutputFile) return;
-
-  while (writeout_fn_head) {
-    struct writeout_fn_node *node = writeout_fn_head;
-    writeout_fn_head = writeout_fn_head->next;
-    node->fn();
-    free(node);
+  if (!OutputFile) {
+    fprintf(stderr, "profile: Failed to open %s for writing: %s\n",
+            OutputName, strerror(errno));
+    return;
   }
 
+  if (reserveHeader()) goto end;
+  if (writeIndex()) goto end;
+  if (writeCounterData()) goto end;
+  if (writeHeader()) goto end;
+
+end:
+  if (CounterData) free(CounterData);
   fclose(OutputFile);
 }
 
-void llvm_pgo_init(writeout_fn wfn) {
-  static int atexit_ran = 0;
+void llvm_pgo_init(CounterFunc Func) {
+  static int Ran = 0;
 
-  if (wfn)
-    llvm_pgo_register_writeout_function(wfn);
+  llvm_pgo_register_counter_function(Func);
 
-  if (atexit_ran == 0) {
-    atexit_ran = 1;
-    atexit(llvm_pgo_writeout_files);
+  if (Ran == 0) {
+    Ran = 1;
+    atexit(llvm_pgo_write_file);
   }
 }





More information about the llvm-commits mailing list