Changeset View
Changeset View
Standalone View
Standalone View
lnt/testing/profile/cPerf.cpp
Show First 20 Lines • Show All 253 Lines • ▼ Show 20 Lines | struct Symbol { | ||||
bool operator<(const Symbol &Other) const { return Start < Other.Start; } | bool operator<(const Symbol &Other) const { return Start < Other.Start; } | ||||
bool operator==(const Symbol &Other) const { | bool operator==(const Symbol &Other) const { | ||||
return Start == Other.Start && End == Other.End && Name == Other.Name; | return Start == Other.Start && End == Other.End && Name == Other.Name; | ||||
} | } | ||||
}; | }; | ||||
class NmOutput : public std::vector<Symbol> { | class NmOutput : public std::vector<Symbol> { | ||||
public: | public: | ||||
std::string Nm; | std::string Nm, BinaryCacheRoot; | ||||
NmOutput(std::string Nm) : Nm(Nm) {} | NmOutput(std::string Nm, std::string BinaryCacheRoot) | ||||
: Nm(Nm), BinaryCacheRoot(BinaryCacheRoot) {} | |||||
void fetchSymbols(Map *M, bool Dynamic) { | void fetchSymbols(Map *M, bool Dynamic) { | ||||
std::string D = "-D"; | std::string D = "-D"; | ||||
if (!Dynamic) | if (!Dynamic) | ||||
// Don't fetch the dynamic symbols - instead fetch static ones. | // Don't fetch the dynamic symbols - instead fetch static ones. | ||||
D = ""; | D = ""; | ||||
std::string Cmd = Nm + " " + D + " -S --defined-only " + std::string(M->Filename) + | std::string Cmd = Nm + " " + D + " -S --defined-only " + | ||||
BinaryCacheRoot + std::string(M->Filename) + | |||||
" 2>/dev/null"; | " 2>/dev/null"; | ||||
auto Stream = ForkAndExec(Cmd); | auto Stream = ForkAndExec(Cmd); | ||||
char *Line = nullptr; | char *Line = nullptr; | ||||
size_t LineLen = 0; | size_t LineLen = 0; | ||||
while (true) { | while (true) { | ||||
ssize_t Len = getline(&Line, &LineLen, Stream); | ssize_t Len = getline(&Line, &LineLen, Stream); | ||||
if (Len == -1) | if (Len == -1) | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | while (std::getline(ss, token, delim)) { | ||||
output.push_back(token); | output.push_back(token); | ||||
} | } | ||||
return output.size(); | return output.size(); | ||||
} | } | ||||
}; | }; | ||||
class ObjdumpOutput { | class ObjdumpOutput { | ||||
public: | public: | ||||
std::string Objdump; | std::string Objdump, BinaryCacheRoot; | ||||
FILE *Stream; | FILE *Stream; | ||||
char *ThisText; | char *ThisText; | ||||
uint64_t ThisAddress; | uint64_t ThisAddress; | ||||
uint64_t EndAddress; | uint64_t EndAddress; | ||||
char *Line; | char *Line; | ||||
size_t LineLen; | size_t LineLen; | ||||
ObjdumpOutput(std::string Objdump) | ObjdumpOutput(std::string Objdump, std::string BinaryCacheRoot) | ||||
: Objdump(Objdump), Stream(nullptr), Line(NULL), LineLen(0) {} | : Objdump(Objdump), BinaryCacheRoot(BinaryCacheRoot), Stream(nullptr), | ||||
Line(NULL), LineLen(0) {} | |||||
~ObjdumpOutput() { | ~ObjdumpOutput() { | ||||
if (Stream) { | if (Stream) { | ||||
fclose(Stream); | fclose(Stream); | ||||
wait(NULL); | wait(NULL); | ||||
} | } | ||||
if (Line) | if (Line) | ||||
free(Line); | free(Line); | ||||
} | } | ||||
void reset(Map *M, uint64_t Start, uint64_t Stop) { | void reset(Map *M, uint64_t Start, uint64_t Stop) { | ||||
ThisAddress = 0; | ThisAddress = 0; | ||||
if (Stream) { | if (Stream) { | ||||
fclose(Stream); | fclose(Stream); | ||||
wait(NULL); | wait(NULL); | ||||
} | } | ||||
char buf1[32], buf2[32]; | char buf1[32], buf2[32]; | ||||
sprintf(buf1, "%#llx", Start); | sprintf(buf1, "%#llx", Start); | ||||
sprintf(buf2, "%#llx", Stop + 4); | sprintf(buf2, "%#llx", Stop + 4); | ||||
std::string Cmd = Objdump + " -d --no-show-raw-insn --start-address=" + | std::string Cmd = Objdump + " -d --no-show-raw-insn --start-address=" + | ||||
std::string(buf1) + " --stop-address=" + | std::string(buf1) + " --stop-address=" + | ||||
std::string(buf2) + " " + std::string(M->Filename) + | std::string(buf2) + " " + | ||||
BinaryCacheRoot + std::string(M->Filename) + | |||||
" 2>/dev/null"; | " 2>/dev/null"; | ||||
Stream = ForkAndExec(Cmd); | Stream = ForkAndExec(Cmd); | ||||
EndAddress = Stop; | EndAddress = Stop; | ||||
}; | }; | ||||
std::string getText() { return ThisText; } | std::string getText() { return ThisText; } | ||||
Show All 28 Lines | |||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
// PerfReader | // PerfReader | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
class PerfReader { | class PerfReader { | ||||
public: | public: | ||||
PerfReader(const std::string &Filename, std::string Nm, | PerfReader(const std::string &Filename, std::string Nm, | ||||
std::string Objdump); | std::string Objdump, std::string BinaryCacheRoot); | ||||
~PerfReader(); | ~PerfReader(); | ||||
void readHeader(); | void readHeader(); | ||||
void readAttrs(); | void readAttrs(); | ||||
void readDataStream(); | void readDataStream(); | ||||
unsigned char *readEvent(unsigned char *); | unsigned char *readEvent(unsigned char *); | ||||
perf_event_sample parseEvent(unsigned char *Buf, uint64_t Layout); | perf_event_sample parseEvent(unsigned char *Buf, uint64_t Layout); | ||||
void emitLine(uint64_t PC, std::map<const char *, uint64_t> *Counters, | void emitLine(uint64_t PC, std::map<const char *, uint64_t> *Counters, | ||||
Show All 21 Lines | private: | ||||
std::map<const char *, uint64_t> TotalEvents; | std::map<const char *, uint64_t> TotalEvents; | ||||
std::map<uint64_t, std::map<const char *, uint64_t>> TotalEventsPerMap; | std::map<uint64_t, std::map<const char *, uint64_t>> TotalEventsPerMap; | ||||
std::vector<Map> Maps; | std::vector<Map> Maps; | ||||
std::map<uint64_t, std::map<uint64_t, size_t>> CurrentMaps; | std::map<uint64_t, std::map<uint64_t, size_t>> CurrentMaps; | ||||
PyObject *Functions, *TopLevelCounters; | PyObject *Functions, *TopLevelCounters; | ||||
std::vector<PyObject*> Lines; | std::vector<PyObject*> Lines; | ||||
std::string Nm, Objdump; | std::string Nm, Objdump, BinaryCacheRoot; | ||||
}; | }; | ||||
PerfReader::PerfReader(const std::string &Filename, | PerfReader::PerfReader(const std::string &Filename, | ||||
std::string Nm, std::string Objdump) | std::string Nm, std::string Objdump, | ||||
: Nm(Nm), Objdump(Objdump) { | std::string BinaryCacheRoot) | ||||
: Nm(Nm), Objdump(Objdump), BinaryCacheRoot(BinaryCacheRoot) { | |||||
int fd = open(Filename.c_str(), O_RDONLY); | int fd = open(Filename.c_str(), O_RDONLY); | ||||
assert(fd > 0); | assert(fd > 0); | ||||
struct stat sb; | struct stat sb; | ||||
assert(fstat(fd, &sb) == 0); | assert(fstat(fd, &sb) == 0); | ||||
BufferLen = (size_t)sb.st_size; | BufferLen = (size_t)sb.st_size; | ||||
Buffer = (unsigned char *)mmap(NULL, BufferLen, PROT_READ, MAP_SHARED, fd, 0); | Buffer = (unsigned char *)mmap(NULL, BufferLen, PROT_READ, MAP_SHARED, fd, 0); | ||||
▲ Show 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | if (AllUnderThreshold) | ||||
continue; | continue; | ||||
// EXEC ELF objects aren't relocated. DYN ones are, | // EXEC ELF objects aren't relocated. DYN ones are, | ||||
// so if it's a DYN object adjust by subtracting the | // so if it's a DYN object adjust by subtracting the | ||||
// map base. | // map base. | ||||
bool IsSO = IsSharedObject(Maps[MapID].Filename); | bool IsSO = IsSharedObject(Maps[MapID].Filename); | ||||
uint64_t Adjust = IsSO ? Maps[MapID].Start : 0; | uint64_t Adjust = IsSO ? Maps[MapID].Start : 0; | ||||
NmOutput Syms(Nm); | NmOutput Syms(Nm, BinaryCacheRoot); | ||||
Syms.reset(&Maps[MapID]); | Syms.reset(&Maps[MapID]); | ||||
// Accumulate the event totals for each symbol | // Accumulate the event totals for each symbol | ||||
auto Sym = Syms.begin(); | auto Sym = Syms.begin(); | ||||
auto Event = MapEvents.begin(); | auto Event = MapEvents.begin(); | ||||
std::map<uint64_t, std::map<const char*, uint64_t>> SymToEventTotals; | std::map<uint64_t, std::map<const char*, uint64_t>> SymToEventTotals; | ||||
while (Event != MapEvents.end() && Sym != Syms.end()) { | while (Event != MapEvents.end() && Sym != Syms.end()) { | ||||
// Skip events until we find one after the start of Sym | // Skip events until we find one after the start of Sym | ||||
Show All 29 Lines | void PerfReader::emitMaps() { | ||||
} | } | ||||
} | } | ||||
void PerfReader::emitSymbol( | void PerfReader::emitSymbol( | ||||
Symbol &Sym, Map &M, | Symbol &Sym, Map &M, | ||||
std::map<uint64_t, std::map<const char *, uint64_t>>::iterator Event, | std::map<uint64_t, std::map<const char *, uint64_t>>::iterator Event, | ||||
std::map<const char *, uint64_t> &SymEvents, | std::map<const char *, uint64_t> &SymEvents, | ||||
uint64_t Adjust) { | uint64_t Adjust) { | ||||
ObjdumpOutput Dump(Objdump); | ObjdumpOutput Dump(Objdump, BinaryCacheRoot); | ||||
Dump.reset(&M, Sym.Start, Sym.End); | Dump.reset(&M, Sym.Start, Sym.End); | ||||
Dump.next(); | Dump.next(); | ||||
emitFunctionStart(Sym.Name); | emitFunctionStart(Sym.Name); | ||||
for (uint64_t I = Sym.Start; I < Sym.End; I = Dump.next()) { | for (uint64_t I = Sym.Start; I < Sym.End; I = Dump.next()) { | ||||
auto PC = Event->first - Adjust; | auto PC = Event->first - Adjust; | ||||
auto Text = Dump.getText(); | auto Text = Dump.getText(); | ||||
Show All 14 Lines | PyObject *PerfReader::complete() { | ||||
return Obj; | return Obj; | ||||
} | } | ||||
#ifndef STANDALONE | #ifndef STANDALONE | ||||
static PyObject *cPerf_importPerf(PyObject *self, PyObject *args) { | static PyObject *cPerf_importPerf(PyObject *self, PyObject *args) { | ||||
const char *Fname; | const char *Fname; | ||||
const char *Nm = "nm"; | const char *Nm = "nm"; | ||||
const char *Objdump = "objdump"; | const char *Objdump = "objdump"; | ||||
if (!PyArg_ParseTuple(args, "s|ss", &Fname, &Nm, &Objdump)) | const char *BinaryCacheRoot = ""; | ||||
if (!PyArg_ParseTuple(args, "s|sss", &Fname, &Nm, &Objdump, &BinaryCacheRoot)) | |||||
return NULL; | return NULL; | ||||
try { | try { | ||||
PerfReader P(Fname, Nm, Objdump); | PerfReader P(Fname, Nm, Objdump, BinaryCacheRoot); | ||||
P.readHeader(); | P.readHeader(); | ||||
P.readAttrs(); | P.readAttrs(); | ||||
P.readDataStream(); | P.readDataStream(); | ||||
P.emitTopLevelCounters(); | P.emitTopLevelCounters(); | ||||
P.emitMaps(); | P.emitMaps(); | ||||
return P.complete(); | return P.complete(); | ||||
} catch (std::logic_error &E) { | } catch (std::logic_error &E) { | ||||
PyErr_SetString(PyExc_AssertionError, E.what()); | PyErr_SetString(PyExc_AssertionError, E.what()); | ||||
▲ Show 20 Lines • Show All 50 Lines • Show Last 20 Lines |