@@ -2,12 +2,14 @@ import collections | |||||
import contextlib | import contextlib | ||||
import functools | import functools | ||||
import itertools | import itertools | ||||
import json | |||||
import typing | import typing | ||||
import warnings | import warnings | ||||
import weakref | import weakref | ||||
import numpy as np | import numpy as np | ||||
from ..core._imperative_rt import GraphProfiler | |||||
from ..core.ops.special import Const | from ..core.ops.special import Const | ||||
from ..core.tensor import megbrain_graph as G | from ..core.tensor import megbrain_graph as G | ||||
from ..core.tensor.core import OpBase, TensorBase, TensorWrapperBase, apply | from ..core.tensor.core import OpBase, TensorBase, TensorWrapperBase, apply | ||||
@@ -85,11 +87,14 @@ class trace: | |||||
symbolic=False, | symbolic=False, | ||||
capture_as_const=False, | capture_as_const=False, | ||||
sublinear_memory_config: SublinearMemoryConfig = None, | sublinear_memory_config: SublinearMemoryConfig = None, | ||||
profiling: bool = False, | |||||
): | ): | ||||
self.__wrapped__ = function | self.__wrapped__ = function | ||||
self._symbolic = symbolic | self._symbolic = symbolic | ||||
self._capture_as_const = capture_as_const | self._capture_as_const = capture_as_const | ||||
self._sublinear_memory_config = sublinear_memory_config | self._sublinear_memory_config = sublinear_memory_config | ||||
self._profiling = profiling | |||||
self._profiler = None | |||||
self._untraced = True | self._untraced = True | ||||
self._tinfo = [] # handle -> TensorInfo | self._tinfo = [] # handle -> TensorInfo | ||||
@@ -308,6 +313,8 @@ class trace: | |||||
) | ) | ||||
sublinear_config.thresh_nr_try = self._sublinear_memory_config.thresh_nr_try | sublinear_config.thresh_nr_try = self._sublinear_memory_config.thresh_nr_try | ||||
sublinear_config.num_worker = self._sublinear_memory_config.num_worker | sublinear_config.num_worker = self._sublinear_memory_config.num_worker | ||||
if self._profiling: | |||||
self._profiler = GraphProfiler(graph) | |||||
def _compile(self): | def _compile(self): | ||||
graph = self._graph = G.Graph() | graph = self._graph = G.Graph() | ||||
@@ -581,6 +588,16 @@ class trace: | |||||
% (output_names and output_names[i] or i) | % (output_names and output_names[i] or i) | ||||
) | ) | ||||
def get_profile(self): | |||||
""" | |||||
Get profiling result for compiled trace. | |||||
:return: a json compatible object. | |||||
""" | |||||
if not self._profiler: | |||||
raise RuntimeError("trace is not set with profiling=True") | |||||
return json.loads(self._profiler.get()) | |||||
class CompiledTensorProxy(RawTensor): | class CompiledTensorProxy(RawTensor): | ||||
""" | """ | ||||
@@ -11,18 +11,38 @@ | |||||
#include "./graph_rt.h" | #include "./graph_rt.h" | ||||
#include "megbrain/graph/cg.h" | |||||
#include "megbrain/serialization/serializer.h" | #include "megbrain/serialization/serializer.h" | ||||
#include "megbrain/imperative/opr_utility.h" | #include "megbrain/imperative/opr_utility.h" | ||||
#include "megbrain/opr/io.h" | #include "megbrain/opr/io.h" | ||||
#include "megbrain/opr/basic_arith.h" | #include "megbrain/opr/basic_arith.h" | ||||
#include "megbrain/imperative.h" | #include "megbrain/imperative.h" | ||||
#include "./helper.h" | #include "./helper.h" | ||||
#include "megbrain/plugin/profiler.h" | |||||
namespace py = pybind11; | namespace py = pybind11; | ||||
using namespace mgb; | using namespace mgb; | ||||
using namespace imperative; | using namespace imperative; | ||||
namespace { | |||||
class _CompGraphProfilerImpl { | |||||
std::shared_ptr<ComputingGraph> m_comp_graph; | |||||
GraphProfiler m_profiler; | |||||
public: | |||||
_CompGraphProfilerImpl(std::shared_ptr<ComputingGraph> cg): | |||||
m_comp_graph{cg}, | |||||
m_profiler{m_comp_graph.get()} | |||||
{ | |||||
} | |||||
std::string _get_result() { | |||||
auto json = m_profiler.to_json_full( | |||||
m_comp_graph->current_comp_seq()); | |||||
return json->to_string(); | |||||
} | |||||
}; | |||||
} | |||||
#define DEF_READWRITE(name) .def_readwrite(#name, &CURRENT_CLASS::name) | #define DEF_READWRITE(name) .def_readwrite(#name, &CURRENT_CLASS::name) | ||||
template<typename T> | template<typename T> | ||||
@@ -102,6 +122,12 @@ void init_graph_rt(py::module m) { | |||||
}) | }) | ||||
.def_property_readonly("options", py::overload_cast<>(&cg::ComputingGraph::options)); | .def_property_readonly("options", py::overload_cast<>(&cg::ComputingGraph::options)); | ||||
py::class_<_CompGraphProfilerImpl, std::shared_ptr<_CompGraphProfilerImpl>>(m, "GraphProfiler") | |||||
.def(py::init([](std::shared_ptr<ComputingGraph> graph) { | |||||
return std::make_shared<_CompGraphProfilerImpl>(graph); | |||||
})) | |||||
.def("get", [](_CompGraphProfilerImpl& profiler) { return profiler._get_result(); }); | |||||
m.def("dump_graph", [](const std::vector<VarNode*>& dest_vars) { | m.def("dump_graph", [](const std::vector<VarNode*>& dest_vars) { | ||||
using namespace mgb::serialization; | using namespace mgb::serialization; | ||||
std::vector<uint8_t> buf; | std::vector<uint8_t> buf; | ||||
@@ -82,3 +82,22 @@ def test_dump(): | |||||
file = io.BytesIO() | file = io.BytesIO() | ||||
f.dump(file) | f.dump(file) | ||||
def test_trace_profiler(): | |||||
for symbolic in [False, True]: | |||||
@trace(symbolic=symbolic, profiling=True) | |||||
def f(x): | |||||
op = ops.Elemwise(mode="negate") | |||||
(y,) = apply(op, x) | |||||
return y | |||||
x = as_raw_tensor([1]).numpy() | |||||
y = f.__wrapped__(as_raw_tensor(x)).numpy() | |||||
f(as_raw_tensor(x)) | |||||
f(as_raw_tensor(x)) # XXX: has to run twice | |||||
out = f.get_profile() | |||||
assert out.get("profiler") |