Reland compiler-rt support for order file instrumentation.
authorManman Ren <manman.ren@gmail.com>
Fri, 8 Mar 2019 15:30:56 +0000 (15:30 +0000)
committerManman Ren <manman.ren@gmail.com>
Fri, 8 Mar 2019 15:30:56 +0000 (15:30 +0000)
r355343 was landed and was reverted in r355363 due to build breakage.
This patch adds Linux/Windows support on top of r355343.

In this patch, Darwin should be working with testing case. Linux should be working,
I will enable the testing case in a follwup diff. Windows/Other should be building.
Correct implementation for Other platforms will be added.

Thanks David for reviewing the original diff, helping me with issues on Linux, and
giving suggestions for adding support for Other platforms.

llvm-svn: 355701

compiler-rt/lib/profile/InstrProfData.inc
compiler-rt/lib/profile/InstrProfiling.h
compiler-rt/lib/profile/InstrProfilingFile.c
compiler-rt/lib/profile/InstrProfilingPlatformDarwin.c
compiler-rt/lib/profile/InstrProfilingPlatformLinux.c
compiler-rt/lib/profile/InstrProfilingPlatformOther.c
compiler-rt/lib/profile/InstrProfilingPlatformWindows.c
compiler-rt/test/profile/Inputs/instrprof-order-file-2.c [new file with mode: 0644]
compiler-rt/test/profile/Inputs/instrprof-order-file.c [new file with mode: 0644]
compiler-rt/test/profile/instrprof-order-file.test [new file with mode: 0644]

index 19d4651..8a3855b 100644 (file)
@@ -265,6 +265,9 @@ INSTR_PROF_SECT_ENTRY(IPSK_vnodes, \
 INSTR_PROF_SECT_ENTRY(IPSK_covmap, \
                       INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON), \
                       INSTR_PROF_COVMAP_COFF, "__LLVM_COV,")
+INSTR_PROF_SECT_ENTRY(IPSK_orderfile, \
+                      INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON), \
+                      INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COFF), "__DATA,")
 
 #undef INSTR_PROF_SECT_ENTRY
 #endif
@@ -656,6 +659,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
 #define INSTR_PROF_VALS_COMMON __llvm_prf_vals
 #define INSTR_PROF_VNODES_COMMON __llvm_prf_vnds
 #define INSTR_PROF_COVMAP_COMMON __llvm_covmap
+#define INSTR_PROF_ORDERFILE_COMMON __llvm_orderfile
 /* Windows section names. Because these section names contain dollar characters,
  * they must be quoted.
  */
@@ -665,6 +669,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
 #define INSTR_PROF_VALS_COFF ".lprfv$M"
 #define INSTR_PROF_VNODES_COFF ".lprfnd$M"
 #define INSTR_PROF_COVMAP_COFF ".lcovmap$M"
+#define INSTR_PROF_ORDERFILE_COFF ".lorderfile$M"
 
 #ifdef _WIN32
 /* Runtime section names and name strings.  */
@@ -678,6 +683,7 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
 /* Value profile nodes section. */
 #define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_VNODES_COFF
 #define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_COVMAP_COFF
+#define INSTR_PROF_ORDERFILE_SECT_NAME INSTR_PROF_ORDERFILE_COFF
 #else
 /* Runtime section names and name strings.  */
 #define INSTR_PROF_DATA_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_DATA_COMMON)
@@ -690,8 +696,18 @@ serializeValueProfDataFrom(ValueProfRecordClosure *Closure,
 /* Value profile nodes section. */
 #define INSTR_PROF_VNODES_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_VNODES_COMMON)
 #define INSTR_PROF_COVMAP_SECT_NAME INSTR_PROF_QUOTE(INSTR_PROF_COVMAP_COMMON)
+/* Order file instrumentation. */
+#define INSTR_PROF_ORDERFILE_SECT_NAME                                         \
+  INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_COMMON)
 #endif
 
+#define INSTR_PROF_ORDERFILE_BUFFER_NAME _llvm_order_file_buffer
+#define INSTR_PROF_ORDERFILE_BUFFER_NAME_STR                                   \
+  INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_BUFFER_NAME)
+#define INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME _llvm_order_file_buffer_idx
+#define INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME_STR                               \
+  INSTR_PROF_QUOTE(INSTR_PROF_ORDERFILE_BUFFER_IDX_NAME)
+
 /* Macros to define start/stop section symbol for a given
  * section on Linux. For instance
  * INSTR_PROF_SECT_START(INSTR_PROF_DATA_SECT_NAME) will
@@ -725,6 +741,12 @@ typedef struct InstrProfValueData {
 
 #endif /* INSTR_PROF_DATA_INC */
 
