From: Serhei Makarov Date: Mon, 19 Jan 2026 20:21:26 +0000 (-0500) Subject: stackprof.cxx snap: unwind arc gathering for now X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d5b30e1999cfac9b4435edfb875a7e458568a559;p=thirdparty%2Felfutils.git stackprof.cxx snap: unwind arc gathering for now gmon.out format writing still WIP --- diff --git a/src/stackprof.cxx b/src/stackprof.cxx index fe31c880..f862c06c 100644 --- a/src/stackprof.cxx +++ b/src/stackprof.cxx @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -122,10 +123,30 @@ struct UnwindDwflStats { Dwfl_Unwound_Source worst_unwound; /* track CFI source, for diagnostic purposes */ }; +struct hash_arc { + template + size_t operator()(const std::pair &p) const { + return std::hash()(p.first) ^ std::hash()(p.second); + } +}; + // Unwind statistics for a single module identified by build-id. struct UnwindModuleStats { - /* TODO: For gmon.out: histogram. */ - /* TODO: For gmon.out: callgraph arcs. */ + /* TODO: Verify histogram granularity */ + unordered_map histogram; + unordered_map, uint32_t, hash_arc> callgraph; + + void record_pc(Dwarf_Addr pc) { + if (histogram.count(pc) == 0) + histogram[pc] = 0; + histogram[pc]++; + } + void record_callgraph_arc(Dwarf_Addr from, Dwarf_Addr to) { + std::pair arc(from, to); + if (callgraph.count(arc) == 0) + callgraph[arc] = 0; + callgraph[arc]++; + } }; struct UnwindStatsTable @@ -142,7 +163,8 @@ struct UnwindStatsTable Dwfl *pid_find_dwfl(pid_t pid); void pid_store_dwfl(pid_t pid, Dwfl *dwfl); - /* TODO buildid functions :: buildid_find{,_or_create} */ + UnwindModuleStats *buildid_find(string buildid); + UnwindModuleStats *buildid_find_or_create(string buildid, Dwfl_Module *mod); }; class PerfConsumer; @@ -258,13 +280,14 @@ public: struct UnwindSample { const perf_event_header *event; + Dwfl *dwfl; uint32_t pid, tid; vector> buildid_reladdrs; /* TODO: Populate. */ vector addrs; int elfclass; + Dwarf_Addr base; /* for diagnostic purposes */ Dwarf_Addr sp; /* for diagnostic purposes */ - Dwfl *dwfl; /* for diagnostic purposes */ }; @@ -1108,6 +1131,24 @@ void UnwindStatsTable::pid_store_dwfl (pid_t pid, Dwfl *dwfl) return; } +UnwindModuleStats *UnwindStatsTable::buildid_find (string buildid) +{ + if (this->buildid_tab.count(buildid) == 0) + return NULL; + return &this->buildid_tab[buildid]; +} + +UnwindModuleStats *UnwindStatsTable::buildid_find_or_create (string buildid, Dwfl_Module *mod) +{ + if (this->buildid_tab.count(buildid) == 0) + { + this->buildid_tab.emplace(buildid, UnwindModuleStats()); + /* TODO: Guess text range for mod? */ + (void)mod; + } + return &this->buildid_tab[buildid]; +} + //////////////////////////////////////////////////////////////////////// // real perf consumer: unwind helpers @@ -1567,11 +1608,46 @@ void UnwindStatsConsumer::process(const UnwindSample* sample) GprofUnwindSampleConsumer::~GprofUnwindSampleConsumer() { - /* TODO write gmon.out files */ + cout << endl << "=== buildid / sample counts ===" << endl; + for (auto& p : this->stats->buildid_tab) + { + const string& buildid = p.first; + UnwindModuleStats& m = p.second; + fprintf (stdout, N_("buildid %s -- received %ld distinct pcs, %ld callgraph arcs\n"), /* TODO also count samples */ + buildid.c_str(), m.histogram.size(), m.callgraph.size()); + /* TODO write gmon.out file always, only fprintf on show_summary */ + } + fprintf(stdout, "===\n"); + fprintf(stdout, N_("TOTAL -- received %ld buildids\n"), this->stats->buildid_tab.size()); + cout << endl; } void GprofUnwindSampleConsumer::process(const UnwindSample *sample) { - /* TODO: Record pc in histogram */ - /* TODO: Record callgraph arc in histogram */ + if (sample->addrs.size() < 2) + return; /* no callgraph arc */ + + Dwarf_Addr pc = sample->addrs[0]; + Dwarf_Addr pc2 = sample->addrs[1]; + + Dwfl_Module *mod = dwfl_addrmodule(sample->dwfl, pc); + if (mod == NULL) + return; + + const unsigned char *desc = nullptr; + GElf_Addr vaddr; + int build_id_len = dwfl_module_build_id(mod, &desc, &vaddr); + if (build_id_len <= 0) + return; + + /* TODO(REVIEW.1): Is it better to use the uncoverted build_id_desc as hash key? */ + std::stringstream bs; + bs << std::hex << std::setw(2) << std::setfill('0'); + for (int i = 0; i < build_id_len; ++i) + bs << static_cast(desc[i]); + string buildid = bs.str(); + + UnwindModuleStats *buildid_ent = this->stats->buildid_find_or_create(buildid, mod); + buildid_ent->record_pc(pc); + buildid_ent->record_callgraph_arc(pc2, pc); }