[Beignet] [PATCH 16/18] Backend: Refine llvm_profiling pass.

junyan.he at inbox.com junyan.he at inbox.com
Thu Dec 24 03:02:08 PST 2015


From: Junyan He <junyan.he at linux.intel.com>

We now can insert profiling point based on the line number.

Signed-off-by: Junyan He <junyan.he at linux.intel.com>
---
 backend/src/llvm/llvm_profiling.cpp | 204 +++++++++++++++++++++++++++++-------
 1 file changed, 166 insertions(+), 38 deletions(-)

diff --git a/backend/src/llvm/llvm_profiling.cpp b/backend/src/llvm/llvm_profiling.cpp
index 7c672e8..914b4a7 100644
--- a/backend/src/llvm/llvm_profiling.cpp
+++ b/backend/src/llvm/llvm_profiling.cpp
@@ -63,19 +63,87 @@
 #include "llvm/llvm_gen_backend.hpp"
 #include "sys/map.hpp"
 #include "ir/unit.hpp"
+#include "ir/profiling.hpp"
+#include "sys/cvar.hpp"
 
 #include <iostream>
 #include <vector>
-
+#include <sstream>
+#include <stdlib.h>
 
 using namespace llvm;
 using std::vector;
 
-
 namespace gbe
 {
   using namespace ir;
 
+  SVAR(OCL_PROFILING_LINES, "");
+
+  inline bool line_cmp(const std::pair<uint32_t, bool>& l0, const std::pair<uint32_t, bool>& l1)
+  {
+    return l0.first < l1.first;
+  }
+
+  static void parseProfilingLines(std::vector<std::pair<uint32_t, bool> >& profLines,
+                                  std::string& profKernel, uint32_t& profilingType)
+  {
+    profKernel = "";
+    profilingType = ProfilingInfo::ProfilingNone;
+
+    if (OCL_PROFILING_LINES == "")
+      return;
+
+    char* profstr = (char *)malloc(OCL_PROFILING_LINES.size() + 1);
+    strcpy(profstr, OCL_PROFILING_LINES.c_str());
+    std::string str;
+
+    char* kernel_name = strtok(profstr, ":");
+    if (!kernel_name) {
+      printf("Wrong profiling format, should be KERNEL_NAME:PROFILING_MODE:"
+             "LINE_NUMBER0,LINE_NUMBER1,LINE_NUMBER2,...");
+      GBE_ASSERT(0);
+    }
+    char* prof_mode = strtok(NULL,":");
+    if (!prof_mode) {
+      printf("Wrong profiling format, should be KERNEL_NAME:PROFILING_MODE:"
+             "LINE_NUMBER0,LINE_NUMBER1,LINE_NUMBER2,...");
+      GBE_ASSERT(0);
+    }
+    char* lines = strtok(NULL,":");
+    if (!lines) {
+      printf("Wrong profiling format, should be KERNEL_NAME:PROFILING_MODE:"
+             "LINE_NUMBER0,LINE_NUMBER1,LINE_NUMBER2,...");
+      GBE_ASSERT(0);
+    }
+
+    profKernel = kernel_name;
+    uint32_t mode = std::atoi(prof_mode);
+    if (mode <= ProfilingInfo::ProfilingVerbose)
+      profilingType = mode;
+
+    if (profilingType == ProfilingInfo::ProfilingNone) {
+      printf("Wrong profiling format, should be KERNEL_NAME:PROFILING_MODE:"
+             "LINE_NUMBER0,LINE_NUMBER1,LINE_NUMBER2,...");
+      GBE_ASSERT(0);
+    }
+
+    std::istringstream lineStream(lines);
+    while (std::getline(lineStream, str, ',')) {
+      uint32_t line = std::atoi(str.c_str());
+      profLines.push_back(std::pair<uint32_t, bool>(line, false));
+    }
+    std::sort(profLines.begin(), profLines.end(), line_cmp);
+
+    printf("Prof kernels is %s, \tin mode %d, \tprofiling points are: ", profKernel.c_str(), profilingType);
+    for (auto & l : profLines) {
+      printf("%d ", l.first);
+    }
+    printf("\n");
+    free(profstr);
+  }
+
+
   class ProfilingInserter : public FunctionPass
   {
   public:
@@ -90,11 +158,13 @@ namespace gbe
     ir::Unit &unit;
     const char* source;
 
-    ProfilingInserter(ir::Unit &u, const char* s) : FunctionPass(ID), unit(u), source(s) {
+    ProfilingInserter(ir::Unit &u, const char* s) : FunctionPass(ID), unit(u), source(s)
+    {
       module = NULL;
       builder = NULL;
       intTy = NULL;
       ptrTy = NULL;
+      parseProfilingLines(profLines, profKernel, profilingType);
     }
 
     ~ProfilingInserter(void)
@@ -112,7 +182,6 @@ namespace gbe
   bool ProfilingInserter::runOnFunction(llvm::Function &F)
   {
     bool changed = false;
-    int pointNum = 0;
 
     switch (F.getCallingConv()) {
 #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR <= 2
@@ -131,7 +200,14 @@ namespace gbe
 
     // As we inline all function calls, so skip non-kernel functions
     bool bKernel = isKernelFunction(F);
-    if (!bKernel) return changed;
+    if (F.getName() != profKernel)
+      return changed;
+    if (!bKernel)
+      return changed;
+
+    if (profLines.size() == 0)
+      return changed;
+
 
     module = F.getParent();
     intTy = IntegerType::get(module->getContext(), 32);
@@ -143,52 +219,96 @@ namespace gbe
     llvm::Constant *profilingBuf = module->getGlobalVariable("__gen_ocl_profiling_buf");
     if (!profilingBuf) {
       profilingBuf = new GlobalVariable(*module, intTy, false,
-          GlobalVariable::ExternalLinkage, nullptr, StringRef("__gen_ocl_profiling_buf"),
-          nullptr, GlobalVariable::NotThreadLocal, 1);
+                                        GlobalVariable::ExternalLinkage, nullptr, StringRef("__gen_ocl_profiling_buf"),
+                                        nullptr, GlobalVariable::NotThreadLocal, 1);
     }
 
-    changed = true;
-
+    /* Some line of source code like:
+       int i = 0x20;
+       Compiler may just record the imm value of var i if it is not used as a dst.
+       Such code line does not have a llvm::Instruction, and so we need to set the
+       profiling point to the next lines. We need to build up a line-instruction map
+       to find the suitable profiling point. */
+    std::map<uint32_t, llvm::Instruction*> lineInstMap;
     for (llvm::Function::iterator B = F.begin(), BE = F.end(); B != BE; B++) {
       /* Skip the empty blocks. */
       if (B->empty())
         continue;
 
+      uint32_t line;
+
       BasicBlock::iterator instI = B->begin();
       for ( ; instI != B->end(); instI++) {
-        if (dyn_cast<llvm::PHINode>(instI))
+        if (dyn_cast<llvm::PHINode>(instI)) // not insert before PHI.
           continue;
-        if (dyn_cast<llvm::ReturnInst>(instI)) {
-          instI++;
-          GBE_ASSERT(instI == B->end());
-          break;
-        }
-        if (dyn_cast<llvm::BranchInst>(instI)) {
-          instI++;
-          GBE_ASSERT(instI == B->end());
-          break;
+
+        DebugLoc dbgLoc = instI->getDebugLoc();
+        line = dbgLoc.getLine();
+        if (line == 0) // Some instruction inserted.
+          continue;
+
+        if (lineInstMap.find(line) == lineInstMap.end()) {
+          lineInstMap.insert(std::pair<uint32_t, llvm::Instruction*>(line, instI));
         }
-        break;
       }
+    }
 
-      if (instI == B->end())
-        continue;
+    if (lineInstMap.size() == 0) {// Nothing to insert.
+      delete builder;
+      return changed;
+    }
+
+    uint32_t inserted = 0;
+    std::map<uint32_t, uint32_t> profPoints;
+
+    std::vector<std::pair<uint32_t, llvm::Instruction*> > lineInstVect;
+    for (auto& e : lineInstMap) {
+      lineInstVect.push_back(e);
+    }
+    std::sort(lineInstVect.begin(), lineInstVect.end(), line_cmp);
 
-      if (pointNum >= 20) // To many timestamp.
+    for (auto& l : profLines) {
+      if (inserted >= ProfilingInfo::MaxTimestampProfilingPoints)
+        break;
+
+      if (l.first < lineInstVect.begin()->first || l.first > lineInstVect.rbegin()->first) {
+        // Not belong to this kernel.
         continue;
+      }
+
+      l.second = true;
+      std::vector<std::pair<uint32_t, llvm::Instruction*> >::iterator instPoint;
+      instPoint = std::lower_bound(lineInstVect.begin(), lineInstVect.end(), l, line_cmp);
 
-      // Insert the first one at beginning of not PHI.
-      builder->SetInsertPoint(instI);
+      builder->SetInsertPoint(instPoint->second);
       /* Add the timestamp store function call. */
       // __gen_ocl_store_timestamp(int nth, int type);
-      Value *Args[2] = {ConstantInt::get(intTy, pointNum++), ConstantInt::get(intTy, profilingType)};
-      builder->CreateCall(cast<llvm::Function>(module->getOrInsertFunction(
-              "__gen_ocl_calc_timestamp", Type::getVoidTy(module->getContext()),
-              IntegerType::getInt32Ty(module->getContext()),
-              IntegerType::getInt32Ty(module->getContext()),
-              NULL)),
-              ArrayRef<Value*>(Args));
+      Value *Args[2] = { ConstantInt::get(intTy, inserted), ConstantInt::get(intTy, profilingType) };
+      CallInst* callTS = builder->CreateCall(cast<llvm::Function>(module->getOrInsertFunction(
+          "__gen_ocl_calc_timestamp", Type::getVoidTy(module->getContext()),
+          IntegerType::getInt32Ty(module->getContext()),
+          IntegerType::getInt32Ty(module->getContext()),
+          NULL)),
+                                             ArrayRef<Value*>(Args));
+      callTS->setDebugLoc(DebugLoc());
+
+      profPoints.insert(std::pair<uint32_t, uint32_t>(inserted, l.first));
+      inserted++;
+      changed = true;
+    }
+
+    if (inserted == 0) { // Nothing to insert.
+      delete builder;
+      return changed;
     }
+
+    for (auto& l : profLines) {
+      if (l.second == false) {
+        printf("Warning: for kernel %s,\tprofiling point for line %d is not applied.\n",
+               std::string(F.getName()).c_str(), l.first);
+      }
+    }
+
     /* We insert one store_profiling at the end of the last block to hold the place. */
     llvm::Function::iterator BE = F.end();
     BE--;
@@ -197,12 +317,20 @@ namespace gbe
     builder->SetInsertPoint(retInst);
     Value *Args2[2] = {profilingBuf, ConstantInt::get(intTy, profilingType)};
 
-    builder->CreateCall(cast<llvm::Function>(module->getOrInsertFunction(
-            "__gen_ocl_store_profiling", Type::getVoidTy(module->getContext()),
-            ptrTy,
-            IntegerType::getInt32Ty(module->getContext()),
-            NULL)),
-            ArrayRef<Value*>(Args2));
+    CallInst* callStorePF = builder->CreateCall(cast<llvm::Function>(module->getOrInsertFunction(
+                              "__gen_ocl_store_profiling", Type::getVoidTy(module->getContext()),
+                              ptrTy,
+                              IntegerType::getInt32Ty(module->getContext()),
+                              NULL)),
+                            ArrayRef<Value*>(Args2));
+    callStorePF->setDebugLoc(DebugLoc());
+
+
+    ProfilingInfo profInfo;
+    profInfo.setprofPoints(profPoints);
+    profInfo.setProfilingType(profilingType);
+    profInfo.setSource(source);
+    unit.setProfilingInfoForKernel(profKernel, profInfo);
 
     delete builder;
     return changed;
-- 
1.9.1





More information about the Beignet mailing list