+#ifndef INSTR_ORDER_FILE_INC
+// The maximal # of functions: 128*1024 (the buffer size will be 128*4 KB).
+#define INSTR_ORDER_FILE_BUFFER_SIZE 131072
+#define INSTR_ORDER_FILE_BUFFER_BITS 17
+#define INSTR_ORDER_FILE_BUFFER_MASK 0x1ffff
+#endif /* INSTR_ORDER_FILE_INC */
 #else
 #undef INSTR_PROF_DATA_DEFINED
 #endif
index 0f9565a..857cff4 100644 (file)
@@ -64,6 +64,7 @@ uint64_t *__llvm_profile_begin_counters(void);
 uint64_t *__llvm_profile_end_counters(void);
 ValueProfNode *__llvm_profile_begin_vnodes();
 ValueProfNode *__llvm_profile_end_vnodes();
+uint32_t *__llvm_profile_begin_orderfile();
 
 /*!
  * \brief Clear profile counters to zero.
@@ -120,6 +121,7 @@ void __llvm_profile_instrument_target_value(uint64_t TargetValue, void *Data,
  */
 int __llvm_profile_write_file(void);
 
+int __llvm_orderfile_write_file(void);
 /*!
  * \brief this is a wrapper interface to \c __llvm_profile_write_file.
  * After this interface is invoked, a arleady dumped flag will be set
@@ -142,6 +144,8 @@ int __llvm_profile_write_file(void);
  */
 int __llvm_profile_dump(void);
 
