1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
|
#pragma once
#include <fmt/format.h>
#include <sys/types.h>
#include <torch/csrc/profiler/unwind/debug_info.h>
#include <torch/csrc/profiler/unwind/line_number_program.h>
#include <torch/csrc/profiler/unwind/sections.h>
#include <torch/csrc/profiler/unwind/unwind.h>
#include <torch/csrc/profiler/unwind/unwind_error.h>
#include <memory>
#include <unordered_map>
namespace torch::unwind {
#define UNWIND_WARN(w, ...) \
do { \
w.emplace_back(fmt::format(__VA_ARGS__)); \
LOG_INFO("WARNING: {}\n", w.back()); \
} while (0);
struct FastSymbolizer {
FastSymbolizer() = default;
Frame symbolize(const std::string& library, uint64_t offset) {
LOG_INFO("symbolizing {} + 0x{:x}\n", library, offset);
Frame frame;
frame.funcname = "??";
frame.filename = library;
frame.lineno = offset;
auto s = getOrCreateSections(library);
if (auto e = s->findSubprogramName(offset)) {
frame.funcname = *e;
} else {
UNWIND_WARN(
warnings_,
"failed to find subprogram name for {} 0x{:x}",
library,
offset);
}
if (auto e = findLine(s, offset)) {
frame.filename = e->first;
frame.lineno = e->second;
} else {
UNWIND_WARN(
warnings_, "failed to find file/line for {} 0x{:x}", library, offset);
}
return frame;
}
const std::vector<std::string>& warnings() {
return warnings_;
}
private:
void parseDebugInfo(Sections* s) {
uint64_t offset = 0;
while (offset < s->debug_info.size) {
DebugInfo info(*s);
info.parse(offset);
if (auto lnp_offset = info.lineNumberProgramOffset()) {
for (auto r : info.ranges()) {
s->addDebugInfoRange(r.first, r.second, line_number_programs_.size());
}
line_number_programs_.emplace_back(
std::make_unique<LineNumberProgram>(*s, *lnp_offset));
}
offset = info.nextOffset();
}
}
Sections* getOrCreateSections(const std::string& library) {
auto it = libraries_.find(library);
if (it == libraries_.end()) {
it = libraries_.insert({library, std::make_unique<Sections>()}).first;
try {
Sections* s = it->second.get();
s->parse(library.c_str());
parseDebugInfo(s);
} catch (UnwindError& err) {
UNWIND_WARN(
warnings_, "failed to parse library {}: {}", library, err.what());
}
}
return it->second.get();
}
std::optional<std::pair<std::string, int64_t>> findLine(
Sections* s,
uint64_t offset) {
if (auto idx = s->findDebugInfoOffset(offset)) {
auto r = line_number_programs_.at(*idx).get();
try {
r->parse();
} catch (UnwindError& err) {
UNWIND_WARN(
warnings_,
"failed to read line number program [{:x}] {}",
r->offset(),
err.what());
}
if (auto e = r->find(offset)) {
return std::make_pair(r->filename(e->file), e->line);
}
}
return std::nullopt;
}
std::unordered_map<std::string, std::unique_ptr<Sections>> libraries_;
std::vector<std::unique_ptr<LineNumberProgram>> line_number_programs_;
std::vector<std::string> warnings_;
};
} // namespace torch::unwind
|