提交 84fc5c92 编写于 作者: M Megvii Engine Team 提交者: huangxinda

refactor(profiler): remove dump logic for old profiler

GitOrigin-RevId: f9a3b6d7b9b9178dd9ce53bb391d0a0077d8af3b
上级 5b5a8261
......@@ -847,7 +847,6 @@ void ChannelImpl::process_one_task(IdentifiedCommand& icmd) {
return "unknown";
}
};
InterpreterProfiler::dump_data(cmd.basename, cmd.format, records, profiler->get_option(), host_map);
} else if constexpr (std::is_same_v<T, PushScope>) {
state.scopes.push_back(cmd.scope_name);
do_finish_command();
......
......@@ -26,255 +26,5 @@
namespace mgb::imperative::interpreter::intl {
namespace {
struct InterpreterProfilerDumpChromeTimelineContext {
// either host_thread(std::thread::id) or device_thread(CompNode)
using Thread = std::variant<std::thread::id, CompNode>;
// input params
std::string base_name;
std::string format;
InterpreterProfiler::Data profile_data;
InterpreterProfiler::Option option;
std::function<std::string(std::thread::id)> host_map;
// internal states
decltype(getpid()) pid;
CompNode::UnorderedMap<std::map<double, CompNode::Event*>> device_sync_map;
SmallVector<Thread> thread_list;
double time_start;
// options
bool show_operator_name;
// results
ChromeTraceEventList event_list;
InterpreterProfilerDumpChromeTimelineContext(
std::string base_name,
std::string format,
InterpreterProfiler::Data profile_data,
InterpreterProfiler::Option option,
std::function<std::string(std::thread::id)> host_map)
: base_name{base_name}, format{format}, profile_data{profile_data}, option{option}, host_map{host_map} {
pid = getpid();
time_start = option.align_time ? time_start : 0;
show_operator_name = option.show_operator_name;
}
// get device time from event
double get_device_time(CompNode::Event* device_event, double host_time) {
device_event->host_wait();
auto& sync_map = device_sync_map[device_event->comp_node()];
// find sync point
auto iter = sync_map.begin();
auto sync_current = [&] {
iter = sync_map.insert(iter, {host_time, device_event});
return host_time;
};
if (iter == sync_map.end()) {
// not found, insert sync
return sync_current();
}
auto& [base_time, base] = *iter;
// calculate elapsed time
double delta_time = base->elapsed_time_until(*device_event) * 1e3;
return base_time + delta_time;
};
template <typename T>
size_t get_tid(T t) {
for (size_t i = 0; i < thread_list.size(); i++) {
if (thread_list[i] == Thread{t}) {
return i;
}
}
thread_list.push_back(t);
return thread_list.size() - 1;
};
ChromeTraceEvent& new_event(std::string name, char ph, uint64_t tid, double ts) {
return event_list.new_event().name(name).ph(ph).tid(tid).ts(ts).pid(pid);
};
// convert Command to json object. Has to be an callable object
static auto constexpr cmd_to_args = [](const auto& cmd) {
auto args = json::Object::make();
cmd.get_props([&](const char* key, auto&& value){
(*args)[key] = json::String::make(to_string(value));
});
(*args)["__type__"] = json::String::make(typeid(cmd).name());
return args;
};
void process() {
// enumerate and process each record
for (auto& record: profile_data.records) {
std::visit([this](const auto& record){
using TEvent = std::decay_t<decltype(record.data)>;
Session<TEvent>(*this, record).process();
}, record);
}
for (size_t tid = 0; tid < thread_list.size(); ++tid) {
auto tname = std::visit([&](auto host_or_device) -> std::string{
using T = std::decay_t<decltype(host_or_device)>;
if constexpr (std::is_same_v<T, std::thread::id>) {
// take name from host_map
return host_map(host_or_device);
} else {
// use CompNode::to_string
return host_or_device.to_string();
}
}, thread_list[tid]);
// assign thread name
new_event("thread_name", 'M', tid, 0)
.arg("name", tname);
}
// wraite output to file
std::string out_buf;
event_list.to_json()->writeto(out_buf, 4);
std::ofstream output_stream;
output_stream.open(base_name + "." + format);
output_stream << out_buf;
output_stream.flush();
output_stream.close();
}
template <typename TEvent>
struct Session {
InterpreterProfilerDumpChromeTimelineContext& ctx;
const ProfilerBase::EventRecord<TEvent>& record;
const TEvent& data;
Session(InterpreterProfilerDumpChromeTimelineContext& ctx,
const ProfilerBase::EventRecord<TEvent>& record)
: ctx{ctx}, record{record}, data{record.data} {}
uint64_t get_host_tid() {
return ctx.get_tid(record.host().tid);
};
double get_host_ts() {
return (ctx.time_start + record.host().time) * 1e3;
};
uint64_t get_device_tid() {
return ctx.get_tid(record.device().event->comp_node());
};
double get_device_ts() {
return (ctx.time_start + ctx.get_device_time(record.device().event.get(), record.device().after)) * 1e3;
};
ChromeTraceEvent& new_host_event(std::string name, char ph) {
return ctx.new_event(std::move(name), ph, get_host_tid(), get_host_ts());
};
ChromeTraceEvent& new_device_event(std::string name, char ph) {
return ctx.new_event(std::move(name), ph, get_device_tid(), get_device_ts());
};
void process() {
// dispatch event by type
if constexpr (std::is_same_v<TEvent, CommandEnqueueEvent>) {
auto args = std::visit(cmd_to_args, data.icmd.second);
new_host_event("CommandEnqueue", 'X').dur(0).args(args);
} else if constexpr (std::is_same_v<TEvent, CommandExecuteEvent>) {
auto args = std::visit(cmd_to_args, data.icmd.second);
new_host_event("CommandExecute", 'B').args(args);
} else if constexpr (std::is_same_v<TEvent, CommandFinishEvent>) {
new_host_event("CommandExecute", 'E');
} else if constexpr (std::is_same_v<TEvent, HostOpExecuteEvent>) {
auto args = json::Object::make();
auto props = OpDef::props(*data.op);
auto name = data.op->trait()->name;
for (auto&& [prop_name, prop_val]: props) {
(*args)[std::string("op.") + prop_name] = json::String::make(prop_val);
}
(*args)["name"] = json::String::make(name);
(*args)["id"] = json::Number::make(data.id);
(*args)["inputs"] = json::String::make(to_string(data.inputs));
(*args)["outputs"] = json::String::make(to_string(data.outputs));
new_host_event(ctx.show_operator_name ? name : "OpExecute", 'B').args(args);
} else if constexpr (std::is_same_v<TEvent, DeviceOpExecuteEvent>) {
auto args = json::Object::make();
auto props = OpDef::props(*data.op);
auto name = data.op->trait()->name;
for (auto&& [prop_name, prop_val]: props) {
(*args)[std::string("op.") + prop_name] = json::String::make(prop_val);
}
(*args)["name"] = json::String::make(name);
(*args)["id"] = json::Number::make(data.id);
(*args)["inputs"] = json::String::make(to_string(data.inputs));
(*args)["outputs"] = json::String::make(to_string(data.outputs));
new_device_event(ctx.show_operator_name ? name : "OpExecute", 'B').args(args);
} else if constexpr (std::is_same_v<TEvent, HostOpFinishEvent>) {
auto name = data.op->trait()->name;
new_host_event(ctx.show_operator_name ? name : "OpExecute", 'E');
} else if constexpr (std::is_same_v<TEvent, DeviceOpFinishEvent>) {
auto name = data.op->trait()->name;
new_device_event(ctx.show_operator_name ? name : "OpExecute", 'E');
} else if constexpr (std::is_same_v<TEvent, TensorDeclareEvent>) {
json::Number::make(data.tensor_id);
new_host_event("TensorLifetime", 'N').id(data.tensor_id);
} else if constexpr (std::is_same_v<TEvent, TensorProduceEvent>) {
auto snapshot = json::Object::make();
(*snapshot)["shape"] = json::String::make(to_string((TensorShape)data.layout));
(*snapshot)["dtype"] = json::String::make(to_string(data.layout.dtype));
(*snapshot)["device"] = json::String::make(to_string(data.device));
json::Number::make(data.tensor_id);
new_host_event("TensorLifetime", 'O').id(data.tensor_id).arg("snapshot", snapshot);
} else if constexpr (std::is_same_v<TEvent, TensorEraseEvent>) {
json::Number::make(data.tensor_id);
new_host_event("TensorLifetime", 'D').id(data.tensor_id);
} else if constexpr (std::is_same_v<TEvent, TensorGetPropEvent>) {
auto args = json::Object::make();
(*args)["id"] = json::Number::make(data.tensor_id);
(*args)["prop"] = json::String::make(to_string(data.prop));
(*args)["prop_desc"] = json::String::make(data.prop_desc);
new_host_event("TensorGetProp", 'X').dur(0).args(args);
} else if constexpr (std::is_same_v<TEvent, TensorNotifyPropEvent>) {
// TODO
} else if constexpr (std::is_same_v<TEvent, TensorWaitPropEvent>) {
auto args = json::Object::make();
(*args)["id"] = json::Number::make(data.tensor_id);
(*args)["prop"] = json::String::make(to_string(data.prop));
(*args)["prop_desc"] = json::String::make(data.prop_desc);
new_host_event("TensorWaitProp", 'B').args(args);
} else if constexpr (std::is_same_v<TEvent, TensorWaitPropFinishEvent>) {
auto args = json::Object::make();
(*args)["id"] = json::Number::make(data.tensor_id);
(*args)["prop"] = json::String::make(to_string(data.prop));
(*args)["prop_desc"] = json::String::make(data.prop_desc);
new_host_event("TensorWaitProp", 'E').args(args);
} else if constexpr (std::is_same_v<TEvent, SyncStartEvent>) {
new_host_event("SyncEvent", 'B');
} else if constexpr (std::is_same_v<TEvent, SyncFinishEvent>) {
new_host_event("SyncEvent", 'E');
} else if constexpr (std::is_same_v<TEvent, ChannelBeginScope>) {
new_host_event(data.name, 'B');
} else if constexpr (std::is_same_v<TEvent, ChannelEndScope>) {
new_host_event(data.name, 'E');
} else if constexpr (std::is_same_v<TEvent, WorkerBeginScope>) {
new_host_event(data.name, 'B');
} else if constexpr (std::is_same_v<TEvent, WorkerEndScope>) {
new_host_event(data.name, 'E');
} else if constexpr (std::is_same_v<TEvent, DeviceBeginScope>) {
new_device_event(data.name, 'B');
} else if constexpr (std::is_same_v<TEvent, DeviceEndScope>) {
new_device_event(data.name, 'E');
} else {
static_assert(!std::is_same_v<TEvent, TEvent>);
}
}
};
};
}
void InterpreterProfiler::dump_data(
std::string basename,
std::string format,
InterpreterProfiler::Data profile_data,
const InterpreterProfiler::Option& option,
std::function<std::string(std::thread::id)> host_map) {
InterpreterProfilerDumpChromeTimelineContext{
basename, format, profile_data, option, host_map
}.process();
}
}
......@@ -61,8 +61,6 @@ public:
m_option = option;
}
static void dump_data(std::string basename, std::string format, InterpreterProfiler::Data profile_data, const Option& option, std::function<std::string(std::thread::id)> host_map);
static Mask topic_to_mask(Topic topic) {
Mask result;
if (topic & Command) {
......
#include <string>
#include <memory>
#include "megbrain/utils/json.h"
namespace mgb {
namespace imperative {
class ChromeTraceEvent {
public:
ChromeTraceEvent& name(std::string name) {
m_name = std::move(name);
return *this;
}
ChromeTraceEvent& tid(uint64_t tid) {
m_tid = std::move(tid);
return *this;
}
ChromeTraceEvent& cat(std::string cat) {
m_cat = std::move(cat);
return *this;
}
ChromeTraceEvent& pid(uint64_t pid) {
m_pid = pid;
return *this;
}
ChromeTraceEvent& id(uint64_t id) {
m_id = id;
return *this;
}
ChromeTraceEvent& idx(uint64_t idx) {
m_idx = idx;
return *this;
}
ChromeTraceEvent& ts(double ts) {
m_ts = ts;
return *this;
}
ChromeTraceEvent& dur(double dur) {
m_dur = dur;
return *this;
}
ChromeTraceEvent& ph(char ph) {
m_ph = ph;
return *this;
}
ChromeTraceEvent& bp(char bp) {
m_bp = bp;
return *this;
}
ChromeTraceEvent& args(std::shared_ptr<json::Object> args) {
m_args = std::move(args);
return *this;
}
ChromeTraceEvent& arg(std::string key, std::string value) {
if (!m_args) {
m_args = json::Object::make();
}
(*m_args)[key] = json::String::make(value);
return *this;
}
ChromeTraceEvent& arg(std::string key, double value) {
if (!m_args) {
m_args = json::Object::make();
}
(*m_args)[key] = json::Number::make(value);
return *this;
}
ChromeTraceEvent& arg(std::string key, std::shared_ptr<json::Value> value) {
if (!m_args) {
m_args = json::Object::make();
}
(*m_args)[key] = value;
return *this;
}
std::shared_ptr<json::Object> to_json() const {
auto result = json::Object::make();
auto prop_str = [&](auto key, auto value) {
if (value.empty()) {
return;
}
(*result)[key] = json::String::make(value);
};
auto prop_num = [&](auto key, auto value) {
if (!value) {
return;
}
(*result)[key] = json::Number::make(value.value());
};
auto prop_char = [&](auto key, auto value) {
if (!value) {
return;
}
(*result)[key] = json::String::make(std::string{} + value.value());
};
prop_str("name", m_name);
prop_num("tid", m_tid);
prop_str("cat", m_cat);
prop_num("pid", m_pid);
prop_num("id", m_id);
prop_num("idx", m_idx);
prop_num("ts", m_ts);
prop_num("dur", m_dur);
prop_char("ph", m_ph);
prop_char("bp", m_bp);
if (m_args) {
(*result)["args"] = m_args;
}
return result;
}
private:
std::string m_name;
std::string m_cat;
std::optional<uint64_t> m_tid;
std::optional<uint64_t> m_pid;
std::optional<uint64_t> m_id;
std::optional<uint64_t> m_idx;
std::optional<double> m_ts;
std::optional<double> m_dur;
std::optional<char> m_ph;
std::optional<char> m_bp;
std::shared_ptr<json::Object> m_args;
};
class ChromeTraceEventList {
public:
ChromeTraceEvent& new_event() {
m_content.emplace_back();
return m_content.back();
}
std::shared_ptr<json::Array> to_json() const {
auto result = json::Array::make();
for (auto&& event: m_content) {
result->add(event.to_json());
}
return result;
}
private:
std::vector<ChromeTraceEvent> m_content;
};
} // namespace imperative
} // namespace mgb
......@@ -190,142 +190,5 @@ protected:
std::atomic<Status> m_status = NotStarted;
};
class ChromeTraceEvent {
public:
ChromeTraceEvent& name(std::string name) {
m_name = std::move(name);
return *this;
}
ChromeTraceEvent& tid(uint64_t tid) {
m_tid = std::move(tid);
return *this;
}
ChromeTraceEvent& cat(std::string cat) {
m_cat = std::move(cat);
return *this;
}
ChromeTraceEvent& pid(uint64_t pid) {
m_pid = pid;
return *this;
}
ChromeTraceEvent& id(uint64_t id) {
m_id = id;
return *this;
}
ChromeTraceEvent& idx(uint64_t idx) {
m_idx = idx;
return *this;
}
ChromeTraceEvent& ts(double ts) {
m_ts = ts;
return *this;
}
ChromeTraceEvent& dur(double dur) {
m_dur = dur;
return *this;
}
ChromeTraceEvent& ph(char ph) {
m_ph = ph;
return *this;
}
ChromeTraceEvent& bp(char bp) {
m_bp = bp;
return *this;
}
ChromeTraceEvent& args(std::shared_ptr<json::Object> args) {
m_args = std::move(args);
return *this;
}
ChromeTraceEvent& arg(std::string key, std::string value) {
if (!m_args) {
m_args = json::Object::make();
}
(*m_args)[key] = json::String::make(value);
return *this;
}
ChromeTraceEvent& arg(std::string key, double value) {
if (!m_args) {
m_args = json::Object::make();
}
(*m_args)[key] = json::Number::make(value);
return *this;
}
ChromeTraceEvent& arg(std::string key, std::shared_ptr<json::Value> value) {
if (!m_args) {
m_args = json::Object::make();
}
(*m_args)[key] = value;
return *this;
}
std::shared_ptr<json::Object> to_json() const {
auto result = json::Object::make();
auto prop_str = [&](auto key, auto value) {
if (value.empty()) {
return;
}
(*result)[key] = json::String::make(value);
};
auto prop_num = [&](auto key, auto value) {
if (!value) {
return;
}
(*result)[key] = json::Number::make(value.value());
};
auto prop_char = [&](auto key, auto value) {
if (!value) {
return;
}
(*result)[key] = json::String::make(std::string{} + value.value());
};
prop_str("name", m_name);
prop_num("tid", m_tid);
prop_str("cat", m_cat);
prop_num("pid", m_pid);
prop_num("id", m_id);
prop_num("idx", m_idx);
prop_num("ts", m_ts);
prop_num("dur", m_dur);
prop_char("ph", m_ph);
prop_char("bp", m_bp);
if (m_args) {
(*result)["args"] = m_args;
}
return result;
}
private:
std::string m_name;
std::string m_cat;
std::optional<uint64_t> m_tid;
std::optional<uint64_t> m_pid;
std::optional<uint64_t> m_id;
std::optional<uint64_t> m_idx;
std::optional<double> m_ts;
std::optional<double> m_dur;
std::optional<char> m_ph;
std::optional<char> m_bp;
std::shared_ptr<json::Object> m_args;
};
class ChromeTraceEventList {
public:
ChromeTraceEvent& new_event() {
m_content.emplace_back();
return m_content.back();
}
std::shared_ptr<json::Array> to_json() const {
auto result = json::Array::make();
for (auto&& event: m_content) {
result->add(event.to_json());
}
return result;
}
private:
std::vector<ChromeTraceEvent> m_content;
};
} // namespace imperative
} // namespace mgb
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册