From ec267210d0eee08842d605e38a7d655c9b337ce5 Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Sun, 1 Jun 2014 00:45:57 +0200 Subject: [PATCH] Simplify code and reduce overhead at trace time. We now evaluate the IP to module connection at evaluation time, rather than during tracing to reduce the overhead. This also gets rid of the rather large IP cache, thereby reducing the memory overhead. --- malloctrace.cpp | 41 +++------------- malloctrace_main.cpp | 129 +++++++++++++++++++++------------------------------ 2 files changed, 59 insertions(+), 111 deletions(-) diff --git a/malloctrace.cpp b/malloctrace.cpp index 35b0638..3577430 100644 --- a/malloctrace.cpp +++ b/malloctrace.cpp @@ -186,8 +186,6 @@ struct Module string fileName; uintptr_t addressStart; uintptr_t addressEnd; - unsigned int id; - bool isExe; bool operator<(const Module& module) const { @@ -205,7 +203,6 @@ struct Data Data() { modules.reserve(32); - ipCache.reserve(65536); traceCache.reserve(16384); allocationInfo.reserve(16384); @@ -276,13 +273,12 @@ struct Data } } - Module module{fileName, addressStart, addressEnd, 0, isExe}; + Module module{fileName, addressStart, addressEnd}; auto it = lower_bound(modules.begin(), modules.end(), module); if (it == modules.end() || *it != module) { - module.id = data->next_module_id++; - fprintf(data->out, "m %u %s %lx %lx %d\n", module.id, module.fileName.c_str(), - module.addressStart, module.addressEnd, module.isExe); + fprintf(data->out, "m %s %d %lx %lx\n", module.fileName.c_str(), isExe, + module.addressStart, module.addressEnd); modules.insert(it, module); } @@ -300,35 +296,13 @@ struct Data } auto it = traceCache.find(traceBuffer); if (it == traceCache.end()) { - // cache before converting + // cache trace auto traceId = next_trace_id++; it = traceCache.insert(it, {traceBuffer, traceId}); - // ensure ip cache is up2date - for (auto& ip : traceBuffer) { - auto ipIt = ipCache.find(ip); - if (ipIt == ipCache.end()) { - // find module and offset from cache - auto module = lower_bound(modules.begin(), modules.end(), ip, - [] (const Module& module, const unw_word_t addr) -> bool { - return module.addressEnd < addr; - }); - if (module == modules.end()) { - ip = numeric_limits::max(); - continue; - } - auto ipId = next_ipCache_id++; - fprintf(out, "i %u %u %lx\n", ipId, module->id, ip - module->addressStart); - ipIt = ipCache.insert(ipIt, {ip, ipId}); - } - ip = ipIt->second; - } // print trace fprintf(out, "t %u ", traceId); - for (auto ipId : traceBuffer) { - if (ipId == numeric_limits::max()) { - continue; - } - fprintf(out, "%lu ", ipId); + for (auto ip : traceBuffer) { + fprintf(out, "%lx ", ip); } fputc('\n', out); } @@ -348,13 +322,10 @@ struct Data } mutex m_mutex; - unsigned int next_module_id = 0; unsigned int next_thread_id = 0; - unsigned int next_ipCache_id = 0; unsigned int next_trace_id = 0; vector modules; - unordered_map ipCache; unordered_map traceCache; struct AllocationInfo { diff --git a/malloctrace_main.cpp b/malloctrace_main.cpp index bf852d3..ed632e4 100644 --- a/malloctrace_main.cpp +++ b/malloctrace_main.cpp @@ -23,9 +23,11 @@ #include #include #include -#include +#include #include +#include + #include "libbacktrace/backtrace.h" using namespace std; @@ -73,7 +75,7 @@ ostream& operator<<(ostream& out, const AddressInformation& info) struct Module { - Module(string _fileName, uintptr_t addressStart, uintptr_t addressEnd, bool isExe) + Module(string _fileName, bool isExe, uintptr_t addressStart, uintptr_t addressEnd) : fileName(move(_fileName)) , addressStart(addressStart) , addressEnd(addressEnd) @@ -97,14 +99,14 @@ struct Module } } - AddressInformation resolveAddress(uintptr_t offset) const + AddressInformation resolveAddress(uintptr_t address) const { AddressInformation info; if (!backtraceState) { return info; } - backtrace_pcinfo(backtraceState, addressStart + offset, + backtrace_pcinfo(backtraceState, address, [] (void *data, uintptr_t /*addr*/, const char *file, int line, const char *function) -> int { auto info = reinterpret_cast(data); info->function = demangle(function); @@ -114,7 +116,7 @@ struct Module }, &emptyErrorCallback, &info); if (info.function.empty()) { - backtrace_syminfo(backtraceState, addressStart + offset, + backtrace_syminfo(backtraceState, address, [] (void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) { if (symname) { reinterpret_cast(data)->function = demangle(symname); @@ -138,6 +140,18 @@ struct Module { } + bool operator<(const Module& module) const + { + return make_tuple(addressStart, addressEnd, fileName) + < make_tuple(module.addressStart, module.addressEnd, module.fileName); + } + + bool operator!=(const Module& module) const + { + return make_tuple(addressStart, addressEnd, fileName) + != make_tuple(module.addressStart, module.addressEnd, module.fileName); + } + backtrace_state* backtraceState = nullptr; string fileName; uintptr_t addressStart; @@ -145,26 +159,11 @@ struct Module bool isExe; }; -struct InstructionPointer -{ - shared_ptr module; - uintptr_t offset; -}; - struct Trace { - vector backtrace; + vector backtrace; size_t allocations = 0; size_t leaked = 0; - - void printBacktrace(ostream& out) const - { - for (const auto& ip : backtrace) { - out << "0x" << hex << ip.offset << dec - << ' ' << ip.module->resolveAddress(ip.offset) - << ' ' << ip.module->fileName << endl; - } - } }; struct AccumulatedTraceData @@ -172,12 +171,29 @@ struct AccumulatedTraceData AccumulatedTraceData() { modules.reserve(64); - instructions.reserve(65536); traces.reserve(16384); } - vector> modules; - vector instructions; + void printBacktrace(const Trace& trace, ostream& out) const + { + for (auto ip : trace.backtrace) { + out << "0x" << hex << ip << dec; + // find module for this instruction pointer + auto module = lower_bound(modules.begin(), modules.end(), ip, + [] (const Module& module, const uintptr_t ip) -> bool { + return module.addressEnd < ip; + }); + if (module != modules.end() && module->addressStart <= ip && module->addressEnd >= ip) { + out << ' ' << module->resolveAddress(ip) + << ' ' << module->fileName; + } else { + out << " "; + } + out << endl; + } + } + + vector modules; vector traces; map sizeHistogram; @@ -210,8 +226,6 @@ int main(int argc, char** argv) line.reserve(1024); stringstream lineIn(ios_base::in); size_t nextTraceId = 0; - size_t nextModuleId = 0; - size_t nextIpId = 0; while (in.good()) { getline(in, line); if (line.empty()) { @@ -222,57 +236,21 @@ int main(int argc, char** argv) char mode = 0; lineIn >> mode; if (mode == 'm') { - size_t id = 0; - lineIn >> id; - if (id != nextModuleId) { - cerr << "inconsistent trace data: " << line << endl - << "expected module with id: " << nextModuleId << endl; - return 1; - } string fileName; lineIn >> fileName; + bool isExe = false; + lineIn >> isExe; lineIn << hex; uintptr_t addressStart = 0; lineIn >> addressStart; uintptr_t addressEnd = 0; lineIn >> addressEnd; - bool isExe = false; lineIn << dec; - lineIn >> isExe; if (lineIn.bad()) { cerr << "failed to parse line: " << line << endl; return 1; } - data.modules.push_back(make_shared(fileName, addressStart, addressEnd, isExe)); - ++nextModuleId; - } else if (mode == 'i') { - InstructionPointer ip; - size_t id = 0; - lineIn >> id; - if (id != nextIpId) { - cerr << "inconsistent trace data: " << line << endl - << "expected instruction with id: " << nextIpId << endl; - return 1; - } - - size_t moduleId = 0; - lineIn >> moduleId; - if (moduleId >= data.modules.size()) { - cerr << "inconsistent trace data: " << line << endl - << "failed to find module " << moduleId << ", only got so far: " << data.modules.size() << endl; - return 1; - } - - lineIn << hex; - lineIn >> ip.offset; - lineIn << dec; - if (lineIn.bad()) { - cerr << "failed to parse line: " << line << endl; - return 1; - } - ip.module = data.modules[moduleId]; - data.instructions.push_back(ip); - ++nextIpId; + data.modules.push_back({fileName, isExe, addressStart, addressEnd}); } else if (mode == 't') { Trace trace; unsigned int id = 0; @@ -286,16 +264,13 @@ int main(int argc, char** argv) << "expected trace with id: " << nextTraceId << endl; return 1; } + lineIn << hex; while (lineIn.good()) { - unsigned int ipId = 0; - lineIn >> ipId; - if (ipId >= data.instructions.size()) { - cerr << "inconsistent trace data: " << line << endl - << "failed to find instruction " << ipId << endl; - return 1; - } - trace.backtrace.push_back(data.instructions[ipId]); + uintptr_t ip = 0; + lineIn >> ip; + trace.backtrace.push_back(ip); } + lineIn << dec; data.traces.push_back(trace); ++nextTraceId; } else if (mode == '+') { @@ -349,6 +324,9 @@ int main(int argc, char** argv) } } + // sort by addresses + sort(data.modules.begin(), data.modules.end()); + // sort by amount of allocations sort(data.traces.begin(), data.traces.end(), [] (const Trace& l, const Trace &r) { return l.allocations > r.allocations; @@ -357,12 +335,11 @@ int main(int argc, char** argv) for (size_t i = 0; i < min(10lu, data.traces.size()); ++i) { const auto& trace = data.traces[i]; cout << trace.allocations << " allocations at:" << endl; - trace.printBacktrace(cout); + data.printBacktrace(trace, cout); cout << endl; } cout << endl; - // sort by amount of leaks sort(data.traces.begin(), data.traces.end(), [] (const Trace& l, const Trace &r) { return l.leaked < r.leaked; @@ -376,7 +353,7 @@ int main(int argc, char** argv) totalLeakAllocations += trace.allocations; cout << trace.leaked << " bytes leaked in " << trace.allocations << " allocations at:" << endl; - trace.printBacktrace(cout); + data.printBacktrace(trace, cout); cout << endl; } cout << data.leaked << " bytes leaked in total from " << totalLeakAllocations << " allocations" << endl; -- 2.7.4