Refine api trace code and document (#634)
* Add support for different input dtype of MaxPoolGrad. Type: Code improvement * Integrate api trace into tim-vx source code, as part of experimeantal. Type: New Feature * Refine api trace code and document Add missing traced apis of tim::vx::Quantization Type: Code improvement
This commit is contained in:
parent
2f018cc088
commit
cf2efc63fd
|
|
@ -2,6 +2,14 @@
|
|||
|
||||
ApiTracer is a header only library provides macros and template functions to trace the C++ object-oriented programs, it not only trace the call-stacks, but also trace the C++ Apis runtime parameters. With the trace log and binary, it's convenient to replay the program execute scene, which helps developer to reproduce bugs and debug.
|
||||
|
||||
## Usage
|
||||
There is a simple case using api trace in `src/tim/vx/graph_test.cc` which named trace_test, follow those steps:
|
||||
1. You need set the cmake option `-DTIM_VX_ENABLE_API_TRACE=1` at first, and rebuild;
|
||||
2. Setting up the run time environments for tim-vx, then execute `$build/install/bin/unit-test --gtest_filter=*trace_test*`;
|
||||
3. `trace_log.cc` and `trace_bin.bin` will generate in the workspace, first one is the tim-vx code record the all api calls and function's runtime parameters, second one is serializable data like std::vector data. You can set the environment `TRACE_DUMP_PREFIX` to control will to dump those file;
|
||||
4. Copy `trace_log.cc` to the root of tim-vx source code, and rename it with `trace_log.rpl.cc`, then follow the guide in `src/tim/vx/graph_test.cc`.
|
||||
5. Rebuild unit-test, execute `$build/install/bin/unit-test --gtest_filter=*replay_test*`, you will get the exactly same result with traced execution.
|
||||
|
||||
## Coding work
|
||||
ApiTracer was implemented by warp original Apis in traced Apis, they got same class names, same function names, but different namespace. So you need implement the traced Apis for specific programs at first.
|
||||
|
||||
|
|
@ -41,6 +49,8 @@ namespace trace {
|
|||
struct TensorSpec : public TraceClassBase<target::TensorSpec> {
|
||||
DEF_CONSTRUCTOR(TensorSpec)
|
||||
|
||||
// define constructor with boost seq arguments, do not need specific the
|
||||
// parameter name, it's auto generate like param_0, param_1, ...
|
||||
DEF_CONSTRUCTOR(TensorSpec, ((DataType))
|
||||
((const ShapeType&))
|
||||
((TensorAttribute))
|
||||
|
|
@ -55,6 +65,10 @@ struct TensorSpec : public TraceClassBase<target::TensorSpec> {
|
|||
DEF_CONSTRUCTOR(TensorSpec, ((const TensorSpec&))
|
||||
)
|
||||
|
||||
// Using DEF_TRACED_API is a more radical way, you only need specific the api
|
||||
// return type and the api name, api arguments will automatically match by the
|
||||
// template arguments variadic.
|
||||
// But it's not fully around now, see next section of it's restrict.
|
||||
DEF_TRACED_API(TensorSpec&, operator=)
|
||||
|
||||
DEF_TRACED_API(TensorSpec&, SetDataType)
|
||||
|
|
@ -70,13 +84,27 @@ struct TensorSpec : public TraceClassBase<target::TensorSpec> {
|
|||
### Macros definition
|
||||
- DEF_CONSTRUCTOR(class_name, optional_arguments_description, optional_macro_to_handle_pointer):
|
||||
arguments_description must follow the format `((arg0))((arg1)(arg1_default_value))`
|
||||
|
||||
- DEF_TRACED_API(return_type, member_function_name, optional_lambda_to_handle_pointer):
|
||||
this macro can define most member functions, except:
|
||||
- function with default parameters
|
||||
- static functions
|
||||
- readonly functions
|
||||
|
||||
- DEF_MEMFN_SP(return_type_removed_shared_pointer, member_function_name,optional_arguments_description, optional_macro_to_handle_pointer):
|
||||
- DEF_MEMFN_SP(return_type_removed_shared_pointer, member_function_name, optional_arguments_description, optional_macro_to_handle_pointer):
|
||||
the macro can define those functions with `shared_ptr<TracedClass>`
|
||||
- DEF_MEMFN(return_type, member_function_name, optional_arguments_description, optional_macro_to_handle_pointer)
|
||||
- DEF_INPLACE_MEMFN(member_function_name, optional_arguments_description, optional_macro_to_handle_pointer)
|
||||
|
||||
- DEF_MEMFN(return_type, member_function_name, optional_arguments_description, optional_macro_to_handle_pointer):
|
||||
to define normal member functions
|
||||
|
||||
- DEF_INPLACE_MEMFN(member_function_name, optional_arguments_description, optional_macro_to_handle_pointer):
|
||||
to define those apis retval is the object itself
|
||||
|
||||
- DEF_SIMPLE_UNTRACED_API(retval, api_name):
|
||||
to define those apis without argument and have no side effect on the graph compile and execution, like `Tensor::GetId()`
|
||||
|
||||
## Meta programming reference
|
||||
api trace utilize some meta programming tricks, here are some reference:
|
||||
1. Boost C/C++ preprocessor - https://www.boost.org/doc/libs/1_82_0/libs/preprocessor/doc/index.html
|
||||
2. std meta programming library - https://en.cppreference.com/w/cpp/meta
|
||||
3. Boost hana meta programming library - https://www.boost.org/doc/libs/1_82_0/libs/hana/doc/html/index.html
|
||||
|
|
|
|||
|
|
@ -780,7 +780,7 @@ static const char* target_namespace_name_ = TARGET_NAMESPACE_NAME;
|
|||
std::string obj_name = \
|
||||
Tracer::allocate_obj_name(Tracer::get_obj_prefix(#class_name)); \
|
||||
Tracer::logging_msg("auto %s = %s::%s();\n", obj_name.c_str(), \
|
||||
target_namespace_name_, __FUNCTION__); \
|
||||
target_namespace_name_, __FUNCTION__); \
|
||||
impl_ = std::make_shared<target::class_name>(); \
|
||||
Tracer::insert_traced_obj( \
|
||||
static_cast<void*>(impl_.get()), static_cast<void*>(this)); \
|
||||
|
|
@ -873,7 +873,7 @@ static const char* target_namespace_name_ = TARGET_NAMESPACE_NAME;
|
|||
Args... params) { \
|
||||
std::string this_obj_name = TraceGetObjName(); \
|
||||
Tracer::push_back_msg_cache( \
|
||||
this_obj_name + "->" + __FUNCTION__ + "("); \
|
||||
this_obj_name + "." + __FUNCTION__ + "("); \
|
||||
Tracer::clear_params_log_cache(); \
|
||||
boost::hana::tuple<Args...> params_tuple = {params...}; \
|
||||
boost::hana::for_each(params_tuple, [&] (auto x) { \
|
||||
|
|
|
|||
|
|
@ -130,9 +130,10 @@ struct Graph : public TraceClassBase<target::Graph> {
|
|||
Tracer::amend_last_msg_cache(");\n");
|
||||
Tracer::msg_cache_sync_to_file();
|
||||
|
||||
// ToDo: the feature to use fake network weights need further refine.
|
||||
#if 1 /* if use fake input data */
|
||||
if (param_0.TraceGetImpl().GetTensorAttribute() ==
|
||||
TensorAttribute::TRANSIENT && param_1 == nullptr) {
|
||||
TensorAttribute::CONSTANT && param_1 == nullptr) {
|
||||
auto fake_vec_name = Tracer::allocate_obj_name("fake_vec_");
|
||||
switch (param_0.TraceGetImpl().GetDataType()) {
|
||||
case DataType::INT32:
|
||||
|
|
@ -313,7 +314,7 @@ struct Graph : public TraceClassBase<target::Graph> {
|
|||
|
||||
DEF_TRACED_API(void, UpdateTensorProducerMap)
|
||||
|
||||
// DEF_TRACED_API(cosnt std::vector<std::shared_ptr<Operation>>, GetConsumersOp)
|
||||
// DEF_TRACED_API(const std::vector<std::shared_ptr<Operation>>, GetConsumersOp)
|
||||
|
||||
// DEF_TRACED_API(std::shared_ptr<Operation>, GetProducerOp)
|
||||
|
||||
|
|
@ -329,21 +330,27 @@ struct Graph : public TraceClassBase<target::Graph> {
|
|||
std::vector<TensorSpec> spec_keeper_;
|
||||
|
||||
DECL_CREATE_OPS(TVX_OPS_SEQ)
|
||||
DECL_CREATE_OP_IMPL_(_, _, Pad)
|
||||
DECL_CREATE_OP_IMPL_(_, _, PadV2)
|
||||
DECL_CREATE_OP_IMPL_(_, _, Pad) // there are enums defined in the op
|
||||
DECL_CREATE_OP_IMPL_(_, _, PadV2) // there are enums defined in the op
|
||||
|
||||
};
|
||||
#define SPECIAL_MACRO_(params) \
|
||||
std::string buf_name = Tracer::allocate_obj_name("nbg_buf_vec_"); \
|
||||
FILE* nbg_dumped = fopen("network_binary_graph.nb", "r"); \
|
||||
fseek(nbg_dumped, 0L, SEEK_END); \
|
||||
uint32_t count = ftell(nbg_dumped); \
|
||||
fclose(nbg_dumped); \
|
||||
uint32_t offset = Tracer::dump_data( \
|
||||
BOOST_PP_SEQ_ELEM(0, params), sizeof(char), count); \
|
||||
Tracer::insert_before_last_msg_cache("std::vector<char> " + buf_name + \
|
||||
" = trace::Replayer::get_vector<char>(" + std::to_string(offset) + \
|
||||
"," + std::to_string(count) + ");\n"); \
|
||||
// For the NBG op, has no good enough way to get the nbg buffer size in the
|
||||
// scope of `CreateOperation<tim::vx::ops::NBG>(buf, inp_num, out_num)`, so
|
||||
// we enable `export VIV_VX_ENABLE_DUMP_NBG=1` to dump nbg at first, then read
|
||||
// it's size.
|
||||
// The best solution is make nbg buf self-analytic the size.
|
||||
// ToDo: push nbg team provide an api to self-analytic the nbg size.
|
||||
#define SPECIAL_MACRO_(params) \
|
||||
std::string buf_name = Tracer::allocate_obj_name("nbg_buf_vec_"); \
|
||||
FILE* nbg_dumped = fopen("network_binary_graph.nb", "r"); \
|
||||
fseek(nbg_dumped, 0L, SEEK_END); \
|
||||
uint32_t count = ftell(nbg_dumped); \
|
||||
fclose(nbg_dumped); \
|
||||
uint32_t offset = Tracer::dump_data( \
|
||||
BOOST_PP_SEQ_ELEM(0, params), sizeof(char), count); \
|
||||
Tracer::insert_before_last_msg_cache("std::vector<char> " + buf_name + \
|
||||
" = trace::Replayer::get_vector<char>(" + std::to_string(offset) + \
|
||||
"," + std::to_string(count) + ");\n"); \
|
||||
Tracer::insert_params_log_cache(buf_name + ".data()", 0);
|
||||
|
||||
SPECIALIZATION_CREATE_OP(NBG, ((const char*))((size_t))((size_t)),
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ struct Quantization : public TraceClassBase<target::Quantization> {
|
|||
DEF_TRACED_API(QuantType&, Type)
|
||||
|
||||
// DEF_TRACED_API(const QuantType&, Type)
|
||||
// lack of macro to def readonly apis
|
||||
template <class R = const QuantType &, class... Args>
|
||||
typename std::enable_if_t<is_not_traced_obj_like<R>::value, R> Type(
|
||||
Args... params) const {
|
||||
|
|
@ -70,9 +71,12 @@ struct Quantization : public TraceClassBase<target::Quantization> {
|
|||
return boost::hana::unpack(params_impl, api_impl);
|
||||
}
|
||||
|
||||
DEF_TRACED_API(Quantization&, SetType)
|
||||
|
||||
DEF_TRACED_API(int32_t&, ChannelDim)
|
||||
|
||||
// DEF_TRACED_API(const int32_t&, ChannelDim)
|
||||
// lack of macro to def readonly apis
|
||||
template <class R = const int32_t &, class... Args>
|
||||
typename std::enable_if_t<is_not_traced_obj_like<R>::value, R> ChannelDim(
|
||||
Args... params) const {
|
||||
|
|
@ -95,9 +99,12 @@ struct Quantization : public TraceClassBase<target::Quantization> {
|
|||
|
||||
DEF_TRACED_API(std::vector<float>&, Scales)
|
||||
|
||||
DEF_TRACED_API(Quantization&, SetScales)
|
||||
|
||||
DEF_TRACED_API(std::vector<int32_t>&, ZeroPoints)
|
||||
|
||||
// DEF_TRACED_API(const std::vector<int32_t>&, ZeroPoints)
|
||||
// lack of macro to def readonly apis
|
||||
template <class R = const std::vector<int32_t> &, class... Args>
|
||||
typename std::enable_if_t<is_not_traced_obj_like<R>::value, R> ZeroPoints(
|
||||
Args... params) const {
|
||||
|
|
|
|||
|
|
@ -92,14 +92,16 @@ TEST(graph, gen_binary_graph_with_simple_add) {
|
|||
}
|
||||
|
||||
#ifdef ENABLE_API_TRACE
|
||||
#define API_REPLAYER_IMPLEMENTATION
|
||||
#define API_TRACER_IMPLEMENTATION
|
||||
#define API_REPLAYER_IMPLEMENTATION // enable static members in api replayer
|
||||
#define API_TRACER_IMPLEMENTATION // enable static members in api tracer
|
||||
#define TARGET_NAMESPACE_NAME "tim::vx"
|
||||
#include "tim/experimental/trace/trace_tvx.h"
|
||||
|
||||
namespace tvx = trace;
|
||||
|
||||
TEST(graph, trace_test) {
|
||||
// Replace all tim::vx name space with tvx, tvx can be alias of trace
|
||||
// namespace.
|
||||
auto ctx = tvx::Context::Create();
|
||||
auto graph = ctx->CreateGraph();
|
||||
|
||||
|
|
@ -135,6 +137,13 @@ TEST(graph, trace_test) {
|
|||
EXPECT_TRUE(output_t0->CopyDataFromTensor(output.data()));
|
||||
EXPECT_EQ(output, expected_out);
|
||||
|
||||
// extra test for Quantization apis
|
||||
tvx::Quantization quant0;
|
||||
quant0.SetType(tvx::QuantType::ASYMMETRIC);
|
||||
quant0.SetChannelDim(1);
|
||||
quant0.SetScales(std::vector<float>({0.2, 0.3}));
|
||||
quant0.SetZeroPoints(std::vector<int32_t>({2, 3}));
|
||||
|
||||
}
|
||||
|
||||
TEST(graph, replay_test) {
|
||||
|
|
@ -144,7 +153,7 @@ TEST(graph, replay_test) {
|
|||
* rename with trace_bin.rpl.bin
|
||||
*/
|
||||
|
||||
#include "trace_log.rpl.cc"
|
||||
// #include "trace_log.rpl.cc"
|
||||
// manual compile and run the selected graph, like:
|
||||
// graph_12->Compile();
|
||||
// graph_12->Run();
|
||||
|
|
|
|||
Loading…
Reference in New Issue