[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