+int __llvm_orderfile_dump(void);
+
 /*!
  * \brief Set the filename for writing instrumentation data.
  *
index 99b138b..8c32bde 100644 (file)
@@ -111,6 +111,15 @@ static uint32_t fileWriter(ProfDataWriter *This, ProfDataIOVec *IOVecs,
   return 0;
 }
 
+/* TODO: make buffer size controllable by an internal option, and compiler can pass the size
+   to runtime via a variable. */
+static uint32_t orderFileWriter(FILE *File, const uint32_t *DataStart) {
+  if (fwrite(DataStart, sizeof(uint32_t), INSTR_ORDER_FILE_BUFFER_SIZE, File) !=
+      INSTR_ORDER_FILE_BUFFER_SIZE)
+    return 1;
+  return 0;
+}
+
 static void initFileWriter(ProfDataWriter *This, FILE *File) {
   This->Write = fileWriter;
   This->WriterCtx = File;
@@ -260,6 +269,27 @@ static int writeFile(const char *OutputName) {
   return RetVal;
 }
 
+/* Write order data to file \c OutputName.  */
+static int writeOrderFile(const char *OutputName) {
+  int RetVal;
+  FILE *OutputFile;
+
+  OutputFile = fopen(OutputName, "w");
+
+  if (!OutputFile) {
+    PROF_WARN("can't open file with mode ab: %s\n", OutputName);
+    return -1;
+  }
+
+  FreeHook = &free;
+  setupIOBuffer();
+  const uint32_t *DataBegin = __llvm_profile_begin_orderfile();
+  RetVal = orderFileWriter(OutputFile, DataBegin);
+
+  fclose(OutputFile);
+  return RetVal;
+}
+
 static void truncateCurrentFile(void) {
   const char *Filename;
   char *FilenameBuf;
@@ -648,6 +678,62 @@ int __llvm_profile_dump(void) {
   return rc;
 }
 
+/* Order file data will be saved in a file with suffx .order. */
+static const char *OrderFileSuffix = ".order";
+
+COMPILER_RT_VISIBILITY
+int __llvm_orderfile_write_file(void) {
+  int rc, Length, LengthBeforeAppend, SuffixLength;
+  const char *Filename;
+  char *FilenameBuf;
+  int PDeathSig = 0;
+
+  SuffixLength = strlen(OrderFileSuffix);
+  Length = getCurFilenameLength() + SuffixLength;
+  FilenameBuf = (char *)COMPILER_RT_ALLOCA(Length + 1);
+  Filename = getCurFilename(FilenameBuf, 1);
+
+  /* Check the filename. */
+  if (!Filename) {
+    PROF_ERR("Failed to write file : %s\n", "Filename not set");
+    return -1;
+  }
+
+  /* Append order file suffix */
+  LengthBeforeAppend = strlen(Filename);
+  memcpy(FilenameBuf + LengthBeforeAppend, OrderFileSuffix, SuffixLength);
+  FilenameBuf[LengthBeforeAppend + SuffixLength] = '\0';
+
+  /* Check if there is llvm/runtime version mismatch.  */
+  if (GET_VERSION(__llvm_profile_get_version()) != INSTR_PROF_RAW_VERSION) {
+    PROF_ERR("Runtime and instrumentation version mismatch : "
+             "expected %d, but get %d\n",
+             INSTR_PROF_RAW_VERSION,
+             (int)GET_VERSION(__llvm_profile_get_version()));
+    return -1;
+  }
+
+  // Temporarily suspend getting SIGKILL when the parent exits.
+  PDeathSig = lprofSuspendSigKill();
+
+  /* Write order data to the file. */
+  rc = writeOrderFile(Filename);
+  if (rc)
+    PROF_ERR("Failed to write file \"%s\": %s\n", Filename, strerror(errno));
+
+  // Restore SIGKILL.
+  if (PDeathSig == 1)
+    lprofRestoreSigKill();
+
+  return rc;
+}
+
+COMPILER_RT_VISIBILITY
+int __llvm_orderfile_dump(void) {
+  int rc = __llvm_orderfile_write_file();
+  return rc;
+}
+
 static void writeFileWithoutReturn(void) { __llvm_profile_write_file(); }
 
 COMPILER_RT_VISIBILITY
index 6eae73f..23bdb7f 100644 (file)
@@ -27,6 +27,9 @@ extern uint64_t
 COMPILER_RT_VISIBILITY
 extern uint64_t
     CountersEnd __asm("section$end$__DATA$" INSTR_PROF_CNTS_SECT_NAME);
+COMPILER_RT_VISIBILITY
+extern uint32_t
+    OrderFileStart __asm("section$start$__DATA$" INSTR_PROF_ORDERFILE_SECT_NAME);
 
 COMPILER_RT_VISIBILITY
 extern ValueProfNode
@@ -49,6 +52,8 @@ COMPILER_RT_VISIBILITY
 uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart; }
 COMPILER_RT_VISIBILITY
 uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
+COMPILER_RT_VISIBILITY
+uint32_t *__llvm_profile_begin_orderfile(void) { return &OrderFileStart; }
 
 COMPILER_RT_VISIBILITY
 ValueProfNode *__llvm_profile_begin_vnodes(void) {
index 33a737e..becfe1f 100644 (file)
@@ -19,6 +19,7 @@
 #define PROF_NAME_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_NAME_COMMON)
 #define PROF_CNTS_START INSTR_PROF_SECT_START(INSTR_PROF_CNTS_COMMON)
 #define PROF_CNTS_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_CNTS_COMMON)
+#define PROF_ORDERFILE_START INSTR_PROF_SECT_START(INSTR_PROF_ORDERFILE_COMMON)
 #define PROF_VNODES_START INSTR_PROF_SECT_START(INSTR_PROF_VNODES_COMMON)
 #define PROF_VNODES_STOP INSTR_PROF_SECT_STOP(INSTR_PROF_VNODES_COMMON)
 
@@ -29,6 +30,7 @@ extern __llvm_profile_data PROF_DATA_START COMPILER_RT_VISIBILITY;
 extern __llvm_profile_data PROF_DATA_STOP COMPILER_RT_VISIBILITY;
 extern uint64_t PROF_CNTS_START COMPILER_RT_VISIBILITY;
 extern uint64_t PROF_CNTS_STOP COMPILER_RT_VISIBILITY;
+extern uint32_t PROF_ORDERFILE_START COMPILER_RT_VISIBILITY;
 extern char PROF_NAME_START COMPILER_RT_VISIBILITY;
 extern char PROF_NAME_STOP COMPILER_RT_VISIBILITY;
 extern ValueProfNode PROF_VNODES_START COMPILER_RT_VISIBILITY;
@@ -39,6 +41,8 @@ __llvm_profile_data
     __prof_data_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_DATA_SECT_NAME);
 uint64_t
     __prof_cnts_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_CNTS_SECT_NAME);
+uint32_t
+    __prof_orderfile_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_ORDERFILE_SECT_NAME);
 char __prof_nms_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_NAME_SECT_NAME);
 ValueProfNode __prof_vnodes_sect_data[0] COMPILER_RT_SECTION(INSTR_PROF_VNODES_SECT_NAME);
 
