368 lines
18 KiB
C++
Executable File
368 lines
18 KiB
C++
Executable File
/****************************************************************************
|
|
*
|
|
* Copyright (c) 2020-2023 Vivante Corporation
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*
|
|
*****************************************************************************/
|
|
#ifndef TIM_EXPERIMENTAL_TRACE_TVX_GRAPH_H_
|
|
#define TIM_EXPERIMENTAL_TRACE_TVX_GRAPH_H_
|
|
#include "tim/vx/graph.h"
|
|
#include "tim/experimental/trace/tvx/ops.h"
|
|
#include "tim/experimental/trace/tvx/tensor.h"
|
|
#include "tim/experimental/trace/tracer.h"
|
|
|
|
namespace trace {
|
|
|
|
namespace target = ::tim::vx;
|
|
|
|
#define DECL_CREATE_OP_IMPL_(r, _, opname) \
|
|
template <class... Params> \
|
|
std::shared_ptr<trace::ops::opname> CreateOperationImpl( \
|
|
BOOST_PP_CAT(ops::_VSI_Tag_of_, opname), Params... params);
|
|
|
|
#define DECL_CREATE_OPS(ops_seq) \
|
|
BOOST_PP_SEQ_FOR_EACH(DECL_CREATE_OP_IMPL_, _, ops_seq)
|
|
|
|
#define TO_STRING_(expr) #expr
|
|
|
|
#define DEF_CREATE_OP_IMPL_(r, _, opname) \
|
|
template <class... Params> \
|
|
std::shared_ptr<trace::ops::opname> Graph::CreateOperationImpl( \
|
|
BOOST_PP_CAT(ops::_VSI_Tag_of_, opname), Params... params) { \
|
|
std::string this_obj_name = TraceGetObjName(); \
|
|
std::string obj_name = \
|
|
Tracer::allocate_obj_name(std::string(TO_STRING_(opname)) + "_"); \
|
|
Tracer::logging_msg( \
|
|
"auto %s = %s->CreateOperation<%s::ops::%s>(", obj_name.c_str(), \
|
|
this_obj_name.c_str(), target_namespace_name_, TO_STRING_(opname)); \
|
|
Tracer::clear_params_log_cache(); \
|
|
boost::hana::tuple<Params...> params_tuple = {params...}; \
|
|
boost::hana::for_each(params_tuple, [&] (auto x) { \
|
|
Tracer::logging_param(x, -1); \
|
|
}); \
|
|
Tracer::dump_params_log_cache(); \
|
|
Tracer::logging_msg(");\n"); \
|
|
auto CreateOpImpl = [&] (auto&&... ts) { \
|
|
return impl_->CreateOperation<target::ops::opname>(ts...); \
|
|
}; \
|
|
auto proc_param_lambda = [] (auto&& t) { \
|
|
return Tracer::proc_param(t); \
|
|
}; \
|
|
auto params_impl = boost::hana::transform(params_tuple, proc_param_lambda); \
|
|
auto op_impl_sp = boost::hana::unpack(params_impl, CreateOpImpl); \
|
|
auto op_sp = std::make_shared<trace::ops::opname>(op_impl_sp); \
|
|
Tracer::insert_obj_name(static_cast<void*>(op_impl_sp.get()), obj_name); \
|
|
return op_sp; \
|
|
}
|
|
|
|
#define DEF_CREATE_OP_IMPLS(ops_seq) \
|
|
BOOST_PP_SEQ_FOR_EACH(DEF_CREATE_OP_IMPL_, _, ops_seq)
|
|
|
|
#define SPECIALIZATION_CREATE_OP(opname, args_desc, SPECIAL_MACRO_) \
|
|
template <> \
|
|
inline std::shared_ptr<trace::ops::opname> Graph::CreateOperation( \
|
|
ARGS_DESC_TO_DECLARATION(args_desc)) { \
|
|
std::string this_obj_name = TraceGetObjName(); \
|
|
std::string obj_name = Tracer::allocate_obj_name(std::string(#opname) + "_");\
|
|
Tracer::push_back_msg_cache( \
|
|
"auto " + obj_name + " = " + this_obj_name + \
|
|
"->CreateOperation<target::ops::" + #opname + ">("); \
|
|
LOG_PARAMS(ARGS_DESC_TO_PARAMS(args_desc)) \
|
|
SPECIAL_MACRO_(ARGS_DESC_TO_PARAMS(args_desc)) \
|
|
Tracer::pop_params_log_cache(); \
|
|
Tracer::amend_last_msg_cache(");\n"); \
|
|
Tracer::msg_cache_sync_to_file(); \
|
|
auto op_impl_sp = impl_->CreateOperation<target::ops::opname>( \
|
|
SEQ_TO_VARIADICS(ARGS_DESC_TO_PARAMS(args_desc))); \
|
|
auto op_sp = std::make_shared<trace::ops::opname>(op_impl_sp); \
|
|
Tracer::insert_obj_name(static_cast<void*>(op_impl_sp.get()), obj_name); \
|
|
return op_sp; \
|
|
}
|
|
|
|
struct Graph : public TraceClassBase<target::Graph> {
|
|
DEF_INTERFACE_CONSTRUCTOR(Graph)
|
|
|
|
#define SPECIAL_MACRO_(params) \
|
|
if (BOOST_PP_SEQ_ELEM(1, params) == nullptr) { \
|
|
Tracer::insert_params_log_cache("nullptr", 1); \
|
|
} else { \
|
|
uint32_t count = \
|
|
BOOST_PP_SEQ_ELEM(0, params).TraceGetImpl().GetByteSize(); \
|
|
uint32_t offset = \
|
|
Tracer::dump_data( \
|
|
BOOST_PP_SEQ_ELEM(1, params), sizeof(char), count); \
|
|
LOGGING_POINTER_MSG(offset, count, 0) \
|
|
}
|
|
|
|
// DEF_MEMFN_SP(Tensor,
|
|
// CreateTensor,
|
|
// ((const TensorSpec&))((const void*)(nullptr)),
|
|
// SPECIAL_MACRO_)
|
|
std::shared_ptr<Tensor> CreateTensor(
|
|
const TensorSpec ¶m_0, const void *param_1 = nullptr) {
|
|
std::string this_obj_name = TraceGetObjName();
|
|
std::string obj_name =
|
|
Tracer::allocate_obj_name(Tracer::get_obj_prefix("Tensor"));
|
|
Tracer::push_back_msg_cache("auto " + obj_name + " = " + this_obj_name
|
|
+ "->" + __FUNCTION__ + "(");
|
|
Tracer::init_params_log_cache(2);
|
|
Tracer::logging_param(param_0, 0);
|
|
Tracer::logging_param(param_1, 1);
|
|
SPECIAL_MACRO_((param_0)(param_1))
|
|
Tracer::pop_params_log_cache();
|
|
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::CONSTANT && param_1 == nullptr) {
|
|
auto fake_vec_name = Tracer::allocate_obj_name("fake_vec_");
|
|
switch (param_0.TraceGetImpl().GetDataType()) {
|
|
case DataType::INT32:
|
|
Tracer::logging_msg("std::vector<int> %s(%d, 42);\n"
|
|
"%s->CopyDataToTensor(%s.data());\n",
|
|
fake_vec_name.c_str(), (int)param_0.TraceGetImpl().GetElementNum(),
|
|
obj_name.c_str(), fake_vec_name.c_str());
|
|
break;
|
|
case DataType::FLOAT32:
|
|
Tracer::logging_msg("std::vector<float> %s(%d, 0.42);\n"
|
|
"%s->CopyDataToTensor(%s.data());\n",
|
|
fake_vec_name.c_str(), (int)param_0.TraceGetImpl().GetElementNum(),
|
|
obj_name.c_str(), fake_vec_name.c_str());
|
|
break;
|
|
case DataType::FLOAT16:
|
|
Tracer::logging_msg("std::vector<int16_t> %s(%d, 0);\n"
|
|
"%s->CopyDataToTensor(%s.data());\n",
|
|
fake_vec_name.c_str(), (int)param_0.TraceGetImpl().GetElementNum(),
|
|
obj_name.c_str(), fake_vec_name.c_str());
|
|
break;
|
|
case DataType::BOOL8:
|
|
Tracer::logging_msg("std::vector<char> %s(%d, 0);\n"
|
|
"%s->CopyDataToTensor(%s.data());\n",
|
|
fake_vec_name.c_str(), (int)param_0.TraceGetImpl().GetElementNum(),
|
|
obj_name.c_str(), fake_vec_name.c_str());
|
|
break;
|
|
default:
|
|
TCLOGE("Unimplemented fake data type:%d\n",
|
|
(int)param_0.TraceGetImpl().GetDataType());
|
|
break;
|
|
}
|
|
}
|
|
#endif /* if use fake input data */
|
|
|
|
auto obj_impl_sp = impl_->CreateTensor(
|
|
Tracer::proc_param(param_0), Tracer::proc_param(param_1));
|
|
auto obj_sp = std::make_shared<Tensor>(obj_impl_sp, param_0);
|
|
Tracer::insert_obj_name(static_cast<void *>(obj_impl_sp.get()), obj_name);
|
|
tensor_sp_keeper_[obj_impl_sp] = obj_sp; // need keep obj_sp alive.
|
|
spec_keeper_.push_back(param_0);
|
|
return obj_sp;
|
|
}
|
|
|
|
// DEF_MEMFN_SP(Tensor,
|
|
// CreateIOTensor,
|
|
// ((const TensorSpec&))((void*)(nullptr)),
|
|
// SPECIAL_MACRO_)
|
|
std::shared_ptr<Tensor> CreateIOTensor(
|
|
const TensorSpec ¶m_0, void *param_1 = nullptr) {
|
|
std::string this_obj_name = TraceGetObjName();
|
|
std::string obj_name =
|
|
Tracer::allocate_obj_name(Tracer::get_obj_prefix("Tensor"));
|
|
Tracer::push_back_msg_cache("auto " + obj_name + " = " + this_obj_name
|
|
+ "->" + __FUNCTION__ + "(");
|
|
Tracer::init_params_log_cache(2);
|
|
Tracer::logging_param(param_0, 0);
|
|
Tracer::logging_param(param_1, 1);
|
|
SPECIAL_MACRO_((param_0)(param_1))
|
|
Tracer::pop_params_log_cache();
|
|
Tracer::amend_last_msg_cache(");\n");
|
|
Tracer::msg_cache_sync_to_file();
|
|
auto obj_impl_sp = impl_->CreateIOTensor(
|
|
Tracer::proc_param(param_0), Tracer::proc_param(param_1));
|
|
auto obj_sp = std::make_shared<Tensor>(obj_impl_sp);
|
|
Tracer::insert_obj_name(static_cast<void *>(obj_impl_sp.get()), obj_name);
|
|
tensor_sp_keeper_[obj_impl_sp] = obj_sp; // need keep obj_sp alive.
|
|
spec_keeper_.push_back(param_0);
|
|
return obj_sp;
|
|
}
|
|
|
|
#undef SPECIAL_MACRO_
|
|
|
|
// DEF_MEMFN_SP(Tensor, CreateTensor,
|
|
// ((const TensorSpec&))((const DmaBufferDesc&))
|
|
// )
|
|
std::shared_ptr<Tensor> CreateTensor(
|
|
const TensorSpec ¶m_0, const DmaBufferDesc ¶m_1) {
|
|
std::string this_obj_name = TraceGetObjName();
|
|
std::string obj_name =
|
|
Tracer::allocate_obj_name(Tracer::get_obj_prefix("Tensor"));
|
|
Tracer::logging_msg("auto %s = %s->%s(", obj_name.c_str(),
|
|
this_obj_name.c_str(), __FUNCTION__);
|
|
Tracer::init_params_log_cache(2);
|
|
Tracer::logging_param(param_0, 0);
|
|
Tracer::logging_param(param_1, 1);
|
|
Tracer::dump_params_log_cache();
|
|
Tracer::logging_msg(");\n");
|
|
auto obj_impl_sp = impl_->CreateTensor(Tracer::proc_param(param_0),
|
|
Tracer::proc_param(param_1));
|
|
auto obj_sp = std::make_shared<Tensor>(obj_impl_sp);
|
|
Tracer::insert_obj_name(static_cast<void *>(obj_impl_sp.get()), obj_name);
|
|
tensor_sp_keeper_[obj_impl_sp] = obj_sp; // need keep obj_sp alive.
|
|
spec_keeper_.push_back(param_0);
|
|
return obj_sp;
|
|
}
|
|
|
|
// DEF_MEMFN_SP(Tensor, CreateTensorPlaceHolder)
|
|
std::shared_ptr<Tensor> CreateTensorPlaceHolder() {
|
|
std::string this_obj_name = TraceGetObjName();
|
|
std::string obj_name =
|
|
Tracer::allocate_obj_name(Tracer::get_obj_prefix("Tensor"));
|
|
Tracer::logging_msg("auto %s = %s->%s();\n", obj_name.c_str(),
|
|
this_obj_name.c_str(), __FUNCTION__);
|
|
auto obj_impl_sp = impl_->CreateTensorPlaceHolder();
|
|
auto obj_sp = std::make_shared<Tensor>(obj_impl_sp);
|
|
Tracer::insert_obj_name(static_cast<void *>(obj_impl_sp.get()), obj_name);
|
|
tensor_sp_keeper_[obj_impl_sp] = obj_sp; // need keep obj_sp alive.
|
|
return obj_sp;
|
|
}
|
|
|
|
DEF_TRACED_API(bool, Compile)
|
|
|
|
// DEF_TRACED_API(bool, CompileToBinary, [&] () {
|
|
// if (boost::hana::at_c<0>(params_tuple) == nullptr) {
|
|
// auto nbg_size_var = Tracer::allocate_obj_name("nbg_size_");
|
|
// Tracer::insert_obj_name(boost::hana::at_c<1>(params_tuple), nbg_size_var);
|
|
// Tracer::insert_before_last_msg_cache(
|
|
// "size_t " + nbg_size_var + " = -1;\n");
|
|
// Tracer::insert_params_log_cache("nullptr", 0);
|
|
// } else {
|
|
// uint32_t count = *boost::hana::at_c<1>(params_tuple);
|
|
// uint32_t offset = Tracer::dump_data(boost::hana::at_c<0>(params_tuple),
|
|
// sizeof(char), count);
|
|
// LOGGING_POINTER_MSG(offset, count, 0)
|
|
// }
|
|
// Tracer::insert_params_log_cache(
|
|
// "&" + Tracer::get_obj_name(boost::hana::at_c<1>(params_tuple)), 1);
|
|
// })
|
|
|
|
#define SPECIAL_MACRO_(params) \
|
|
if (BOOST_PP_SEQ_ELEM(0, params) == nullptr) { \
|
|
std::string size_name = Tracer::allocate_obj_name("nbg_size_"); \
|
|
Tracer::insert_obj_name(BOOST_PP_SEQ_ELEM(1, params), size_name); \
|
|
Tracer::insert_before_last_msg_cache( \
|
|
"size_t " + size_name + " = -1;\n"); \
|
|
Tracer::insert_params_log_cache("nullptr", 0); \
|
|
} else { \
|
|
uint32_t data_length = *BOOST_PP_SEQ_ELEM(1, params); \
|
|
uint32_t offset = Tracer::dump_data( \
|
|
BOOST_PP_SEQ_ELEM(0, params), sizeof(char), data_length); \
|
|
LOGGING_POINTER_MSG(offset, data_length, 0) \
|
|
} \
|
|
Tracer::insert_params_log_cache( \
|
|
"&" + Tracer::get_obj_name(BOOST_PP_SEQ_ELEM(1, params)), 1);
|
|
|
|
DEF_MEMFN(bool,
|
|
CompileToBinary,
|
|
((void*))((size_t*)),
|
|
SPECIAL_MACRO_)
|
|
|
|
#undef SPECIAL_MACRO_
|
|
|
|
DEF_TRACED_API(bool, Run)
|
|
|
|
template <class OpType, class... Params>
|
|
std::shared_ptr<OpType> CreateOperation(Params... params) {
|
|
return CreateOperationImpl(
|
|
typename ops::TagDispatchTrait<OpType>::tag {}, params...);
|
|
}
|
|
|
|
const std::vector<std::shared_ptr<Tensor>> InputsTensor() {
|
|
std::vector<std::shared_ptr<Tensor>> ret;
|
|
for (auto& x : impl_->InputsTensor()) {
|
|
ret.push_back(tensor_sp_keeper_[x]);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
const std::vector<std::shared_ptr<Tensor>> OutputsTensor() {
|
|
std::vector<std::shared_ptr<Tensor>> ret;
|
|
for (auto& x : impl_->OutputsTensor()) {
|
|
ret.push_back(tensor_sp_keeper_[x]);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
DEF_TRACED_API(void, UpdateTensorConsumersMap)
|
|
|
|
DEF_TRACED_API(void, UpdateTensorProducerMap)
|
|
|
|
// DEF_TRACED_API(const std::vector<std::shared_ptr<Operation>>, GetConsumersOp)
|
|
|
|
// DEF_TRACED_API(std::shared_ptr<Operation>, GetProducerOp)
|
|
|
|
DEF_TRACED_API(void, PrintGraph)
|
|
|
|
// DEF_TRACED_API(const std::vector<std::shared_ptr<Tensor>>, GetConstantInputs)
|
|
|
|
// DEF_TRACED_API(const std::vector<std::shared_ptr<Operation>>, GetOpVector)
|
|
|
|
private:
|
|
std::unordered_map<std::shared_ptr<target::Tensor>, std::shared_ptr<Tensor>>
|
|
tensor_sp_keeper_;
|
|
std::vector<TensorSpec> spec_keeper_;
|
|
|
|
DECL_CREATE_OPS(TVX_OPS_SEQ)
|
|
DECL_CREATE_OP_IMPL_(_, _, Pad) // there are enums defined in the op
|
|
DECL_CREATE_OP_IMPL_(_, _, PadV2) // there are enums defined in the op
|
|
|
|
};
|
|
// 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)),
|
|
SPECIAL_MACRO_)
|
|
|
|
#undef SPECIAL_MACRO_
|
|
|
|
DEF_CREATE_OP_IMPLS(TVX_OPS_SEQ)
|
|
DEF_CREATE_OP_IMPL_(_, _, Pad)
|
|
DEF_CREATE_OP_IMPL_(_, _, PadV2)
|
|
|
|
} /* namespace trace */
|
|
|
|
#endif // TIM_EXPERIMENTAL_TRACE_TVX_GRAPH_H_
|