WIP - building call tree.

This commit is contained in:
Félix Baylac-Jacqué 2019-10-24 10:54:45 +02:00
parent fa6586e2bb
commit f3b71acc0b
3 changed files with 183 additions and 56 deletions

View File

@ -11,12 +11,13 @@
#include <algorithm>
#include <chrono>
#include <cstring>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <iostream>
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/resource.h>
@ -966,10 +967,9 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
std::ostringstream ossName;
ossName << *this;
string name = ossName.str();
ProfilerCallLevel lvl {&(this->pos), name, ProfilerCallLevel::var};
state.profState.jumpInValue(lvl);
state.profState.jumpInValue(&(this->pos), name, ProfilerCallType::var);
state.forceValue(*v2, pos);
state.profState.createCallgraphentry(lvl);
state.profState.jumpOutValue();
}
v = *v2;
}
@ -1032,10 +1032,10 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
std::ostringstream ossName;
ossName << *this;
string name = ossName.str();
ProfilerCallLevel lvl {pos2 != NULL ? pos2 : &(this->pos), name, ProfilerCallLevel::select};
state.profState.jumpInValue(lvl);
state.forceValue(*vAttrs, ( pos2 != NULL ? *pos2 : this->pos ) );
state.profState.createCallgraphentry(lvl);
Pos* fpos = pos2 != NULL ? pos2 : &(this->pos);
state.profState.jumpInValue(fpos, name, ProfilerCallType::select);
state.forceValue(*vAttrs, *fpos);
state.profState.jumpOutValue();
}
} catch (Error & e) {
@ -1809,6 +1809,8 @@ void EvalState::printStats()
uint64_t bLists = nrListElems * sizeof(Value *);
uint64_t bValues = nrValues * sizeof(Value);
uint64_t bAttrsets = nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr);
if(settings.profileEvaluation)
profState.printCallGraph();
#if HAVE_BOEHMGC
GC_word heapSize, totalBytes;
@ -2035,16 +2037,19 @@ static GlobalConfig::Register r1(&evalSettings);
*/
ProfilerState::ProfilerState():
nestedLevel(0)
{}
profilerTreeRoot(std::nullopt),
lastProfilerCall(std::nullopt)
{
}
CompressedFileId ProfilerState::registerFile(FileName& fName) {
CompressedFileId fid;
auto it = fileMap.find(fName);
if(it == fileMap.end()) {
fid = currentFuncId;
fileMap.insert({fName,currentFuncId});
currentFuncId++;
fid = currentFileId;
fileMap.insert({fName,currentCostCenterId});
currentFileId++;
}
else {
fid = it->second;
@ -2052,13 +2057,13 @@ CompressedFileId ProfilerState::registerFile(FileName& fName) {
return fid;
}
CompressedFuncId ProfilerState::registerFunction(CostCenterName& fName) {
CompressedFuncId fid;
CompressedCostCenterId ProfilerState::registerCostCenter(CostCenterName& fName) {
CompressedCostCenterId fid;
auto it = costMap.find(fName);
if(it == costMap.end()) {
fid = currentFuncId;
costMap.insert({fName,currentFuncId});
currentFuncId++;
fid = currentCostCenterId;
costMap.insert({fName,currentCostCenterId});
currentCostCenterId++;
}
else {
fid = it->second;
@ -2066,36 +2071,139 @@ CompressedFuncId ProfilerState::registerFunction(CostCenterName& fName) {
return fid;
}
void ProfilerState::jumpInValue(ProfilerCallLevel& call) {
void ProfilerState::jumpInValue(Pos* pos, CostCenterName name, ProfilerCallType type) {
std::shared_ptr<ProfilerCallLevel> call =
std::make_shared<ProfilerCallLevel>
(ProfilerCallLevel{
lastProfilerCall,
std::forward_list<ProfilerCallLevel*>(),
pos, name, type, false});
string delim="";
string opStr="";
std::ostringstream srcPos;
if (lastProfilerCall) {
lastProfilerCall->children.push_front(call);
} else {
std::cout << "Redifining tree root " << std::endl;
profilerTreeRoot = call;
}
callGraphStack.push(call);
lastProfilerCall = call;
// Printing stuff
int stackSize = callGraphStack.size();
for(int i=0;i<stackSize;i++) {
delim+="=";
}
switch (call.callType) {
case ProfilerCallLevel::select:
switch (type) {
case ProfilerCallType::select:
opStr="select";
break;
case ProfilerCallLevel::var:
case ProfilerCallType::var:
opStr="var";
break;
}
if(call.pos->file.set()) {
if(pos->file.set()) {
std::ostringstream ossFi;
ossFi << call.pos->file;
ossFi << pos->file;
string fileName = ossFi.str();
srcPos << fileName << " " << call.pos->line << ":" << call.pos->column;
srcPos << fileName << " " << pos->line << ":" << pos->column;
} else {
srcPos << "NOT DEFINED";
}
std::cout << delim << " " << opStr << "::" << call.name << " " << srcPos.str() << std::endl;
//std::cout << delim << " " << opStr << "::" << name << " " << srcPos.str() << std::endl;
}
void ProfilerState::createCallgraphentry(ProfilerCallLevel& call) {
void ProfilerState::jumpOutValue() {
if (!callGraphStack.empty())
lastProfilerCall = callGraphStack.top().get().parent.get();
else {
std::cout << "jumpOutValue, CONDITION CHELOUE" << std::endl;
}
callGraphStack.pop();
}
void ProfilerState::printCallGraph() {
std::stack<ProfilerCallLevel*> nodesToProcess;
std::ostringstream ossFi;
LineNumber line;
nodesToProcess.push(profilerTreeRoot);
while(!nodesToProcess.empty()) {
// %%%%%%%%%%%%%%%%%%%%%%%%%
// Get Node struct
// %%%%%%%%%%%%%%%%%%%%%%%%%
auto currentNode = nodesToProcess.top();
if (!currentNode->visited) {
nodesToProcess.pop();
currentNode->visited = true;
std::cout << "Current stack size: " << nodesToProcess.size() << std::endl;
string fileName;
if(currentNode->pos->file.set()) {
ossFi << currentNode->pos->file;
fileName = ossFi.str();
} else {
fileName = "NOT DEFINED";
}
FileName fname = fileName;
CostCenterName ccname = currentNode->name;
line = currentNode->pos->line;
PosCost entryPos = {line, 666};
CallGraphCostEntry costEntry = { fname, ccname, std::forward_list<CallGraphCall>(), entryPos };
auto children = currentNode->children;
// %%%%%%%%%%%%%%%%%%%%%%%%%
// Create Children Structs
// %%%%%%%%%%%%%%%%%%%%%%%%%
PosCost posCost;
CallGraphCall call;
for (auto it = children.begin(); it != children.end(); it++) {
nodesToProcess.push(*it);
if((*it)->pos->file.set()) {
ossFi << (*it)->pos->file;
fileName = ossFi.str();
} else {
fileName = "NOT DEFINED";
}
line = (*it)->pos->line;
posCost = { line, 666 };
/* fid = registerFile(fileName);
ccid = registerCostCenter(currentNode->name); */
call = { fileName, (*it)->name, posCost };
costEntry.calls.push_front(call);
}
costEntries.push_front(costEntry);
}
}
renderCostEntries(costEntries);
}
void ProfilerState::renderCostEntries(std::forward_list<CallGraphCostEntry> costEntries){
for (auto i = costEntries.begin(); i != costEntries.end(); i++) {
std::cout << "fl=" << i->fileName << std::endl;
std::cout << "fn=" << i->costCenter << std::endl;
std::cout << i->pos.line << " " << i->pos.cost << std::endl;
auto calls = i->calls;
for (auto j = calls.begin(); j != calls.end(); j++) {
std::cout << "cfi=" << j->fileName << std::endl;
std::cout << "cfn=" << j->costCenter << std::endl;
std::cout << "calls=" << "1 " << j->pos.cost << std::endl;
std::cout << "1 " << i->pos.line << std::endl;
}
std::cout << std::endl;
}
/*fl=(1) file1.c
fn=(1) main
16 20
cfn=(2) func1
calls=1 50
16 400
cfi=(2) file2.c
cfn=(3) func2
calls=3 20
16 400*/
}
}

View File

@ -8,9 +8,12 @@
#include "config.hh"
#include "function-trace.hh"
#include <forward_list>
#include <map>
#include <unordered_map>
#include <optional>
#include <optional>
#include <stack>
#include <unordered_map>
namespace nix {
@ -25,34 +28,43 @@ enum RepairFlag : bool;
typedef string CostCenterName;
typedef string FileName;
typedef int CompressedFuncId;
typedef int CompressedCostCenterId;
typedef int CompressedFileId;
typedef int LineNumber;
typedef int BullshitCost;
struct ProfFuncOcc {
CompressedFuncId funcId;
CompressedFileId fileId;
struct PosCost {
LineNumber line;
BullshitCost cost;
};
struct ProfFuncCall {
CompressedFuncId calledFunc;
CompressedFileId calledFile;
LineNumber calledFuncLineNb;
int cost;
struct CallCost {
LineNumber line;
int nbCalls;
};
struct ProfCostOcc {
CompressedFuncId funcId;
CompressedFileId fileId;
ProfFuncOcc funcOcc;
int selfCost;
struct CallGraphCall {
FileName fileName;
CostCenterName costCenter;
PosCost pos;
};
struct CallGraphCostEntry {
FileName fileName;
CostCenterName costCenter;
std::forward_list<CallGraphCall> calls;
PosCost pos;
};
enum ProfilerCallType { select=0, var};
struct ProfilerCallLevel {
std::shared_ptr<ProfilerCallLevel> parent;
std::forward_list<std::shared_ptr<ProfilerCallLevel>> children;
Pos* pos;
CostCenterName name;
enum { select=0, var} callType;
ProfilerCallType type;
bool visited;
};
class ProfilerState {
@ -60,21 +72,23 @@ class ProfilerState {
public:
ProfilerState();
CompressedFileId registerFile(FileName& fName);
CompressedFuncId registerFunction(CostCenterName& fName);
ProfCostOcc& getFuncOcc(FileName& fName, CostCenterName& fnName);
void saveCost(ProfCostOcc& occCost);
void jumpInValue(ProfilerCallLevel& call);
void createCallgraphentry(ProfilerCallLevel& call);
int nestedLevel;
CompressedCostCenterId registerCostCenter(CostCenterName& fName);
void jumpInValue(Pos* pos, CostCenterName name, ProfilerCallType type);
void jumpOutValue();
void printCallGraph();
private:
/* We index every func and file to leverage Callgrind's string compression.
See section "3.1.6.<EFBFBD>Subposition Compression" section from [callgrindSpec]. */
std::map<CostCenterName,CompressedFuncId> costMap;
See section "3.1.6.Subposition Compression" section from [callgrindSpec]. */
std::map<CostCenterName,CompressedCostCenterId> costMap;
std::map<FileName,CompressedFileId> fileMap;
CompressedFuncId currentFuncId;
CompressedCostCenterId currentCostCenterId;
CompressedFileId currentFileId;
std::stack<ProfilerCallLevel> callGraphStack;
std::stack<std::shared_ptr<ProfilerCallLevel>> callGraphStack;
std::optional<std::shared_ptr<ProfilerCallLevel>> lastProfilerCall;
std::optional<std::shared_ptr<ProfilerCallLevel>> profilerTreeRoot;
std::forward_list<CallGraphCostEntry> costEntries;
void renderCostEntries(std::forward_list<CallGraphCostEntry> costEntries);
};

View File

@ -54,6 +54,11 @@ public:
}
friend std::ostream & operator << (std::ostream & str, const Symbol & sym);
string str() const
{
return *s;
}
};
class SymbolTable