2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
21 #include <json/json.h>
26 // This function parses a json object and returns as a vector of integers
28 // [0, [1, 2, 3, 4], 3, 40, 4, []] in JSON
34 // } in std::unordered_map. Note that the value type is still Json::Value.
35 std::unordered_map<uint32_t, Json::Value> argArrayToMap(const Json::Value &jsonval)
37 if (!jsonval.isArray() || (jsonval.size() % 2 != 0))
39 std::cerr << "JSON argument must be an even-sized array in JSON\n";
43 std::unordered_map<uint32_t, Json::Value> ret;
44 for (uint32_t i = 0; i < jsonval.size(); i += 2)
46 if (!jsonval[i].isUInt())
48 std::cerr << "Key values(values in even indices) must be unsigned integers\n";
51 uint32_t key = jsonval[i].asUInt();
52 Json::Value val = jsonval[i + 1];
53 ret[key] = jsonval[i + 1];
58 // param shape_str is a form of, e.g., "[1, [2, 3], 3, []]" or "h5"
59 void handleShapeJsonParam(nnpkg_run::TensorShapeMap &shape_map, const std::string &shape_str)
63 if (!reader.parse(shape_str, root, false))
65 std::cerr << "Invalid JSON format for output_sizes \"" << shape_str << "\"\n";
69 auto arg_map = argArrayToMap(root);
70 for (auto &pair : arg_map)
72 uint32_t key = pair.first;
73 Json::Value &shape_json = pair.second;
74 if (!shape_json.isArray())
76 std::cerr << "All the values must be list: " << shape_str << "\n";
80 std::vector<int> shape;
81 for (auto &dim_json : shape_json)
83 if (!dim_json.isUInt())
85 std::cerr << "All the dims should be dim >= 0: " << shape_str << "\n";
89 shape.emplace_back(dim_json.asUInt64());
92 shape_map[key] = shape;
101 Args::Args(const int argc, char **argv)
107 void Args::Initialize(void)
109 auto process_nnpackage = [&](const std::string &package_filename) {
110 _package_filename = package_filename;
112 std::cerr << "Package Filename " << _package_filename << std::endl;
113 if (_package_filename.empty())
115 // TODO Print usage instead of the below message
116 std::cerr << "Please specify nnpackage file. Run with `--help` for usage."
123 if (access(_package_filename.c_str(), F_OK) == -1)
125 std::cerr << "nnpackage not found: " << _package_filename << "\n";
130 auto process_output_sizes = [&](const std::string &output_sizes_json_str) {
133 if (!reader.parse(output_sizes_json_str, root, false))
135 std::cerr << "Invalid JSON format for output_sizes \"" << output_sizes_json_str << "\"\n";
139 auto arg_map = argArrayToMap(root);
140 for (auto &pair : arg_map)
142 uint32_t key = pair.first;
143 Json::Value &val_json = pair.second;
144 if (!val_json.isUInt())
146 std::cerr << "All the values in `output_sizes` must be unsigned integers\n";
149 uint32_t val = val_json.asUInt();
150 _output_sizes[key] = val;
154 auto process_shape_prepare = [&](const std::string &shape_str) {
155 #if defined(ONERT_HAVE_HDF5) && ONERT_HAVE_HDF5 == 1
156 if (shape_str == "H5" || shape_str == "h5")
158 _when_to_use_h5_shape = WhenToUseH5Shape::PREPARE;
164 handleShapeJsonParam(_shape_prepare, shape_str);
166 catch (const std::exception &e)
168 std::cerr << "error with '--shape_prepare' option: " << shape_str << std::endl;
173 auto process_shape_run = [&](const std::string &shape_str) {
174 #if defined(ONERT_HAVE_HDF5) && ONERT_HAVE_HDF5 == 1
175 if (shape_str == "H5" || shape_str == "h5")
177 _when_to_use_h5_shape = WhenToUseH5Shape::RUN;
183 handleShapeJsonParam(_shape_run, shape_str);
185 catch (const std::exception &e)
187 std::cerr << "error with '--shape_run' option: " << shape_str << std::endl;
193 po::options_description general("General options", 100);
196 general.add_options()
197 ("help,h", "Print available options")
198 ("version", "Print version and exit immediately")
199 ("nnpackage", po::value<std::string>()->required()->notifier(process_nnpackage))
200 #if defined(ONERT_HAVE_HDF5) && ONERT_HAVE_HDF5 == 1
201 ("dump,d", po::value<std::string>()->default_value("")->notifier([&](const auto &v) { _dump_filename = v; }), "Output filename")
202 ("load,l", po::value<std::string>()->default_value("")->notifier([&](const auto &v) { _load_filename = v; }), "Input filename")
204 ("output_sizes", po::value<std::string>()->notifier(process_output_sizes),
205 "The output buffer size in JSON 1D array\n"
206 "If not given, the model's output sizes are used\n"
207 "e.g. '[0, 40, 2, 80]' to set 0th tensor to 40 and 2nd tensor to 80.\n")
208 ("num_runs,r", po::value<int>()->default_value(1)->notifier([&](const auto &v) { _num_runs = v; }), "The number of runs")
209 ("warmup_runs,w", po::value<int>()->default_value(0)->notifier([&](const auto &v) { _warmup_runs = v; }), "The number of warmup runs")
210 ("run_delay,t", po::value<int>()->default_value(-1)->notifier([&](const auto &v) { _run_delay = v; }), "Delay time(ms) between runs (as default no delay")
211 ("gpumem_poll,g", po::value<bool>()->default_value(false)->notifier([&](const auto &v) { _gpumem_poll = v; }), "Check gpu memory polling separately")
212 ("mem_poll,m", po::value<bool>()->default_value(false)->notifier([&](const auto &v) { _mem_poll = v; }), "Check memory polling")
213 ("write_report,p", po::value<bool>()->default_value(false)->notifier([&](const auto &v) { _write_report = v; }),
215 "{exec}-{nnpkg}-{backend}.csv will be generated.\n"
216 "e.g. nnpackage_run-UNIT_Add_000-acl_cl.csv.\n"
217 "{nnpkg} name may be changed to realpath if you use symbolic-link.")
218 ("shape_prepare", po::value<std::string>()->default_value("[]")->notifier(process_shape_prepare),
219 "set shape of specified tensor before compilation (before calling nnfw_prepare()).\n"
220 "'h5': read shape(s) from H5 input file. '--load' should also be provided.\n"
221 "'[0, [1, 2], 2, []]': set 0th tensor to [1, 2] and 2nd tensor to [].")
222 ("shape_run", po::value<std::string>()->default_value("[]")->notifier(process_shape_run),
223 "set shape of specified tensor before running (before calling nnfw_run()).\n"
224 "'h5': read shape(s) from H5 input file. '--load' should also be provided.\n"
225 "'[0, [1, 2], 2, []]': set 0th tensor to [1, 2] and 2nd tensor to [].")
226 ("verbose_level,v", po::value<int>()->default_value(0)->notifier([&](const auto &v) { _verbose_level = v; }),
228 "0: prints the only result. Messages btw run don't print\n"
229 "1: prints result and message btw run\n"
230 "2: prints all of messages to print\n")
234 _options.add(general);
235 _positional.add("nnpackage", 1);
238 void Args::Parse(const int argc, char **argv)
240 po::variables_map vm;
241 po::store(po::command_line_parser(argc, argv).options(_options).positional(_positional).run(),
245 auto conflicting_options = [&](const std::string &o1, const std::string &o2) {
246 if ((vm.count(o1) && !vm[o1].defaulted()) && (vm.count(o2) && !vm[o2].defaulted()))
248 throw boost::program_options::error(std::string("Two options '") + o1 + "' and '" + o2 +
249 "' cannot be given at once.");
254 if (vm.count("help"))
256 std::cout << "nnpackage_run\n\n";
257 std::cout << "Usage: " << argv[0] << " path to nnpackage root directory [<options>]\n\n";
258 std::cout << _options;
264 if (vm.count("version"))
266 _print_version = true;
274 catch (const std::bad_cast &e)
276 std::cerr << "Bad cast error - " << e.what() << '\n';
280 // This must be run after `notify` as `_warm_up_runs` must have been processed before.
281 if (vm.count("mem_poll"))
283 // Instead of EXECUTE to avoid overhead, memory polling runs on WARMUP
284 if (_mem_poll && _warmup_runs == 0)
291 } // end of namespace nnpkg_run