r200874 - PGO: instrumentation based profiling sets function attributes.

Manman Ren manman.ren at gmail.com
Wed Feb 5 12:40:15 PST 2014


Author: mren
Date: Wed Feb  5 14:40:15 2014
New Revision: 200874

URL: http://llvm.org/viewvc/llvm-project?rev=200874&view=rev
Log:
PGO: instrumentation based profiling sets function attributes.

We collect a maximal function count among all functions in the pgo data file.
For functions that are hot, we set its InlineHint attribute. For functions that
are cold, we set its Cold attribute.

We currently treat functions with >= 30% of the maximal function count as hot
and functions with <= 1% of the maximal function count are treated as cold.
These two numbers are from preliminary tuning on SPEC.

This commit should not affect non-PGO builds and should boost performance on
instrumentation based PGO.

Added:
    cfe/trunk/test/CodeGen/Inputs/instr-attribute.pgodata
    cfe/trunk/test/CodeGen/instr-attribute.c
Modified:
    cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
    cfe/trunk/lib/CodeGen/CodeGenPGO.cpp
    cfe/trunk/lib/CodeGen/CodeGenPGO.h

Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=200874&r1=200873&r2=200874&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Wed Feb  5 14:40:15 2014
@@ -591,6 +591,16 @@ void CodeGenFunction::StartFunction(Glob
     EmitMCountInstrumentation();
 
   PGO.assignRegionCounters(GD);
+  if (CGM.getPGOData()) {
+    if (const Decl *D = GD.getDecl()) {
+      // Turn on InlineHint attribute for hot functions.
+      if (CGM.getPGOData()->isHotFunction(CGM.getMangledName(GD)))
+        Fn->addFnAttr(llvm::Attribute::InlineHint);
+      // Turn on Cold attribute for cold functions.
+      else if (CGM.getPGOData()->isColdFunction(CGM.getMangledName(GD)))
+        Fn->addFnAttr(llvm::Attribute::Cold);
+    }
+  }
 
   if (RetTy->isVoidType()) {
     // Void type; nothing to return.

Modified: cfe/trunk/lib/CodeGen/CodeGenPGO.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenPGO.cpp?rev=200874&r1=200873&r2=200874&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenPGO.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenPGO.cpp Wed Feb  5 14:40:15 2014
@@ -45,6 +45,7 @@ PGOProfileData::PGOProfileData(CodeGenMo
   const char *BufferStart = DataBuffer->getBufferStart();
   const char *BufferEnd = DataBuffer->getBufferEnd();
   const char *CurPtr = BufferStart;
+  uint64_t MaxCount = 0;
   while (CurPtr < BufferEnd) {
     // Read the mangled function name.
     const char *FuncName = CurPtr;
@@ -65,8 +66,19 @@ PGOProfileData::PGOProfileData(CodeGenMo
     }
     CurPtr = EndPtr;
 
+    // Read function count.
+    uint64_t Count = strtoll(CurPtr, &EndPtr, 10);
+    if (EndPtr == CurPtr || *EndPtr != '\n') {
+      ReportBadPGOData(CGM, "pgo-data file has bad count value");
+      return;
+    }
+    CurPtr = EndPtr + 1;
+    FunctionCounts[MangledName] = Count;
+    MaxCount = Count > MaxCount ? Count : MaxCount;
+
     // There is one line for each counter; skip over those lines.
-    for (unsigned N = 0; N < NumCounters; ++N) {
+    // Since function count is already read, we start the loop from 1.
+    for (unsigned N = 1; N < NumCounters; ++N) {
       CurPtr = strchr(++CurPtr, '\n');
       if (!CurPtr) {
         ReportBadPGOData(CGM, "pgo data file is missing some counter info");
@@ -79,6 +91,33 @@ PGOProfileData::PGOProfileData(CodeGenMo
 
     DataOffsets[MangledName] = FuncName - BufferStart;
   }
+  MaxFunctionCount = MaxCount;
+}
+
+/// Return true if a function is hot. If we know nothing about the function,
+/// return false.
+bool PGOProfileData::isHotFunction(StringRef MangledName) {
+  llvm::StringMap<uint64_t>::const_iterator CountIter =
+    FunctionCounts.find(MangledName);
+  // If we know nothing about the function, return false.
+  if (CountIter == FunctionCounts.end())
+    return false;
+  // FIXME: functions with >= 30% of the maximal function count are
+  // treated as hot. This number is from preliminary tuning on SPEC.
+  return CountIter->getValue() >= (uint64_t)(0.3 * (double)MaxFunctionCount);
+}
+
+/// Return true if a function is cold. If we know nothing about the function,
+/// return false.
+bool PGOProfileData::isColdFunction(StringRef MangledName) {
+  llvm::StringMap<uint64_t>::const_iterator CountIter =
+    FunctionCounts.find(MangledName);
+  // If we know nothing about the function, return false.
+  if (CountIter == FunctionCounts.end())
+    return false;
+  // FIXME: functions with <= 1% of the maximal function count are treated as
+  // cold. This number is from preliminary tuning on SPEC.
+  return CountIter->getValue() <= (uint64_t)(0.01 * (double)MaxFunctionCount);
 }
 
 bool PGOProfileData::getFunctionCounts(StringRef MangledName,

Modified: cfe/trunk/lib/CodeGen/CodeGenPGO.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenPGO.h?rev=200874&r1=200873&r2=200874&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenPGO.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenPGO.h Wed Feb  5 14:40:15 2014
@@ -33,12 +33,22 @@ private:
   llvm::OwningPtr<llvm::MemoryBuffer> DataBuffer;
   /// Offsets into DataBuffer for each function's counters
   llvm::StringMap<unsigned> DataOffsets;
+  /// Execution counts for each function.
+  llvm::StringMap<uint64_t> FunctionCounts;
+  /// The maximal execution count among all functions.
+  uint64_t MaxFunctionCount;
   CodeGenModule &CGM;
 public:
   PGOProfileData(CodeGenModule &CGM, std::string Path);
   /// Fill Counts with the profile data for the given function name. Returns
   /// false on success.
   bool getFunctionCounts(StringRef MangledName, std::vector<uint64_t> &Counts);
+  /// Return true if a function is hot. If we know nothing about the function,
+  /// return false.
+  bool isHotFunction(StringRef MangledName);
+  /// Return true if a function is cold. If we know nothing about the function,
+  /// return false.
+  bool isColdFunction(StringRef MangledName);
 };
 
 /// Per-function PGO state. This class should generally not be used directly,

Added: cfe/trunk/test/CodeGen/Inputs/instr-attribute.pgodata
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/Inputs/instr-attribute.pgodata?rev=200874&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/Inputs/instr-attribute.pgodata (added)
+++ cfe/trunk/test/CodeGen/Inputs/instr-attribute.pgodata Wed Feb  5 14:40:15 2014
@@ -0,0 +1,39 @@
+hot_100_percent 4
+100000
+4999950000
+0
+0
+
+hot_40_percent 4
+40000
+799980000
+0
+0
+
+normal_func 4
+20000
+199990000
+0
+0
+
+cold_func 4
+500
+124750
+0
+0
+
+main 13
+1
+100000
+0
+0
+40000
+0
+0
+20000
+0
+0
+500
+0
+0
+

Added: cfe/trunk/test/CodeGen/instr-attribute.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/instr-attribute.c?rev=200874&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/instr-attribute.c (added)
+++ cfe/trunk/test/CodeGen/instr-attribute.c Wed Feb  5 14:40:15 2014
@@ -0,0 +1,47 @@
+// Test that instrumentation based profiling sets function attributes correctly.
+
+// RUN: %clang %s -o - -mllvm -disable-llvm-optzns -emit-llvm -S -fprofile-instr-use=%S/Inputs/instr-attribute.pgodata | FileCheck %s
+
+extern int atoi(const char *);
+
+// CHECK: hot_100_percent(i32 %i) [[HOT:#[0-9]+]]
+void hot_100_percent(int i) {
+  while (i > 0)
+    i--;
+}
+
+// CHECK: hot_40_percent(i32 %i) [[HOT]]
+void hot_40_percent(int i) {
+  while (i > 0)
+    i--;
+}
+
+// CHECK: normal_func(i32 %i) [[NORMAL:#[0-9]+]]
+void normal_func(int i) {
+  while (i > 0)
+    i--;
+}
+
+// CHECK: cold_func(i32 %i) [[COLD:#[0-9]+]]
+void cold_func(int i) {
+  while (i > 0)
+    i--;
+}
+
+// CHECK: attributes [[HOT]] = { inlinehint nounwind {{.*}} }
+// CHECK: attributes [[NORMAL]] = { nounwind {{.*}} }
+// CHECK: attributes [[COLD]] = { cold nounwind {{.*}} }
+
+int main(int argc, const char *argv[]) {
+  int max = atoi(argv[1]);
+  int i;
+  for (i = 0; i < max; i++)
+    hot_100_percent(i);
+  for (i = 0; i < max * 4 / 10; i++)
+    hot_40_percent(i);
+  for (i = 0; i < max * 2 / 10; i++)
+    normal_func(i);
+  for (i = 0; i < max / 200; i++)
+    cold_func(i);
+  return 0;
+}





More information about the cfe-commits mailing list