GitOrigin-RevId: 7d86e5f257
tags/v1.10.0
| @@ -14,7 +14,6 @@ | |||
| #include <list> | |||
| #include "megbrain/imperative/transformations/trace.h" | |||
| #include "megbrain/imperative/utils/map.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| #include "./tensor.h" | |||
| @@ -23,9 +23,9 @@ | |||
| #include "megbrain/imperative/transformations/symbol.h" | |||
| #include "megbrain/imperative/transformations/trace.h" | |||
| #include "megbrain/imperative/utils/map.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| #include "megbrain/opr/io.h" | |||
| #include "megbrain/plugin/profiler.h" | |||
| #include "megbrain/utils/stats.h" | |||
| #include "./common.h" | |||
| #include "./grad.h" | |||
| @@ -1367,9 +1367,9 @@ void init_tensor(py::module m) { | |||
| 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", | |||
| []() -> bool { return DTypePromoteCfg::convert_input_enabled; }); | |||
| @@ -21,7 +21,6 @@ | |||
| #include "megbrain/imperative/transformations/symbol.h" | |||
| #include "megbrain/imperative/transformations/trace.h" | |||
| #include "megbrain/imperative/utils/map.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| #include "megbrain/opr/io.h" | |||
| #include "megbrain/plugin/profiler.h" | |||
| @@ -14,7 +14,6 @@ | |||
| #include "megbrain/imperative/utils/debug.h" | |||
| #include "megbrain/imperative/utils/helper.h" | |||
| #include "megbrain/imperative/utils/map.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| namespace mgb { | |||
| namespace imperative { | |||
| @@ -19,7 +19,6 @@ | |||
| #include "megbrain/imperative/ops/backward_graph.h" | |||
| #include "megbrain/imperative/ops/opr_attr.h" | |||
| #include "megbrain/imperative/ops/utility.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| #include "megbrain/imperative/utils/to_string.h" | |||
| #include "../blob_manager_impl.h" | |||
| @@ -11,7 +11,6 @@ | |||
| #include "megbrain/imperative/opr_utility.h" | |||
| #include "megbrain/imperative/ops/autogen.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| #include "megbrain/opr/basic_arith.h" | |||
| #include "megbrain/opr/utility.h" | |||
| @@ -11,7 +11,6 @@ | |||
| #include "megbrain/opr/dnn/pooling.h" | |||
| #include "megbrain/imperative/ops/autogen.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| #include "megbrain/opr/utility.h" | |||
| #include "megbrain/opr/internal/megdnn_opr_wrapper.h" | |||
| @@ -1,5 +1,4 @@ | |||
| #include "megbrain/imperative/transformation.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| namespace mgb { | |||
| namespace imperative { | |||
| @@ -10,7 +10,6 @@ | |||
| */ | |||
| #include "megbrain/imperative/transformations/eval.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| namespace mgb { | |||
| namespace imperative { | |||
| @@ -15,7 +15,6 @@ | |||
| #include "megbrain/imperative/graph_cache.h" | |||
| #include "megbrain/imperative/resource_manager.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| #include <range/v3/all.hpp> | |||
| @@ -13,7 +13,6 @@ | |||
| #include "megbrain/imperative/ops/autogen.h" | |||
| #include "megbrain/imperative/ops/utility.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| namespace mgb { | |||
| 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/local_ptr.h" | |||
| #include "megbrain/imperative/utils/span.h" | |||
| #include "megbrain/imperative/utils/stats.h" | |||
| namespace mgb { | |||
| 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 | |||