GitOrigin-RevId: 7d86e5f257
release-1.10
@@ -14,7 +14,6 @@ | |||||
#include <list> | #include <list> | ||||
#include "megbrain/imperative/transformations/trace.h" | #include "megbrain/imperative/transformations/trace.h" | ||||
#include "megbrain/imperative/utils/map.h" | #include "megbrain/imperative/utils/map.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
#include "./tensor.h" | #include "./tensor.h" | ||||
@@ -23,9 +23,9 @@ | |||||
#include "megbrain/imperative/transformations/symbol.h" | #include "megbrain/imperative/transformations/symbol.h" | ||||
#include "megbrain/imperative/transformations/trace.h" | #include "megbrain/imperative/transformations/trace.h" | ||||
#include "megbrain/imperative/utils/map.h" | #include "megbrain/imperative/utils/map.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
#include "megbrain/opr/io.h" | #include "megbrain/opr/io.h" | ||||
#include "megbrain/plugin/profiler.h" | #include "megbrain/plugin/profiler.h" | ||||
#include "megbrain/utils/stats.h" | |||||
#include "./common.h" | #include "./common.h" | ||||
#include "./grad.h" | #include "./grad.h" | ||||
@@ -1367,9 +1367,9 @@ void init_tensor(py::module m) { | |||||
return reprs; | return reprs; | ||||
}); | }); | ||||
m.def("print_stats", [] { imperative::Stats::print(); }); | |||||
m.def("print_stats", [] { Stats::print(); }); | |||||
m.def("reset_stats", [] { imperative::Stats::reset(); }); | |||||
m.def("reset_stats", [] { Stats::reset(); }); | |||||
m.def("_get_convert_inputs", | m.def("_get_convert_inputs", | ||||
[]() -> bool { return DTypePromoteCfg::convert_input_enabled; }); | []() -> bool { return DTypePromoteCfg::convert_input_enabled; }); | ||||
@@ -21,7 +21,6 @@ | |||||
#include "megbrain/imperative/transformations/symbol.h" | #include "megbrain/imperative/transformations/symbol.h" | ||||
#include "megbrain/imperative/transformations/trace.h" | #include "megbrain/imperative/transformations/trace.h" | ||||
#include "megbrain/imperative/utils/map.h" | #include "megbrain/imperative/utils/map.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
#include "megbrain/opr/io.h" | #include "megbrain/opr/io.h" | ||||
#include "megbrain/plugin/profiler.h" | #include "megbrain/plugin/profiler.h" | ||||
@@ -14,7 +14,6 @@ | |||||
#include "megbrain/imperative/utils/debug.h" | #include "megbrain/imperative/utils/debug.h" | ||||
#include "megbrain/imperative/utils/helper.h" | #include "megbrain/imperative/utils/helper.h" | ||||
#include "megbrain/imperative/utils/map.h" | #include "megbrain/imperative/utils/map.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
namespace mgb { | namespace mgb { | ||||
namespace imperative { | namespace imperative { | ||||
@@ -19,7 +19,6 @@ | |||||
#include "megbrain/imperative/ops/backward_graph.h" | #include "megbrain/imperative/ops/backward_graph.h" | ||||
#include "megbrain/imperative/ops/opr_attr.h" | #include "megbrain/imperative/ops/opr_attr.h" | ||||
#include "megbrain/imperative/ops/utility.h" | #include "megbrain/imperative/ops/utility.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
#include "megbrain/imperative/utils/to_string.h" | #include "megbrain/imperative/utils/to_string.h" | ||||
#include "../blob_manager_impl.h" | #include "../blob_manager_impl.h" | ||||
@@ -11,7 +11,6 @@ | |||||
#include "megbrain/imperative/opr_utility.h" | #include "megbrain/imperative/opr_utility.h" | ||||
#include "megbrain/imperative/ops/autogen.h" | #include "megbrain/imperative/ops/autogen.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
#include "megbrain/opr/basic_arith.h" | #include "megbrain/opr/basic_arith.h" | ||||
#include "megbrain/opr/utility.h" | #include "megbrain/opr/utility.h" | ||||
@@ -11,7 +11,6 @@ | |||||
#include "megbrain/opr/dnn/pooling.h" | #include "megbrain/opr/dnn/pooling.h" | ||||
#include "megbrain/imperative/ops/autogen.h" | #include "megbrain/imperative/ops/autogen.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
#include "megbrain/opr/utility.h" | #include "megbrain/opr/utility.h" | ||||
#include "megbrain/opr/internal/megdnn_opr_wrapper.h" | #include "megbrain/opr/internal/megdnn_opr_wrapper.h" | ||||
@@ -1,5 +1,4 @@ | |||||
#include "megbrain/imperative/transformation.h" | #include "megbrain/imperative/transformation.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
namespace mgb { | namespace mgb { | ||||
namespace imperative { | namespace imperative { | ||||
@@ -10,7 +10,6 @@ | |||||
*/ | */ | ||||
#include "megbrain/imperative/transformations/eval.h" | #include "megbrain/imperative/transformations/eval.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
namespace mgb { | namespace mgb { | ||||
namespace imperative { | namespace imperative { | ||||
@@ -15,7 +15,6 @@ | |||||
#include "megbrain/imperative/graph_cache.h" | #include "megbrain/imperative/graph_cache.h" | ||||
#include "megbrain/imperative/resource_manager.h" | #include "megbrain/imperative/resource_manager.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
#include <range/v3/all.hpp> | #include <range/v3/all.hpp> | ||||
@@ -13,7 +13,6 @@ | |||||
#include "megbrain/imperative/ops/autogen.h" | #include "megbrain/imperative/ops/autogen.h" | ||||
#include "megbrain/imperative/ops/utility.h" | #include "megbrain/imperative/ops/utility.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
namespace mgb { | namespace mgb { | ||||
namespace imperative { | namespace imperative { | ||||
@@ -1,199 +0,0 @@ | |||||
#pragma once | |||||
#include <chrono> | |||||
#include <iostream> | |||||
#include <map> | |||||
#include <memory> | |||||
#include <string> | |||||
#include <unordered_map> | |||||
#include <vector> | |||||
namespace mgb { | |||||
namespace imperative { | |||||
namespace stats { | |||||
#define MGE_ENABLE_STATS 0 | |||||
class Timer { | |||||
public: | |||||
using clock_t = std::chrono::system_clock; | |||||
private: | |||||
clock_t::duration m_duration = clock_t::duration{0}; | |||||
size_t m_timing = 0; | |||||
std::string m_name; | |||||
uint64_t m_count = 0; | |||||
size_t m_enabled = 1; | |||||
bool m_default_enabled = true; | |||||
struct TimeScopeRecursive { | |||||
Timer& timer; | |||||
clock_t::time_point start; | |||||
bool released = false; | |||||
TimeScopeRecursive(Timer& timer) : timer(timer) { | |||||
if (timer.m_enabled && !timer.m_timing++) { | |||||
start = clock_t::now(); | |||||
} | |||||
} | |||||
~TimeScopeRecursive() { release(); } | |||||
void release() { | |||||
if (released) { | |||||
return; | |||||
} | |||||
if (timer.m_enabled) { | |||||
if (!--timer.m_timing) { | |||||
auto duration = (clock_t::now() - start); | |||||
timer.m_duration += duration; | |||||
} | |||||
timer.m_count++; | |||||
} | |||||
released = true; | |||||
} | |||||
}; | |||||
struct EnableScope { | |||||
Timer& timer; | |||||
bool released = false; | |||||
EnableScope(Timer& timer) : timer(timer) { timer.m_enabled++; } | |||||
~EnableScope() { release(); } | |||||
void release() { | |||||
if (released) { | |||||
return; | |||||
} | |||||
timer.m_enabled--; | |||||
released = true; | |||||
} | |||||
}; | |||||
public: | |||||
Timer(std::string name, bool default_enabled = true); | |||||
std::string name() { return m_name; } | |||||
auto time_scope_recursive() { return TimeScopeRecursive(*this); }; | |||||
auto enable_scope() { return EnableScope(*this); } | |||||
void reset() { | |||||
m_duration = clock_t::duration{0}; | |||||
m_count = 0; | |||||
m_enabled = m_default_enabled ? 1 : 0; | |||||
} | |||||
clock_t::duration get() const { return m_duration; } | |||||
uint64_t count() const { return m_count; } | |||||
}; | |||||
} // namespace stats | |||||
struct Stats { | |||||
struct TimerNode { | |||||
std::map<std::string, std::unique_ptr<TimerNode>> children; | |||||
stats::Timer* timer = nullptr; | |||||
TimerNode() {} | |||||
}; | |||||
static inline TimerNode sm_root; | |||||
// register your timers here | |||||
// for example: | |||||
// | |||||
// static inline stats::Timer mytimer; | |||||
// | |||||
// then use MGE_TIMER_SCOPE(mytimer) to collect durations in your code | |||||
static std::pair<long, long> print_node( | |||||
std::string name, TimerNode& node, size_t indent = 0) { | |||||
auto print_indent = [&] { | |||||
for (size_t i = 0; i < indent; ++i) { | |||||
printf(" "); | |||||
} | |||||
}; | |||||
long ns = 0, count = 0; | |||||
if (auto* timer = node.timer) { | |||||
print_indent(); | |||||
printf("%s costs %'ld ns, hits %'ld times\n", name.c_str(), | |||||
(long)timer->get().count(), (long)timer->count()); | |||||
ns = timer->get().count(); | |||||
count = timer->count(); | |||||
} | |||||
if (!node.children.empty()) { | |||||
bool collect_children = node.timer == nullptr; | |||||
if (collect_children) { | |||||
print_indent(); | |||||
printf("%s:\n", name.c_str()); | |||||
} | |||||
long ns = 0, count = 0; | |||||
for (auto&& child : node.children) { | |||||
auto [child_ns, child_count] = | |||||
print_node(child.first, *child.second, indent + 4); | |||||
if (collect_children) { | |||||
ns += child_ns; | |||||
count += child_count; | |||||
} | |||||
} | |||||
if (collect_children) { | |||||
print_indent(); | |||||
printf("total costs %'ld ns, hits %'ld times\n", ns, count); | |||||
} | |||||
} | |||||
return {ns, count}; | |||||
} | |||||
static void print() { | |||||
for (auto&& child : sm_root.children) { | |||||
print_node(child.first, *child.second); | |||||
} | |||||
} | |||||
static void reset() { | |||||
auto reset_node = [](TimerNode& node, auto&& reset_node) -> void { | |||||
if (auto* timer = node.timer) { | |||||
timer->reset(); | |||||
} | |||||
for (auto&& child : node.children) { | |||||
reset_node(*child.second, reset_node); | |||||
} | |||||
}; | |||||
reset_node(sm_root, reset_node); | |||||
} | |||||
}; | |||||
inline stats::Timer::Timer(std::string name, bool default_enabled) | |||||
: m_name(name), m_default_enabled(default_enabled) { | |||||
std::vector<std::string> terms; | |||||
Stats::TimerNode* node = &Stats::sm_root; | |||||
while (true) { | |||||
auto pos = name.find("."); | |||||
if (pos == std::string::npos) { | |||||
auto& child = node->children[name]; | |||||
child = std::make_unique<Stats::TimerNode>(); | |||||
node = child.get(); | |||||
node->timer = this; | |||||
break; | |||||
} else { | |||||
auto& child = node->children[name.substr(0, pos)]; | |||||
if (!child) { | |||||
child = std::make_unique<Stats::TimerNode>(); | |||||
} | |||||
node = child.get(); | |||||
name = name.substr(pos + 1); | |||||
} | |||||
} | |||||
} | |||||
#if MGE_ENABLE_STATS | |||||
#define MGE_TIMER_SCOPE(name) auto name = Stats::name.time_scope_recursive() | |||||
#define MGE_TIMER_SCOPE_RELEASE(name) name.release() | |||||
#define MGE_TIMER_SCOPE_ENABLE(name) auto name = Stats::name.enable_scope() | |||||
#else | |||||
#define MGE_TIMER_SCOPE(name) (void)0 | |||||
#define MGE_TIMER_SCOPE_RELEASE(name) (void)0 | |||||
#define MGE_TIMER_SCOPE_ENABLE(name) (void)0 | |||||
#endif | |||||
} // namespace imperative | |||||
} // namespace mgb |
@@ -23,7 +23,6 @@ | |||||
#include "megbrain/imperative/utils/debug.h" | #include "megbrain/imperative/utils/debug.h" | ||||
#include "megbrain/imperative/utils/local_ptr.h" | #include "megbrain/imperative/utils/local_ptr.h" | ||||
#include "megbrain/imperative/utils/span.h" | #include "megbrain/imperative/utils/span.h" | ||||
#include "megbrain/imperative/utils/stats.h" | |||||
namespace mgb { | namespace mgb { | ||||
namespace imperative { | namespace imperative { | ||||
@@ -0,0 +1,89 @@ | |||||
#include "megbrain/utils/stats.h" | |||||
namespace mgb { | |||||
Stats::TimerNode Stats::sm_root; | |||||
stats::Timer& Stats::get_timer(std::string name) { | |||||
auto full_name = name; | |||||
Stats::TimerNode* node = &Stats::sm_root; | |||||
while (true) { | |||||
auto pos = name.find("_"); | |||||
if (pos == std::string::npos) { | |||||
auto& child = node->children[name]; | |||||
child = std::make_unique<Stats::TimerNode>(); | |||||
node = child.get(); | |||||
auto& timer = node->timer; | |||||
if (!timer) { | |||||
timer = std::make_unique<stats::Timer>(full_name); | |||||
} | |||||
return *timer; | |||||
} else { | |||||
auto& child = node->children[name.substr(0, pos)]; | |||||
if (!child) { | |||||
child = std::make_unique<Stats::TimerNode>(); | |||||
} | |||||
node = child.get(); | |||||
name = name.substr(pos + 1); | |||||
} | |||||
} | |||||
} | |||||
std::pair<long, long> Stats::print_node( | |||||
std::string name, TimerNode& node, size_t indent) { | |||||
auto print_indent = [&] { | |||||
for (size_t i = 0; i < indent; ++i) { | |||||
printf(" "); | |||||
} | |||||
}; | |||||
long ns = 0, count = 0; | |||||
if (auto& timer = node.timer) { | |||||
print_indent(); | |||||
printf("%s costs %'ld ns, hits %'ld times\n", name.c_str(), | |||||
(long)timer->get().count(), (long)timer->count()); | |||||
ns = timer->get().count(); | |||||
count = timer->count(); | |||||
} | |||||
if (!node.children.empty()) { | |||||
bool collect_children = node.timer == nullptr; | |||||
if (collect_children) { | |||||
print_indent(); | |||||
printf("%s:\n", name.c_str()); | |||||
} | |||||
long ns = 0, count = 0; | |||||
for (auto&& child : node.children) { | |||||
auto&& child_res = print_node(child.first, *child.second, indent + 4); | |||||
auto&& child_ns = child_res.first; | |||||
auto&& child_count = child_res.second; | |||||
if (collect_children) { | |||||
ns += child_ns; | |||||
count += child_count; | |||||
} | |||||
} | |||||
if (collect_children) { | |||||
print_indent(); | |||||
printf("total costs %'ld ns, hits %'ld times\n", ns, count); | |||||
} | |||||
} | |||||
return {ns, count}; | |||||
} | |||||
void Stats::print() { | |||||
for (auto&& child : sm_root.children) { | |||||
print_node(child.first, *child.second); | |||||
} | |||||
} | |||||
void Stats::reset() { | |||||
auto reset_node = [](TimerNode& node, auto&& reset_node) -> void { | |||||
if (auto& timer = node.timer) { | |||||
timer->reset(); | |||||
} | |||||
for (auto&& child : node.children) { | |||||
reset_node(*child.second, reset_node); | |||||
} | |||||
}; | |||||
reset_node(sm_root, reset_node); | |||||
} | |||||
} // namespace mgb |
@@ -0,0 +1,135 @@ | |||||
#pragma once | |||||
#include <chrono> | |||||
#include <iostream> | |||||
#include <map> | |||||
#include <memory> | |||||
#include <string> | |||||
#include <unordered_map> | |||||
#include <vector> | |||||
#include "megbrain/common.h" | |||||
namespace mgb { | |||||
namespace stats { | |||||
#define MGE_ENABLE_STATS 1 | |||||
class Timer { | |||||
public: | |||||
using clock_t = std::chrono::system_clock; | |||||
private: | |||||
clock_t::duration m_duration = clock_t::duration{0}; | |||||
size_t m_timing = 0; | |||||
std::string m_name; | |||||
uint64_t m_count = 0; | |||||
size_t m_enabled = 1; | |||||
bool m_default_enabled = true; | |||||
struct TimeScopeRecursive { | |||||
Timer& timer; | |||||
clock_t::time_point start; | |||||
bool released = false; | |||||
TimeScopeRecursive(Timer& timer) : timer(timer) { | |||||
if (timer.m_enabled && !timer.m_timing++) { | |||||
start = clock_t::now(); | |||||
} | |||||
} | |||||
~TimeScopeRecursive() { release(); } | |||||
void release() { | |||||
if (released) { | |||||
return; | |||||
} | |||||
if (timer.m_enabled) { | |||||
if (!--timer.m_timing) { | |||||
auto duration = (clock_t::now() - start); | |||||
timer.m_duration += duration; | |||||
} | |||||
timer.m_count++; | |||||
} | |||||
released = true; | |||||
} | |||||
}; | |||||
struct EnableScope { | |||||
Timer& timer; | |||||
bool released = false; | |||||
EnableScope(Timer& timer) : timer(timer) { timer.m_enabled++; } | |||||
~EnableScope() { release(); } | |||||
void release() { | |||||
if (released) { | |||||
return; | |||||
} | |||||
timer.m_enabled--; | |||||
released = true; | |||||
} | |||||
}; | |||||
public: | |||||
Timer(std::string name, bool default_enabled = true) | |||||
: m_name(name), m_default_enabled(default_enabled){}; | |||||
std::string name() { return m_name; } | |||||
auto time_scope_recursive() { return TimeScopeRecursive(*this); }; | |||||
auto enable_scope() { return EnableScope(*this); } | |||||
void reset() { | |||||
m_duration = clock_t::duration{0}; | |||||
m_count = 0; | |||||
m_enabled = m_default_enabled ? 1 : 0; | |||||
} | |||||
clock_t::duration get() const { return m_duration; } | |||||
uint64_t count() const { return m_count; } | |||||
}; | |||||
} // namespace stats | |||||
struct Stats { | |||||
private: | |||||
struct TimerNode { | |||||
std::map<std::string, std::unique_ptr<TimerNode>> children; | |||||
std::unique_ptr<stats::Timer> timer; | |||||
}; | |||||
static TimerNode sm_root; | |||||
// don't register your timers here | |||||
// use MGE_TIMER_SCOPE(mytimer) to collect durations in your code | |||||
public: | |||||
MGE_WIN_DECLSPEC_FUC static stats::Timer& get_timer(std::string name); | |||||
MGE_WIN_DECLSPEC_FUC static std::pair<long, long> print_node( | |||||
std::string name, TimerNode& node, size_t indent = 0); | |||||
MGE_WIN_DECLSPEC_FUC static void print(); | |||||
MGE_WIN_DECLSPEC_FUC static void reset(); | |||||
}; | |||||
#if MGE_ENABLE_STATS | |||||
#define MGE_TIMER_SCOPE(name) \ | |||||
static auto& _timer_##name = mgb::Stats::get_timer(#name); \ | |||||
auto name = _timer_##name.time_scope_recursive() | |||||
#define MGE_TIMER_SCOPE_RELEASE(name) name.release() | |||||
#define MGE_TIMER_SCOPE_ENABLE(name) \ | |||||
static auto& _timer_##name = mgb::Stats::get_timer(#name); \ | |||||
auto name = _timer_##name.enable_scope() | |||||
#else | |||||
#define MGE_TIMER_SCOPE(name) (void)0 | |||||
#define MGE_TIMER_SCOPE_RELEASE(name) (void)0 | |||||
#define MGE_TIMER_SCOPE_ENABLE(name) (void)0 | |||||
#endif | |||||
} // namespace mgb |