Compare commits

...

1 Commits

Author SHA1 Message Date
Félix Baylac-Jacqué f3b71acc0b WIP - building call tree. 2019-11-05 08:04:41 +01:00
3 changed files with 183 additions and 56 deletions

View File

@ -11,12 +11,13 @@
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <cstring> #include <cstring>
#include <unistd.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <iostream>
#include <fstream> #include <fstream>
#include <iostream>
#include <memory>
#include <sstream> #include <sstream>
#include <sys/resource.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/resource.h> #include <sys/resource.h>
@ -966,10 +967,9 @@ void ExprVar::eval(EvalState & state, Env & env, Value & v)
std::ostringstream ossName; std::ostringstream ossName;
ossName << *this; ossName << *this;
string name = ossName.str(); string name = ossName.str();
ProfilerCallLevel lvl {&(this->pos), name, ProfilerCallLevel::var}; state.profState.jumpInValue(&(this->pos), name, ProfilerCallType::var);
state.profState.jumpInValue(lvl);
state.forceValue(*v2, pos); state.forceValue(*v2, pos);
state.profState.createCallgraphentry(lvl); state.profState.jumpOutValue();
} }
v = *v2; v = *v2;
} }
@ -1032,10 +1032,10 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
std::ostringstream ossName; std::ostringstream ossName;
ossName << *this; ossName << *this;
string name = ossName.str(); string name = ossName.str();
ProfilerCallLevel lvl {pos2 != NULL ? pos2 : &(this->pos), name, ProfilerCallLevel::select}; Pos* fpos = pos2 != NULL ? pos2 : &(this->pos);
state.profState.jumpInValue(lvl); state.profState.jumpInValue(fpos, name, ProfilerCallType::select);
state.forceValue(*vAttrs, ( pos2 != NULL ? *pos2 : this->pos ) ); state.forceValue(*vAttrs, *fpos);
state.profState.createCallgraphentry(lvl); state.profState.jumpOutValue();
} }
} catch (Error & e) { } catch (Error & e) {
@ -1809,6 +1809,8 @@ void EvalState::printStats()
uint64_t bLists = nrListElems * sizeof(Value *); uint64_t bLists = nrListElems * sizeof(Value *);
uint64_t bValues = nrValues * sizeof(Value); uint64_t bValues = nrValues * sizeof(Value);
uint64_t bAttrsets = nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr); uint64_t bAttrsets = nrAttrsets * sizeof(Bindings) + nrAttrsInAttrsets * sizeof(Attr);
if(settings.profileEvaluation)
profState.printCallGraph();
#if HAVE_BOEHMGC #if HAVE_BOEHMGC
GC_word heapSize, totalBytes; GC_word heapSize, totalBytes;
@ -2035,16 +2037,19 @@ static GlobalConfig::Register r1(&evalSettings);
*/ */
ProfilerState::ProfilerState(): ProfilerState::ProfilerState():
nestedLevel(0) profilerTreeRoot(std::nullopt),
{} lastProfilerCall(std::nullopt)
{
}
CompressedFileId ProfilerState::registerFile(FileName& fName) { CompressedFileId ProfilerState::registerFile(FileName& fName) {
CompressedFileId fid; CompressedFileId fid;
auto it = fileMap.find(fName); auto it = fileMap.find(fName);
if(it == fileMap.end()) { if(it == fileMap.end()) {
fid = currentFuncId; fid = currentFileId;
fileMap.insert({fName,currentFuncId}); fileMap.insert({fName,currentCostCenterId});
currentFuncId++; currentFileId++;
} }
else { else {
fid = it->second; fid = it->second;
@ -2052,13 +2057,13 @@ CompressedFileId ProfilerState::registerFile(FileName& fName) {
return fid; return fid;
} }
CompressedFuncId ProfilerState::registerFunction(CostCenterName& fName) { CompressedCostCenterId ProfilerState::registerCostCenter(CostCenterName& fName) {
CompressedFuncId fid; CompressedCostCenterId fid;
auto it = costMap.find(fName); auto it = costMap.find(fName);
if(it == costMap.end()) { if(it == costMap.end()) {
fid = currentFuncId; fid = currentCostCenterId;
costMap.insert({fName,currentFuncId}); costMap.insert({fName,currentCostCenterId});
currentFuncId++; currentCostCenterId++;
} }
else { else {
fid = it->second; fid = it->second;
@ -2066,36 +2071,139 @@ CompressedFuncId ProfilerState::registerFunction(CostCenterName& fName) {
return fid; 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 delim="";
string opStr=""; string opStr="";
std::ostringstream srcPos; std::ostringstream srcPos;
if (lastProfilerCall) {
lastProfilerCall->children.push_front(call);
} else {
std::cout << "Redifining tree root " << std::endl;
profilerTreeRoot = call;
}
callGraphStack.push(call); callGraphStack.push(call);
lastProfilerCall = call;
// Printing stuff
int stackSize = callGraphStack.size(); int stackSize = callGraphStack.size();
for(int i=0;i<stackSize;i++) { for(int i=0;i<stackSize;i++) {
delim+="="; delim+="=";
} }
switch (call.callType) { switch (type) {
case ProfilerCallLevel::select: case ProfilerCallType::select:
opStr="select"; opStr="select";
break; break;
case ProfilerCallLevel::var: case ProfilerCallType::var:
opStr="var"; opStr="var";
break; break;
} }
if(call.pos->file.set()) { if(pos->file.set()) {
std::ostringstream ossFi; std::ostringstream ossFi;
ossFi << call.pos->file; ossFi << pos->file;
string fileName = ossFi.str(); string fileName = ossFi.str();
srcPos << fileName << " " << call.pos->line << ":" << call.pos->column; srcPos << fileName << " " << pos->line << ":" << pos->column;
} else { } else {
srcPos << "NOT DEFINED"; 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(); 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 "config.hh"
#include "function-trace.hh" #include "function-trace.hh"
#include <forward_list>
#include <map> #include <map>
#include <unordered_map> #include <optional>
#include <optional>
#include <stack> #include <stack>
#include <unordered_map>
namespace nix { namespace nix {
@ -25,34 +28,43 @@ enum RepairFlag : bool;
typedef string CostCenterName; typedef string CostCenterName;
typedef string FileName; typedef string FileName;
typedef int CompressedFuncId; typedef int CompressedCostCenterId;
typedef int CompressedFileId; typedef int CompressedFileId;
typedef int LineNumber; typedef int LineNumber;
typedef int BullshitCost;
struct ProfFuncOcc { struct PosCost {
CompressedFuncId funcId; LineNumber line;
CompressedFileId fileId; BullshitCost cost;
}; };
struct ProfFuncCall { struct CallCost {
CompressedFuncId calledFunc; LineNumber line;
CompressedFileId calledFile; int nbCalls;
LineNumber calledFuncLineNb;
int cost;
}; };
struct ProfCostOcc { struct CallGraphCall {
CompressedFuncId funcId; FileName fileName;
CompressedFileId fileId; CostCenterName costCenter;
ProfFuncOcc funcOcc; PosCost pos;
int selfCost;
}; };
struct CallGraphCostEntry {
FileName fileName;
CostCenterName costCenter;
std::forward_list<CallGraphCall> calls;
PosCost pos;
};
enum ProfilerCallType { select=0, var};
struct ProfilerCallLevel { struct ProfilerCallLevel {
std::shared_ptr<ProfilerCallLevel> parent;
std::forward_list<std::shared_ptr<ProfilerCallLevel>> children;
Pos* pos; Pos* pos;
CostCenterName name; CostCenterName name;
enum { select=0, var} callType; ProfilerCallType type;
bool visited;
}; };
class ProfilerState { class ProfilerState {
@ -60,21 +72,23 @@ class ProfilerState {
public: public:
ProfilerState(); ProfilerState();
CompressedFileId registerFile(FileName& fName); CompressedFileId registerFile(FileName& fName);
CompressedFuncId registerFunction(CostCenterName& fName); CompressedCostCenterId registerCostCenter(CostCenterName& fName);
ProfCostOcc& getFuncOcc(FileName& fName, CostCenterName& fnName); void jumpInValue(Pos* pos, CostCenterName name, ProfilerCallType type);
void saveCost(ProfCostOcc& occCost); void jumpOutValue();
void jumpInValue(ProfilerCallLevel& call); void printCallGraph();
void createCallgraphentry(ProfilerCallLevel& call);
int nestedLevel;
private: private:
/* We index every func and file to leverage Callgrind's string compression. /* We index every func and file to leverage Callgrind's string compression.
See section "3.1.6.<EFBFBD>Subposition Compression" section from [callgrindSpec]. */ See section "3.1.6.Subposition Compression" section from [callgrindSpec]. */
std::map<CostCenterName,CompressedFuncId> costMap; std::map<CostCenterName,CompressedCostCenterId> costMap;
std::map<FileName,CompressedFileId> fileMap; std::map<FileName,CompressedFileId> fileMap;
CompressedFuncId currentFuncId; CompressedCostCenterId currentCostCenterId;
CompressedFileId currentFileId; 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); friend std::ostream & operator << (std::ostream & str, const Symbol & sym);
string str() const
{
return *s;
}
}; };
class SymbolTable class SymbolTable