[LNT] r264042 - [profile] Implement support for profiling shared objects
James Molloy via llvm-commits
llvm-commits at lists.llvm.org
Tue Mar 22 04:45:50 PDT 2016
Author: jamesm
Date: Tue Mar 22 06:45:50 2016
New Revision: 264042
URL: http://llvm.org/viewvc/llvm-project?rev=264042&view=rev
Log:
[profile] Implement support for profiling shared objects
Shared objects are relocated, which means we need to adjust the PC value by subtracting the map base. However we need to determine the difference between a shared object (DYN) and an executable (EXEC) to do this (because executables' PCs should not be adjusted). We therefore load in part of the ELF header and test for e_type == ET_DYN.
Modified:
lnt/trunk/lnt/lnttool/main.py
lnt/trunk/lnt/testing/profile/cPerf.cpp
Modified: lnt/trunk/lnt/lnttool/main.py
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/lnttool/main.py?rev=264042&r1=264041&r2=264042&view=diff
==============================================================================
--- lnt/trunk/lnt/lnttool/main.py (original)
+++ lnt/trunk/lnt/lnttool/main.py Tue Mar 22 06:45:50 2016
@@ -472,7 +472,7 @@ def action_profile(name, args):
if len(args) < 3:
parser.error('Expected 2 arguments')
- profile.Profile.fromFile(args[1]).upgrade().toFile(args[2])
+ profile.Profile.fromFile(args[1]).upgrade().save(filename=args[2])
return
if args[0] == 'getVersion':
Modified: lnt/trunk/lnt/testing/profile/cPerf.cpp
URL: http://llvm.org/viewvc/llvm-project/lnt/trunk/lnt/testing/profile/cPerf.cpp?rev=264042&r1=264041&r2=264042&view=diff
==============================================================================
--- lnt/trunk/lnt/testing/profile/cPerf.cpp (original)
+++ lnt/trunk/lnt/testing/profile/cPerf.cpp Tue Mar 22 06:45:50 2016
@@ -133,6 +133,30 @@ void Assert(bool Expr, const char *ExprS
throw std::logic_error(Str);
}
+// Returns true if the ELF file given by filename
+// is a shared object (DYN).
+bool IsSharedObject(std::string Fname) {
+ // We replicate the first part of an ELF header here
+ // so as not to rely on <elf.h>.
+ struct PartialElfHeader {
+ unsigned char e_ident[16];
+ uint16_t e_type;
+ };
+ const int ET_DYN = 3;
+
+ FILE *stream = fopen(Fname.c_str(), "r");
+ if (stream == NULL)
+ return false;
+
+ PartialElfHeader H;
+ auto NumRead = fread(&H, 1, sizeof(H), stream);
+ assert(NumRead == sizeof(H));
+
+ fclose(stream);
+
+ return H.e_type == ET_DYN;
+}
+
//===----------------------------------------------------------------------===//
// Perf structures. Taken from https://lwn.net/Articles/644919/
//===----------------------------------------------------------------------===//
@@ -386,8 +410,8 @@ public:
unsigned char *readEvent(unsigned char *);
perf_event_sample parseEvent(unsigned char *Buf, uint64_t Layout);
void emitLine(uint64_t PC, std::map<const char *, uint64_t> *Counters,
- const std::string &Text, bool First);
- void emitFunctionStart(std::string &Name, bool First);
+ const std::string &Text);
+ void emitFunctionStart(std::string &Name);
void emitFunctionEnd(std::string &Name,
std::map<const char *, uint64_t> &Counters);
void emitTopLevelCounters();
@@ -395,7 +419,7 @@ public:
void emitSymbol(
Symbol &Sym, Map &M,
std::map<uint64_t, std::map<const char *, uint64_t>>::iterator &Event,
- bool FirstSym);
+ uint64_t Adjust);
PyObject *complete();
private:
@@ -565,7 +589,7 @@ perf_event_sample PerfReader::parseEvent
return E;
}
-void PerfReader::emitFunctionStart(std::string &Name, bool First) {
+void PerfReader::emitFunctionStart(std::string &Name) {
Lines.clear();
}
@@ -590,7 +614,7 @@ void PerfReader::emitFunctionEnd(std::st
void PerfReader::emitLine(uint64_t PC,
std::map<const char *, uint64_t> *Counters,
- const std::string &Text, bool First) {
+ const std::string &Text) {
auto *CounterDict = PyDict_New();
if (Counters)
for (auto &KV : *Counters)
@@ -614,7 +638,6 @@ void PerfReader::emitTopLevelCounters()
}
void PerfReader::emitMaps() {
- bool FirstSym = true;
for (auto &KV : Events) {
auto MapID = KV.first;
auto &MapEvents = KV.second;
@@ -640,13 +663,19 @@ void PerfReader::emitMaps() {
if (AllUnderThreshold)
continue;
+ // EXEC ELF objects aren't relocated. DYN ones are,
+ // so if it's a DYN object adjust by subtracting the
+ // map base.
+ bool IsSO = IsSharedObject(Maps[MapID].Filename);
+ uint64_t Adjust = IsSO ? Maps[MapID].Start : 0;
+ Adjust = 0;
NmOutput Syms(Nm);
Syms.reset(&Maps[MapID]);
auto Sym = Syms.begin();
auto Event = MapEvents.begin();
while (Event != MapEvents.end() && Sym != Syms.end()) {
- auto PC = Event->first;
+ auto PC = Event->first - Adjust;
if (PC < Sym->Start) {
++Event;
continue;
@@ -658,8 +687,7 @@ void PerfReader::emitMaps() {
continue;
}
- emitSymbol(*Sym++, Maps[MapID], Event, FirstSym);
- FirstSym = false;
+ emitSymbol(*Sym++, Maps[MapID], Event, Adjust);
}
}
}
@@ -667,27 +695,27 @@ void PerfReader::emitMaps() {
void PerfReader::emitSymbol(
Symbol &Sym, Map &M,
std::map<uint64_t, std::map<const char *, uint64_t>>::iterator &Event,
- bool FirstSym) {
+ uint64_t Adjust) {
ObjdumpOutput Dump(Objdump);
Dump.reset(&M, Sym.Start, Sym.End);
Dump.next();
std::map<const char *, uint64_t> SymEvents;
- emitFunctionStart(Sym.Name, FirstSym);
+ emitFunctionStart(Sym.Name);
for (uint64_t I = Sym.Start; I < Sym.End; I = Dump.next()) {
- auto PC = Event->first;
+ auto PC = Event->first - Adjust;
auto Text = Dump.getText();
if (PC == I) {
- emitLine(I, &Event->second, Text, I == Sym.Start);
+ emitLine(I, &Event->second, Text);
for (auto &KV : Event->second)
SymEvents[KV.first] += KV.second;
++Event;
} else {
- emitLine(I, nullptr, Text, I == Sym.Start);
+ emitLine(I, nullptr, Text);
}
}
emitFunctionEnd(Sym.Name, SymEvents);
More information about the llvm-commits
mailing list