@@ -5,11 +5,13 @@ cc_library( | |||||
"src/infile_persistent_cache.cpp", | "src/infile_persistent_cache.cpp", | ||||
"src/mgblar.cpp", | "src/mgblar.cpp", | ||||
"src/json_loader.cpp", | "src/json_loader.cpp", | ||||
"src/text_table.cpp", | |||||
], | ], | ||||
hdrs = [ | hdrs = [ | ||||
"src/infile_persistent_cache.h", | "src/infile_persistent_cache.h", | ||||
"src/mgblar.h", | "src/mgblar.h", | ||||
"src/json_loader.h", | "src/json_loader.h", | ||||
"src/text_table.h", | |||||
"src/npy.h", | "src/npy.h", | ||||
], | ], | ||||
features = if_opt([ | features = if_opt([ | ||||
@@ -13,6 +13,7 @@ | |||||
#include "./infile_persistent_cache.h" | #include "./infile_persistent_cache.h" | ||||
#include "./json_loader.h" | #include "./json_loader.h" | ||||
#include "./npy.h" | #include "./npy.h" | ||||
#include "./text_table.h" | |||||
#include "megbrain/comp_node_env.h" | #include "megbrain/comp_node_env.h" | ||||
#include "megbrain/gopt/inference.h" | #include "megbrain/gopt/inference.h" | ||||
@@ -91,6 +92,8 @@ R"__usage__( | |||||
param.json --data bbox:bbox.npy@batchid:b.npy --data rect:[0,0,227,227]; | param.json --data bbox:bbox.npy@batchid:b.npy --data rect:[0,0,227,227]; | ||||
batchid:0,1,2,3. --io-dump or --bin-io-dump | batchid:0,1,2,3. --io-dump or --bin-io-dump | ||||
should be enabled at the same time. | should be enabled at the same time. | ||||
--verbose | |||||
Format and display model input/output tensor info. | |||||
--io-dump <output> | --bin-io-dump <output dir> | --io-dump <output> | --bin-io-dump <output dir> | ||||
Dump input/output values of all internal variables to output file or | Dump input/output values of all internal variables to output file or | ||||
directory, in text or binary format. The binary file can be parsed by | directory, in text or binary format. The binary file can be parsed by | ||||
@@ -526,6 +529,7 @@ struct Args { | |||||
COprArgs c_opr_args; | COprArgs c_opr_args; | ||||
bool show_verbose = false; | |||||
bool disable_assert_throw = false; | bool disable_assert_throw = false; | ||||
bool share_param_mem = false; | bool share_param_mem = false; | ||||
#if MGB_ENABLE_FASTRUN | #if MGB_ENABLE_FASTRUN | ||||
@@ -637,6 +641,36 @@ public: | |||||
} | } | ||||
}; | }; | ||||
void format_and_print(const std::string& tablename, const Args& env) { | |||||
auto table = mgb::TextTable(tablename); | |||||
table.padding(1); | |||||
table.align(mgb::TextTable::Align::Mid) | |||||
.add("type") | |||||
.add("name") | |||||
.add("shape") | |||||
.eor(); | |||||
for (auto &&i: env.load_ret.tensor_map) { | |||||
table.align(mgb::TextTable::Align::Mid) | |||||
.add("INPUT") | |||||
.add(i.first) | |||||
.add(i.second->shape().to_string()) | |||||
.eor(); | |||||
} | |||||
for (auto&& i : env.load_ret.output_var_list) { | |||||
table.align(mgb::TextTable::Align::Mid) | |||||
.add("OUTPUT") | |||||
.add(i.node()->name()) | |||||
.add(i.shape().to_string()) | |||||
.eor(); | |||||
} | |||||
std::stringstream ss; | |||||
ss << table; | |||||
printf("%s\n\n", ss.str().c_str()); | |||||
} | |||||
void run_test_st(Args &env) { | void run_test_st(Args &env) { | ||||
std::unique_ptr<serialization::InputFile> inp_file; | std::unique_ptr<serialization::InputFile> inp_file; | ||||
@@ -675,6 +709,10 @@ void run_test_st(Args &env) { | |||||
// compile function to compute all outputs | // compile function to compute all outputs | ||||
ComputingGraph::OutputSpec out_spec; | ComputingGraph::OutputSpec out_spec; | ||||
std::string output_names; | std::string output_names; | ||||
if (env.show_verbose) { | |||||
format_and_print("Original Model Info", env); | |||||
} | |||||
OutputDumper output_dumper(env); | OutputDumper output_dumper(env); | ||||
for (auto&& i : env.load_ret.output_var_list) { | for (auto&& i : env.load_ret.output_var_list) { | ||||
@@ -987,6 +1025,10 @@ void run_test_st(Args &env) { | |||||
TensorRTEngineCache::inst().dump_cache(); | TensorRTEngineCache::inst().dump_cache(); | ||||
} | } | ||||
#endif | #endif | ||||
if (env.show_verbose) { | |||||
format_and_print("Runtime Model Info", env); | |||||
} | |||||
} | } | ||||
} // anonymous namespace | } // anonymous namespace | ||||
@@ -1217,6 +1259,11 @@ Args Args::from_argv(int argc, char **argv) { | |||||
} | } | ||||
continue; | continue; | ||||
} | } | ||||
if (!strcmp(argv[i], "--verbose")) { | |||||
++i; | |||||
ret.show_verbose = true; | |||||
continue; | |||||
} | |||||
if (!strcmp(argv[i], "--io-dump")) { | if (!strcmp(argv[i], "--io-dump")) { | ||||
mgb_log_warn("enable opr io dump"); | mgb_log_warn("enable opr io dump"); | ||||
++ i; | ++ i; | ||||
@@ -0,0 +1,108 @@ | |||||
/** | |||||
* \file sdk/load-and-run/src/text_table.cpp | |||||
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License") | |||||
* | |||||
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved. | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, | |||||
* software distributed under the License is distributed on an | |||||
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||||
* implied. | |||||
*/ | |||||
#include "text_table.h" | |||||
using namespace mgb; | |||||
namespace { | |||||
inline void mid(std::ostream& os, const std::string& str, size_t max_w) { | |||||
size_t l = (max_w - str.length()) / 2 + str.length(); | |||||
size_t r = max_w - l; | |||||
os << std::setw(l) << std::right << str; | |||||
if (r > 0) os << std::setw(r) << ' '; | |||||
} | |||||
inline size_t char_length(char c) { return c ? 1 : 0; } | |||||
} // namespace | |||||
void TextTable::adjuster_last_row() { | |||||
if (m_rows.empty()) return; | |||||
auto& row = m_rows.back(); | |||||
if (row.params.horizontal == 0 or row.params.vertical == 0) { | |||||
row.params.corner = 0; | |||||
} | |||||
if (row.params.horizontal != 0 && row.params.vertical != 0 && | |||||
row.params.corner == 0) { | |||||
row.params.corner = row.params.horizontal; | |||||
} | |||||
} | |||||
void TextTable::show(std::ostream& os) { | |||||
if (m_rows.empty()) return; | |||||
auto& last_row = m_rows.front(); | |||||
bool first = true; | |||||
for (auto& row : m_rows) { | |||||
auto& lrow = | |||||
(last_row.values.size() * char_length(last_row.params.horizontal)) > | |||||
(row.values.size() * char_length(row.params.horizontal)) | |||||
? last_row | |||||
: row; | |||||
// line before row | |||||
if (lrow.params.horizontal) { | |||||
if (not first) os << std::endl; | |||||
os << m_prefix; | |||||
if (lrow.params.corner) os << lrow.params.corner; | |||||
size_t skip_size = 0; | |||||
// table name | |||||
if (first) { | |||||
os << m_name; | |||||
skip_size = m_name.length(); | |||||
} | |||||
for (size_t i = 0; i < lrow.values.size(); ++i) { | |||||
auto max_w = m_cols_max_w.at(i) + m_padding * 2; | |||||
if (max_w + char_length(lrow.params.corner) <= skip_size) { | |||||
skip_size = | |||||
skip_size - max_w - char_length(lrow.params.corner); | |||||
continue; | |||||
} | |||||
size_t rest = | |||||
max_w + char_length(lrow.params.corner) - skip_size; | |||||
skip_size = 0; | |||||
if (rest > char_length(lrow.params.corner)) { | |||||
os << std::string(rest - char_length(lrow.params.corner), | |||||
lrow.params.horizontal); | |||||
rest = char_length(lrow.params.corner); | |||||
} | |||||
if (rest > 0 && lrow.params.corner) os << lrow.params.corner; | |||||
} | |||||
} else if (first) { | |||||
os << m_prefix << ' ' << m_name; | |||||
} | |||||
first = false; | |||||
os << std::endl << m_prefix; | |||||
if (row.params.vertical) os << row.params.vertical; | |||||
// row | |||||
for (size_t i = 0; i < row.values.size(); ++i) { | |||||
auto& str = row.values.at(i); | |||||
auto max_w = m_cols_max_w.at(i) + 2 * m_padding; | |||||
if (row.params.align == Align::Mid) { | |||||
mid(os, str, max_w); | |||||
} else if (row.params.align == Align::Left) { | |||||
os << std::setw(max_w) << std::left << str; | |||||
} else { | |||||
os << std::setw(max_w) << std::right << str; | |||||
} | |||||
if (row.params.vertical) os << row.params.vertical; | |||||
} | |||||
last_row = row; | |||||
} | |||||
if (last_row.params.horizontal) { | |||||
os << std::endl << m_prefix; | |||||
if (last_row.params.corner) os << last_row.params.corner; | |||||
for (size_t i = 0; i < last_row.values.size(); ++i) { | |||||
auto max_w = m_cols_max_w.at(i); | |||||
std::string tmp(max_w + m_padding * 2, last_row.params.horizontal); | |||||
os << tmp; | |||||
if (last_row.params.corner) os << last_row.params.corner; | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1,117 @@ | |||||
/** | |||||
* \file sdk/load-and-run/src/text_table.h | |||||
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License") | |||||
* | |||||
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved. | |||||
* | |||||
* Unless required by applicable law or agreed to in writing, | |||||
* software distributed under the License is distributed on an | |||||
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or | |||||
* implied. | |||||
*/ | |||||
#pragma once | |||||
#include <array> | |||||
#include <iomanip> | |||||
#include <ostream> | |||||
#include <string> | |||||
#include <tuple> | |||||
#include <type_traits> | |||||
#include <vector> | |||||
#include "megbrain/common.h" | |||||
namespace mgb | |||||
{ | |||||
class TextTable { | |||||
public: | |||||
enum Level { Summary, Detail }; | |||||
enum class Align : int { Left, Right, Mid }; | |||||
explicit TextTable(const std::string& table_name) : m_name(table_name) {} | |||||
TextTable& horizontal(char c) { | |||||
m_row.params.horizontal = c; | |||||
return *this; | |||||
} | |||||
TextTable& vertical(char c) { | |||||
m_row.params.vertical = c; | |||||
return *this; | |||||
} | |||||
TextTable& corner(char c) { | |||||
m_row.params.corner = c; | |||||
return *this; | |||||
} | |||||
TextTable& align(Align v) { | |||||
m_row.params.align = v; | |||||
return *this; | |||||
} | |||||
TextTable& padding(size_t w) { | |||||
m_padding = w; | |||||
return *this; | |||||
} | |||||
TextTable& prefix(const std::string& str) { | |||||
m_prefix = str; | |||||
return *this; | |||||
} | |||||
template <typename T> | |||||
TextTable& add(const T& value) { | |||||
if constexpr (std::is_floating_point<T>::value) { | |||||
std::stringstream ss; | |||||
ss << std::setiosflags(std::ios::fixed) << std::setprecision(2); | |||||
ss << value; | |||||
m_row.values.emplace_back(ss.str()); | |||||
} else if constexpr (std::is_integral<T>::value) { | |||||
m_row.values.emplace_back(std::to_string(value)); | |||||
} else { | |||||
m_row.values.emplace_back(value); | |||||
} | |||||
if (m_cols_max_w.size() < m_row.values.size()) { | |||||
m_cols_max_w.emplace_back(m_row.values.back().length()); | |||||
} else { | |||||
mgb_assert(m_row.values.size() >= 1); | |||||
size_t i = m_row.values.size() - 1; | |||||
m_cols_max_w[i] = | |||||
std::max(m_cols_max_w[i], m_row.values.back().length()); | |||||
} | |||||
return *this; | |||||
} | |||||
void eor() { | |||||
m_rows.emplace_back(m_row); | |||||
adjuster_last_row(); | |||||
m_row.values.clear(); | |||||
} | |||||
void reset() { | |||||
m_row = {}; | |||||
m_cols_max_w.clear(); | |||||
m_padding = 0; | |||||
m_rows.clear(); | |||||
} | |||||
void show(std::ostream& os); | |||||
private: | |||||
void adjuster_last_row(); | |||||
std::string m_name; | |||||
std::vector<size_t> m_cols_max_w; | |||||
size_t m_padding = 0; | |||||
std::string m_prefix = ""; | |||||
struct Row { | |||||
std::vector<std::string> values; | |||||
struct Params { | |||||
Align align = Align::Left; | |||||
char horizontal = '-', vertical = '|', corner = '+'; | |||||
} params; | |||||
}; | |||||
std::vector<Row> m_rows; | |||||
Row m_row; | |||||
}; | |||||
inline std::ostream& operator<<(std::ostream& stream, TextTable& table) { | |||||
table.show(stream); | |||||
return stream; | |||||
} | |||||
} // namespace mgb |