Skip to content

Commit be94c95

Browse files
committed
[Relay][VM]VM debugger
1 parent d14ca52 commit be94c95

File tree

9 files changed

+374
-6
lines changed

9 files changed

+374
-6
lines changed

CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,12 @@ if(USE_GRAPH_RUNTIME)
198198
endif(USE_GRAPH_RUNTIME_DEBUG)
199199
endif(USE_GRAPH_RUNTIME)
200200

201+
message(STATUS "Build with Relay VM debug support...")
202+
file(GLOB RUNTIME_VM_DEBUG_SRCS src/runtime/vm/debug/*.cc)
203+
list(APPEND RUNTIME_SRCS ${RUNTIME_VM_DEBUG_SRCS})
204+
set_source_files_properties(${RUNTIME_GRAPH_SRCS}
205+
PROPERTIES COMPILE_DEFINITIONS "TVM_VM_RUNTIME_DEBUG")
206+
201207
# Module rules
202208
include(cmake/modules/VTA.cmake)
203209
include(cmake/modules/CUDA.cmake)

include/tvm/runtime/vm.h

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,41 @@ struct VMFrame {
375375
*/
376376
class VirtualMachine : public runtime::ModuleNode {
377377
public:
378-
PackedFunc GetFunction(const std::string& name,
379-
const std::shared_ptr<ModuleNode>& sptr_to_self) final;
378+
/*!
379+
* \brief Get a PackedFunc from module.
380+
*
381+
* The PackedFunc may not be fully initialized,
382+
* there might still be first time running overhead when
383+
* executing the function on certain devices.
384+
* For benchmarking, use prepare to eliminate
385+
*
386+
* \param name the name of the function.
387+
* \param sptr_to_self The shared_ptr that points to this module node.
388+
*
389+
* \return PackedFunc(nullptr) when it is not available.
390+
*
391+
* \note The function will always remain valid.
392+
* If the function need resource from the module(e.g. late linking),
393+
* it should capture sptr_to_self.
394+
*/
395+
virtual PackedFunc GetFunction(const std::string& name,
396+
const std::shared_ptr<ModuleNode>& sptr_to_self);
397+
398+
/*!
399+
* \brief Invoke a PackedFunction
400+
*
401+
* \param packed_index The offset of the PackedFunction in all functions.
402+
* \param func The PackedFunction to be invoked.
403+
* \param arg_count The number of arguments to the PackedFunction.
404+
* \param output_size The number of outputs of the PackedFunction.
405+
* \param args Arguments to the PackedFunction.
406+
*
407+
* \note The return value will be stored in the last output_size slots of args.
408+
*/
409+
virtual void InvokePacked(Index packed_index, const PackedFunc& func, Index arg_count,
410+
Index output_size, const std::vector<Object>& args);
411+
412+
virtual ~VirtualMachine() {}
380413

381414
const char* type_key() const final {
382415
return "VirtualMachine";

python/tvm/relay/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
from . import param_dict
3535
from . import feature
3636
from .backend import vm
37+
from .backend import debug_vm
3738
from .backend import serializer
3839
from .backend import deserializer
3940
from .backend import vmobj
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# License .to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
# pylint: disable=no-else-return, unidiomatic-typecheck, undefined-variable, invalid-name
18+
"""
19+
The debug Relay Virtual Machine.
20+
21+
Provides extra APIs for debugging vm execution.
22+
"""
23+
import tvm
24+
from . import vm, _vm
25+
26+
def _update_target(target):
27+
target = target if target else tvm.target.current_target()
28+
if target is None:
29+
raise ValueError("Target is not set in env or passed as argument.")
30+
31+
tgts = {}
32+
if isinstance(target, (str, tvm.target.Target)):
33+
dev_type = tvm.expr.IntImm("int32", tvm.nd.context(str(target)).device_type)
34+
tgts[dev_type] = tvm.target.create(target)
35+
elif isinstance(target, dict):
36+
for dev, tgt in target.items():
37+
dev_type = tvm.expr.IntImm("int32", tvm.nd.context(dev).device_type)
38+
tgts[dev_type] = tvm.target.create(tgt)
39+
else:
40+
raise TypeError("target is expected to be str, tvm.target.Target, " +
41+
"or dict of str to str/tvm.target.Target, but received " +
42+
"{}".format(type(target)))
43+
return tgts
44+
45+
class VMCompilerDebug(object):
46+
"""Build Relay module to run on VM runtime."""
47+
def __init__(self):
48+
self.mod = _vm._VMCompilerDebug()
49+
self._compile = self.mod["compile"]
50+
self._get_vm = self.mod["get_vm"]
51+
52+
def compile(self, mod, target=None, target_host=None):
53+
"""
54+
Parameters
55+
----------
56+
mod : relay.Module
57+
The Relay module to build.
58+
59+
target : str, :any:`tvm.target.Target`, or dict of str(i.e.
60+
device/context name) to str/tvm.target.Target, optional
61+
For heterogeneous compilation, it is a dictionary indicating context
62+
to target mapping. For homogeneous compilation, it is a build target.
63+
64+
target_host : str or :any:`tvm.target.Target`, optional
65+
Host compilation target, if target is device.
66+
When TVM compiles device specific program such as CUDA,
67+
we also need host(CPU) side code to interact with the driver
68+
to setup the dimensions and parameters correctly.
69+
target_host is used to specify the host side codegen target.
70+
By default, llvm is used if it is enabled,
71+
otherwise a stackvm intepreter is used.
72+
73+
Returns
74+
-------
75+
vm : VirtualMachineDebug
76+
The debug VM runtime.
77+
"""
78+
target = _update_target(target)
79+
self._compile(mod, target, target_host)
80+
return VirtualMachineDebug(self._get_vm())
81+
82+
class VirtualMachineDebug(vm.VirtualMachine):
83+
"""Relay debug VM runtime."""
84+
def __init__(self, mod):
85+
super().__init__(mod)
86+
self._get_stat = self.mod["get_stat"]
87+
88+
def get_stat(self):
89+
return self._get_stat()

src/relay/backend/vm/compiler.cc

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include <unordered_map>
3434
#include <unordered_set>
3535
#include <vector>
36+
#include "../../../runtime/vm/debug/debug_vm.h"
3637
#include "../../../runtime/vm/naive_allocator.h"
3738
#include "../../backend/compile_engine.h"
3839
#include "../../pass/pass_util.h"
@@ -666,6 +667,7 @@ class VMFunctionCompiler : ExprFunctor<void(const Expr& expr)> {
666667

667668
class VMCompiler : public runtime::ModuleNode {
668669
public:
670+
virtual ~VMCompiler() {}
669671
PackedFunc GetFunction(const std::string& name,
670672
const std::shared_ptr<ModuleNode>& sptr_to_self) final {
671673
if (name == "compile") {
@@ -691,14 +693,20 @@ class VMCompiler : public runtime::ModuleNode {
691693
return vm_;
692694
}
693695

696+
697+
virtual void InitVM() {
698+
vm_ = std::make_shared<VirtualMachine>();
699+
}
700+
694701
void Compile(const Module& mod_ref,
695702
const TargetsMap& targets,
696703
const tvm::Target& target_host) {
697704
CHECK_EQ(targets.size(), 1)
698705
<< "Currently VM compiler doesn't support heterogeneous compilation";
706+
707+
InitVM();
699708
targets_ = targets;
700709
target_host_ = target_host;
701-
vm_ = std::make_shared<VirtualMachine>();
702710

703711
// Run some optimizations first, this code should
704712
// be moved to pass manager.
@@ -821,6 +829,28 @@ TVM_REGISTER_GLOBAL("relay._vm._VMCompiler")
821829
*rv = CreateVMCompiler();
822830
});
823831

832+
833+
class VMCompilerDebug : public VMCompiler {
834+
public:
835+
VMCompilerDebug() {}
836+
837+
void InitVM() override {
838+
vm_ = std::make_shared<VirtualMachineDebug>();
839+
}
840+
841+
virtual ~VMCompilerDebug() {}
842+
};
843+
844+
runtime::Module CreateVMCompilerDebug() {
845+
std::shared_ptr<VMCompilerDebug> exec = std::make_shared<VMCompilerDebug>();
846+
return runtime::Module(exec);
847+
}
848+
849+
TVM_REGISTER_GLOBAL("relay._vm._VMCompilerDebug")
850+
.set_body([](TVMArgs args, TVMRetValue* rv) {
851+
*rv = CreateVMCompilerDebug();
852+
});
853+
824854
} // namespace vm
825855
} // namespace relay
826856
} // namespace tvm

src/runtime/vm/debug/debug_vm.cc

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* Copyright (c) 2019 by Contributors
22+
* \file src/runtime/vm/debug/vm_debug.cc
23+
* \brief The Relay debug virtual machine.
24+
*/
25+
26+
#include <tvm/runtime/registry.h>
27+
#include <tvm/runtime/vm.h>
28+
29+
#include <iomanip>
30+
#include <memory>
31+
#include <string>
32+
#include <vector>
33+
34+
#include "debug_vm.h"
35+
36+
namespace tvm {
37+
namespace runtime {
38+
namespace vm {
39+
40+
PackedFunc VirtualMachineDebug::GetFunction(
41+
const std::string& name, const std::shared_ptr<ModuleNode>& sptr_to_self) {
42+
if (name == "get_stat") {
43+
return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
44+
double total_duration = 0.0;
45+
std::ostringstream os;
46+
os << std::setw(30) << std::left << "#OpName"
47+
<< "\t" << std::setw(10) << std::left << "#InvokeCount"
48+
<< "\t"
49+
<< "#Duration(us)" << std::endl;
50+
51+
for (auto kv : op_durations) {
52+
os << std::setw(30) << std::left << packed_index_map[kv.first] << "\t"
53+
<< std::setw(10) << std::left << op_invokes[kv.first] << "\t"
54+
<< op_durations[kv.first] << std::endl;
55+
56+
total_duration += op_durations[kv.first];
57+
}
58+
os << "Total Duration " << total_duration << " us" << std::endl;
59+
*rv = os.str();
60+
});
61+
} else if (name == "init") {
62+
return PackedFunc([sptr_to_self, this](TVMArgs args, TVMRetValue* rv) {
63+
CHECK_EQ(args.size() % 2, 0);
64+
std::vector<TVMContext> contexts;
65+
for (int i = 0; i < args.size() / 2; ++i) {
66+
TVMContext ctx;
67+
int device_type = args[i * 2];
68+
ctx.device_type = DLDeviceType(device_type);
69+
ctx.device_id = args[i * 2 + 1];
70+
contexts.push_back(ctx);
71+
}
72+
this->Init(contexts);
73+
});
74+
} else {
75+
return VirtualMachine::GetFunction(name, sptr_to_self);
76+
}
77+
}
78+
79+
void VirtualMachineDebug::Init(const std::vector<TVMContext>& ctxs) {
80+
VirtualMachine::Init(ctxs);
81+
for (auto kv : primitive_map) {
82+
packed_index_map[kv.second] = kv.first;
83+
op_durations[kv.second] = 0.0;
84+
op_invokes[kv.second] = 0;
85+
}
86+
}
87+
88+
void VirtualMachineDebug::InvokePacked(Index packed_index,
89+
const PackedFunc& func, Index arg_count,
90+
Index output_size,
91+
const std::vector<Object>& args) {
92+
auto op_begin = std::chrono::high_resolution_clock::now();
93+
VirtualMachine::InvokePacked(packed_index, func, arg_count, output_size,
94+
args);
95+
auto op_end = std::chrono::high_resolution_clock::now();
96+
double op_duration =
97+
std::chrono::duration_cast<std::chrono::duration<double> >(op_end -
98+
op_begin)
99+
.count();
100+
101+
op_durations[packed_index] += op_duration * 1e6;
102+
op_invokes[packed_index] += 1;
103+
}
104+
105+
} // namespace vm
106+
} // namespace runtime
107+
} // namespace tvm

src/runtime/vm/debug/debug_vm.h

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
/*!
21+
* Copyright (c) 2019 by Contributors
22+
* \file src/runtime/vm/debug/debug_vm.h
23+
* \brief The Relay debug virtual machine.
24+
*/
25+
26+
#ifndef TVM_RUNTIME_VM_DEBUG_DEBUG_VM_H_
27+
#define TVM_RUNTIME_VM_DEBUG_DEBUG_VM_H_
28+
29+
#include <tvm/runtime/vm.h>
30+
31+
#include <memory>
32+
#include <string>
33+
#include <unordered_map>
34+
#include <vector>
35+
36+
namespace tvm {
37+
namespace runtime {
38+
namespace vm {
39+
40+
class VirtualMachineDebug : public VirtualMachine {
41+
public:
42+
VirtualMachineDebug() : VirtualMachine() {}
43+
44+
PackedFunc GetFunction(const std::string& name,
45+
const std::shared_ptr<ModuleNode>& sptr_to_self) final;
46+
47+
void InvokePacked(Index packed_index, const PackedFunc& func, Index arg_count,
48+
Index output_size, const std::vector<Object>& args) final;
49+
50+
~VirtualMachineDebug() {}
51+
52+
private:
53+
void Init(const std::vector<TVMContext>& ctxs);
54+
55+
std::unordered_map<Index, std::string> packed_index_map;
56+
std::unordered_map<Index, double> op_durations;
57+
std::unordered_map<Index, int> op_invokes;
58+
};
59+
60+
} // namespace vm
61+
} // namespace runtime
62+
} // namespace tvm
63+
64+
#endif // TVM_RUNTIME_VM_DEBUG_DEBUG_VM_H_

0 commit comments

Comments
 (0)