Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / tests / tools / nnpackage_run / src / args.cc
1 /*
2  * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
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
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "args.h"
18
19 #include <iostream>
20 #include <json/json.h>
21
22 namespace
23 {
24
25 // This function parses a json object and returns as a vector of integers
26 // For example,
27 // [0, [1, 2, 3, 4], 3, 40, 4, []] in JSON
28 // is converted to:
29 // {
30 //  0 -> [1, 2, 3, 4]
31 //  3 -> 40
32 //  4 -> []
33 // } in std::unordered_map. Note that the value type is still Json::Value.
34 std::unordered_map<uint32_t, Json::Value> argArrayToMap(const Json::Value &jsonval)
35 {
36   if (!jsonval.isArray() || (jsonval.size() % 2 != 0))
37   {
38     std::cerr << "JSON argument must be an even-sized array in JSON\n";
39     exit(1);
40   }
41
42   std::unordered_map<uint32_t, Json::Value> ret;
43   for (uint32_t i = 0; i < jsonval.size(); i += 2)
44   {
45     if (!jsonval[i].isUInt())
46     {
47       std::cerr << "Key values(values in even indices) must be unsigned integers\n";
48       exit(1);
49     }
50     uint32_t key = jsonval[i].asUInt();
51     Json::Value val = jsonval[i + 1];
52     ret[key] = jsonval[i + 1];
53   }
54   return ret;
55 }
56
57 // param shape_str is a form of, e.g., "[1, [2, 3], 3, []]"
58 void handleShapeParam(nnpkg_run::TensorShapeMap &shape_map, const std::string &shape_str)
59 {
60   Json::Value root;
61   Json::Reader reader;
62   if (!reader.parse(shape_str, root, false))
63   {
64     std::cerr << "Invalid JSON format for output_sizes \"" << shape_str << "\"\n";
65     exit(1);
66   }
67
68   auto arg_map = argArrayToMap(root);
69   for (auto &pair : arg_map)
70   {
71     uint32_t key = pair.first;
72     Json::Value &shape_json = pair.second;
73     if (!shape_json.isArray())
74     {
75       std::cerr << "All the values must be list: " << shape_str << "\n";
76       exit(1);
77     }
78
79     std::vector<int> shape;
80     for (auto &dim_json : shape_json)
81     {
82       if (!dim_json.isUInt())
83       {
84         std::cerr << "All the dims should be dim >= 0: " << shape_str << "\n";
85         exit(1);
86       }
87
88       shape.emplace_back(dim_json.asUInt64());
89     }
90
91     shape_map[key] = shape;
92   }
93 }
94
95 } // namespace
96
97 namespace nnpkg_run
98 {
99
100 Args::Args(const int argc, char **argv)
101 {
102   Initialize();
103   Parse(argc, argv);
104 }
105
106 void Args::Initialize(void)
107 {
108   // General options
109   po::options_description general("General options", 100);
110
111   // clang-format off
112   general.add_options()
113     ("help,h", "Print available options")
114     ("version", "Print version and exit immediately")
115     ("nnpackage", po::value<std::string>()->required())
116 #if defined(ONERT_HAVE_HDF5) && ONERT_HAVE_HDF5 == 1
117     ("dump,d", po::value<std::string>()->default_value(""), "Output filename")
118     ("load,l", po::value<std::string>()->default_value(""), "Input filename")
119 #endif
120     ("output_sizes", po::value<std::string>(),
121         "The output buffer size in JSON 1D array\n"
122         "If not given, the model's output sizes are used\n"
123         "e.g. '[0, 40, 2, 80]' to set 0th tensor to 40 and 2nd tensor to 80.\n")
124     ("num_runs,r", po::value<int>()->default_value(1), "The number of runs")
125     ("warmup_runs,w", po::value<int>()->default_value(0), "The number of warmup runs")
126     ("run_delay,t", po::value<int>()->default_value(-1), "Delay time(ms) between runs (as default no delay")
127     ("gpumem_poll,g", po::value<bool>()->default_value(false), "Check gpu memory polling separately")
128     ("mem_poll,m", po::value<bool>()->default_value(false), "Check memory polling")
129     ("write_report,p", po::value<bool>()->default_value(false),
130          "Write report\n"
131          "{exec}-{nnpkg}-{backend}.csv will be generated.\n"
132          "e.g. nnpackage_run-UNIT_Add_000-acl_cl.csv.\n"
133          "{nnpkg} name may be changed to realpath if you use symbolic-link.")
134     ("shape_prepare", po::value<std::string>()->default_value("[]"),
135          "set shape of specified tensor before compilation\n"
136          "e.g. '[0, [1, 2], 2, []]' to set 0th tensor to [1, 2] and 2nd tensor to [].\n")
137     ("shape_run", po::value<std::string>()->default_value("[]"),
138          "set shape of specified tensor right before running\n"
139          "e.g. '[1, [1, 2]]` to set 1st tensor to [1, 2].\n")
140     ("verbose_level,v", po::value<int>()->default_value(0), "Verbose level\n"
141          "0: prints the only result. Messages btw run don't print\n"
142          "1: prints result and message btw run\n"
143          "2: prints all of messages to print\n")
144     ;
145   // clang-format on
146
147   _options.add(general);
148   _positional.add("nnpackage", 1);
149 }
150
151 void Args::Parse(const int argc, char **argv)
152 {
153   po::variables_map vm;
154   po::store(po::command_line_parser(argc, argv).options(_options).positional(_positional).run(),
155             vm);
156
157   {
158     auto conflicting_options = [&](const std::string &o1, const std::string &o2) {
159       if ((vm.count(o1) && !vm[o1].defaulted()) && (vm.count(o2) && !vm[o2].defaulted()))
160       {
161         throw boost::program_options::error(std::string("Two options '") + o1 + "' and '" + o2 +
162                                             "' cannot be given at once.");
163       }
164     };
165   }
166
167   if (vm.count("help"))
168   {
169     std::cout << "nnpackage_run\n\n";
170     std::cout << "Usage: " << argv[0] << " path to nnpackage root directory [<options>]\n\n";
171     std::cout << _options;
172     std::cout << "\n";
173
174     exit(0);
175   }
176
177   if (vm.count("version"))
178   {
179     _print_version = true;
180     return;
181   }
182
183   po::notify(vm);
184   try
185   {
186 #if defined(ONERT_HAVE_HDF5) && ONERT_HAVE_HDF5 == 1
187     if (vm.count("dump"))
188     {
189       _dump_filename = vm["dump"].as<std::string>();
190     }
191
192     if (vm.count("load"))
193     {
194       _load_filename = vm["load"].as<std::string>();
195     }
196 #endif
197
198     if (vm.count("nnpackage"))
199     {
200       _package_filename = vm["nnpackage"].as<std::string>();
201
202       if (_package_filename.empty())
203       {
204         // TODO Print usage instead of the below message
205         std::cerr << "Please specify nnpackage file. Run with `--help` for usage."
206                   << "\n";
207
208         exit(1);
209       }
210       else
211       {
212         if (access(_package_filename.c_str(), F_OK) == -1)
213         {
214           std::cerr << "nnpackage not found: " << _package_filename << "\n";
215         }
216       }
217     }
218
219     if (vm.count("output_sizes"))
220     {
221       auto output_sizes_json_str = vm["output_sizes"].as<std::string>();
222
223       Json::Value root;
224       Json::Reader reader;
225       if (!reader.parse(output_sizes_json_str, root, false))
226       {
227         std::cerr << "Invalid JSON format for output_sizes \"" << output_sizes_json_str << "\"\n";
228         exit(1);
229       }
230
231       auto arg_map = argArrayToMap(root);
232       for (auto &pair : arg_map)
233       {
234         uint32_t key = pair.first;
235         Json::Value &val_json = pair.second;
236         if (!val_json.isUInt())
237         {
238           std::cerr << "All the values in `output_sizes` must be unsigned integers\n";
239           exit(1);
240         }
241         uint32_t val = val_json.asUInt();
242         _output_sizes[key] = val;
243       }
244     }
245
246     if (vm.count("num_runs"))
247     {
248       _num_runs = vm["num_runs"].as<int>();
249     }
250
251     if (vm.count("warmup_runs"))
252     {
253       _warmup_runs = vm["warmup_runs"].as<int>();
254     }
255
256     if (vm.count("run_delay"))
257     {
258       _run_delay = vm["run_delay"].as<int>();
259     }
260
261     if (vm.count("gpumem_poll"))
262     {
263       _gpumem_poll = vm["gpumem_poll"].as<bool>();
264     }
265
266     if (vm.count("mem_poll"))
267     {
268       _mem_poll = vm["mem_poll"].as<bool>();
269       // Instead of EXECUTE to avoid overhead, memory polling runs on WARMUP
270       if (_mem_poll && _warmup_runs == 0)
271       {
272         _warmup_runs = 1;
273       }
274     }
275
276     if (vm.count("write_report"))
277     {
278       _write_report = vm["write_report"].as<bool>();
279     }
280
281     if (vm.count("verbose_level"))
282     {
283       _verbose_level = vm["verbose_level"].as<int>();
284     }
285   }
286   catch (const std::bad_cast &e)
287   {
288     std::cerr << "error by bad cast" << e.what() << '\n';
289     exit(1);
290   }
291
292   if (vm.count("shape_prepare"))
293   {
294     std::string shape_str;
295     try
296     {
297       shape_str = vm["shape_prepare"].as<std::string>();
298     }
299     catch (const std::bad_cast &e)
300     {
301       std::cerr << "error by bad cast with '--shape_prepare' option" << e.what() << '\n';
302       exit(1);
303     }
304     try
305     {
306       handleShapeParam(_shape_prepare, shape_str);
307     }
308     catch (const std::exception &e)
309     {
310       std::cerr << "error with '--shape_prepare' option: " << shape_str << std::endl;
311       exit(1);
312     }
313   }
314
315   if (vm.count("shape_run"))
316   {
317     std::string shape_str;
318     try
319     {
320       shape_str = vm["shape_run"].as<std::string>();
321     }
322     catch (const std::bad_cast &e)
323     {
324       std::cerr << "error by bad cast with '--shape_run' option" << e.what() << '\n';
325       exit(1);
326     }
327     try
328     {
329       handleShapeParam(_shape_run, shape_str);
330     }
331     catch (const std::exception &e)
332     {
333       std::cerr << "error with '--shape_run' option: " << shape_str << std::endl;
334       exit(1);
335     }
336   }
337 }
338
339 } // end of namespace nnpkg_run