mirror of
https://github.com/pytorch/pytorch.git
synced 2025-10-20 21:14:14 +08:00
This reverts commit e1ea584b1caf9c50de25ce69396dfeb523a452c0. Adds __has_include check to fix fbcode build. Pull Request resolved: https://github.com/pytorch/pytorch/pull/96878 Approved by: https://github.com/ezyang
172 lines
4.9 KiB
C++
172 lines
4.9 KiB
C++
#include <torch/csrc/profiler/combined_traceback.h>
|
|
|
|
namespace torch {
|
|
|
|
static std::atomic<CapturedTraceback::Python*> python_support_ = nullptr;
|
|
|
|
std::shared_ptr<CapturedTraceback> CapturedTraceback::gather(
|
|
bool python,
|
|
bool script,
|
|
bool cpp) {
|
|
auto r = std::make_shared<CapturedTraceback>();
|
|
if (python) {
|
|
auto p = python_support_.load();
|
|
while (p && r->frames_.size() == 0) {
|
|
r->frames_ = p->gather();
|
|
r->python_ = p;
|
|
p = p->next_;
|
|
}
|
|
}
|
|
if (script) {
|
|
r->script_frames_ = torch::jit::currentCallstack();
|
|
}
|
|
if (cpp) {
|
|
r->cpp_frames_ = unwind::unwind();
|
|
}
|
|
return r;
|
|
}
|
|
|
|
CapturedTraceback::~CapturedTraceback() {
|
|
if (frames_.size() > 0) {
|
|
TORCH_INTERNAL_ASSERT(python_);
|
|
python_->release(frames_);
|
|
}
|
|
}
|
|
|
|
struct PyFrameHash {
|
|
std::size_t operator()(const CapturedTraceback::PyFrame& f) const {
|
|
return std::hash<void*>()(f.code) ^ std::hash<int>()(f.lasti);
|
|
}
|
|
};
|
|
|
|
struct PyFrameEq {
|
|
std::size_t operator()(
|
|
const CapturedTraceback::PyFrame& lhs,
|
|
const CapturedTraceback::PyFrame& rhs) const {
|
|
return lhs.code == rhs.code && lhs.lasti == rhs.lasti;
|
|
}
|
|
};
|
|
|
|
SymbolizedTracebacks symbolize(
|
|
const std::vector<CapturedTraceback*>& to_symbolize) {
|
|
SymbolizedTracebacks r;
|
|
|
|
std::unordered_map<void*, size_t> ip_to_frame_offset;
|
|
std::unordered_map<CapturedTraceback::PyFrame, size_t, PyFrameHash, PyFrameEq>
|
|
py_to_frame_offset;
|
|
std::vector<void*> all_cpp_ips;
|
|
|
|
// dedup and collect any C++ frames that need symbols for
|
|
for (const auto& e : to_symbolize) {
|
|
for (void* f : e->cpp_frames_) {
|
|
if (!ip_to_frame_offset.count(f)) {
|
|
ip_to_frame_offset[f] = all_cpp_ips.size();
|
|
all_cpp_ips.push_back(f);
|
|
}
|
|
}
|
|
}
|
|
// gather symbol names for C++ frames
|
|
if (all_cpp_ips.size() > 0) {
|
|
r.all_frames = unwind::symbolize(all_cpp_ips);
|
|
}
|
|
|
|
// batch symbolization requests so we dedup frame objects
|
|
// however, we might have to request from different python interpreters
|
|
// make sure we flush requests before switching interpreters;
|
|
CapturedTraceback::Python* cur_python = nullptr;
|
|
std::vector<CapturedTraceback::PyFrame> cur_py_frames;
|
|
size_t py_frames_size_ = 0;
|
|
|
|
for (const auto& e : to_symbolize) {
|
|
if (e->python_) {
|
|
if (cur_python != e->python_ && cur_py_frames.size() > 0) {
|
|
cur_python->appendSymbolized(cur_py_frames, r);
|
|
cur_py_frames.clear();
|
|
}
|
|
cur_python = e->python_;
|
|
for (const auto& f : e->frames_) {
|
|
if (!py_to_frame_offset.count(f)) {
|
|
py_to_frame_offset[f] = py_frames_size_++;
|
|
cur_py_frames.push_back(f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (cur_py_frames.size() > 0) {
|
|
cur_python->appendSymbolized(cur_py_frames, r);
|
|
cur_py_frames.clear();
|
|
}
|
|
std::vector<std::vector<uint64_t>> python_frame_fragments =
|
|
std::move(r.tracebacks);
|
|
|
|
for (const auto& sc : to_symbolize) {
|
|
r.tracebacks.emplace_back();
|
|
auto py_it = sc->frames_.begin();
|
|
auto py_end = sc->frames_.end();
|
|
|
|
bool jit_appended = false;
|
|
|
|
auto append_python = [&](const CapturedTraceback::PyFrame& f) {
|
|
const auto& fragment =
|
|
python_frame_fragments.at(py_to_frame_offset.at(f));
|
|
r.tracebacks.back().insert(
|
|
r.tracebacks.back().end(), fragment.begin(), fragment.end());
|
|
};
|
|
|
|
auto append_jit = [&]() {
|
|
if (jit_appended) {
|
|
return;
|
|
}
|
|
jit_appended = true;
|
|
for (const auto& f : sc->script_frames_) {
|
|
unwind::Frame frame;
|
|
frame.funcname =
|
|
f.filename; // sic: torchscript puts funcname in filename field
|
|
auto flc = f.range.file_line_col();
|
|
if (flc) {
|
|
size_t col;
|
|
std::tie(frame.filename, frame.lineno, col) = *flc;
|
|
} else {
|
|
frame.filename = "??";
|
|
frame.lineno = 0;
|
|
}
|
|
r.tracebacks.back().push_back(r.all_frames.size());
|
|
r.all_frames.emplace_back(std::move(frame));
|
|
}
|
|
};
|
|
|
|
for (void* f : sc->cpp_frames_) {
|
|
uint64_t cpp_frame = ip_to_frame_offset.at(f);
|
|
const unwind::Frame& uf = r.all_frames.at(cpp_frame);
|
|
if (uf.funcname.find("PyEval_EvalFrame") != std::string::npos) {
|
|
if (py_it != py_end) {
|
|
append_python(*py_it++);
|
|
}
|
|
} else if (
|
|
uf.funcname.rfind("torch::jit::InterpreterStateImpl::run", 0) !=
|
|
std::string::npos) {
|
|
append_jit();
|
|
}
|
|
r.tracebacks.back().push_back(cpp_frame);
|
|
}
|
|
|
|
// add frames if we otherwise haven't seen the C++ frame indicating where
|
|
// it should go
|
|
append_jit();
|
|
|
|
for (; py_it != py_end; ++py_it) {
|
|
append_python(*py_it);
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
void CapturedTraceback::addPythonUnwinder(CapturedTraceback::Python* p) {
|
|
CapturedTraceback::Python* old_unwinder = python_support_.load();
|
|
do {
|
|
p->next_ = old_unwinder;
|
|
} while (!python_support_.compare_exchange_strong(old_unwinder, p));
|
|
}
|
|
|
|
} // namespace torch
|