@@ -62,6 +66,9 @@ COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_begin_counters(void) {
 COMPILER_RT_VISIBILITY uint64_t *__llvm_profile_end_counters(void) {
   return &PROF_CNTS_STOP;
 }
+COMPILER_RT_VISIBILITY uint32_t *__llvm_profile_begin_orderfile(void) {
+  return &PROF_ORDERFILE_START;
+}
 
 COMPILER_RT_VISIBILITY ValueProfNode *
 __llvm_profile_begin_vnodes(void) {
index 6cb17aa..56c5d83 100644 (file)
@@ -21,6 +21,7 @@ static const char *NamesFirst = NULL;
 static const char *NamesLast = NULL;
 static uint64_t *CountersFirst = NULL;
 static uint64_t *CountersLast = NULL;
+static uint32_t *OrderFileFirst = NULL;
 
 static const void *getMinAddr(const void *A1, const void *A2) {
   return A1 < A2 ? A1 : A2;
@@ -82,6 +83,9 @@ COMPILER_RT_VISIBILITY
 uint64_t *__llvm_profile_begin_counters(void) { return CountersFirst; }
 COMPILER_RT_VISIBILITY
 uint64_t *__llvm_profile_end_counters(void) { return CountersLast; }
+/* TODO: correctly set up OrderFileFirst. */
+COMPILER_RT_VISIBILITY
+uint32_t *__llvm_profile_begin_orderfile(void) { return OrderFileFirst; }
 
 COMPILER_RT_VISIBILITY
 ValueProfNode *__llvm_profile_begin_vnodes(void) {
index 594e394..81b708b 100644 (file)
@@ -29,6 +29,7 @@
 #pragma section(".lprfd$Z", read, write)
 #pragma section(".lprfc$A", read, write)
 #pragma section(".lprfc$Z", read, write)
+#pragma section(".lorderfile$A", read, write)
 #pragma section(".lprfnd$A", read, write)
 #pragma section(".lprfnd$Z", read, write)
 #endif
@@ -41,6 +42,7 @@ const char COMPILER_RT_SECTION(".lprfn$Z") NamesEnd = '\0';
 
 uint64_t COMPILER_RT_SECTION(".lprfc$A") CountersStart;
 uint64_t COMPILER_RT_SECTION(".lprfc$Z") CountersEnd;
+uint32_t COMPILER_RT_SECTION(".lorderfile$A") OrderFileStart;
 
 ValueProfNode COMPILER_RT_SECTION(".lprfnd$A") VNodesStart;
 ValueProfNode COMPILER_RT_SECTION(".lprfnd$Z") VNodesEnd;
@@ -55,6 +57,7 @@ const char *__llvm_profile_end_names(void) { return &NamesEnd; }
 
 uint64_t *__llvm_profile_begin_counters(void) { return &CountersStart + 1; }
 uint64_t *__llvm_profile_end_counters(void) { return &CountersEnd; }
+uint32_t *__llvm_profile_begin_orderfile(void) { return &OrderFileStart; }
 
 ValueProfNode *__llvm_profile_begin_vnodes(void) { return &VNodesStart + 1; }
 ValueProfNode *__llvm_profile_end_vnodes(void) { return &VNodesEnd; }
diff --git a/compiler-rt/test/profile/Inputs/instrprof-order-file-2.c b/compiler-rt/test/profile/Inputs/instrprof-order-file-2.c
new file mode 100644 (file)
index 0000000..ee44857
--- /dev/null
@@ -0,0 +1,7 @@
+__attribute__((noinline)) int f(int a) {
+  return a + 1;
+}
+
+__attribute__((noinline)) int g(int a) {
+  return a + 2;
+}
diff --git a/compiler-rt/test/profile/Inputs/instrprof-order-file.c b/compiler-rt/test/profile/Inputs/instrprof-order-file.c
new file mode 100644 (file)
index 0000000..9251a8e
--- /dev/null
@@ -0,0 +1,17 @@
+void __llvm_profile_initialize_file(void);
+int __llvm_orderfile_dump(void);
+
+__attribute__((noinline)) int f(int a);
+
+__attribute__((noinline)) int g(int a);
+
+int main(int argc, const char *argv[]) {
+  int a = f(argc);
+  int t = 0;
+  for (int i = 0; i < argc; i++)
+    t += g(a);
+  f(t);
+  __llvm_profile_initialize_file();
+  __llvm_orderfile_dump();
+  return 0;
+}
diff --git a/compiler-rt/test/profile/instrprof-order-file.test b/compiler-rt/test/profile/instrprof-order-file.test
new file mode 100644 (file)
index 0000000..09e77d7
--- /dev/null
@@ -0,0 +1,17 @@
+// UNSUPPORTED: windows
+// REQUIRES: darwin
+// RUN: rm -rf %t.dir && mkdir -p %t.dir
+// RUN: cd %t.dir
+//
+// RUN: %clang -forder-file-instrumentation -O1 -o %t.2 %S/Inputs/instrprof-order-file-2.c %S/Inputs/instrprof-order-file.c -mllvm -orderfile-write-mapping="mapping.txt"
+// RUN: %run %t.2 ANY
+// RUN: od -h default.profraw.order | FileCheck %s
+// RUN: cat mapping.txt | FileCheck %s --check-prefix=MAPPING
+
+// Make sure we have MD5 for main, then f, then g.
+// CHECK: 0000000      d5fa    e78d    6436    db95    a18f    dd4c    4f75    cc91
+// CHECK: 0000020      f5b2    47ff    6643    b671    0000    0000    0000    0000
+
+// MAPPING: MD5 cc914f75dd4ca18f f
+// MAPPING: MD5 b671664347fff5b2 g
+// MAPPING: MD5 db956436e78dd5fa main