blob: c1711bf79976aa7812663711fecb6081700a7230 [file] [log] [blame]
Eric Kunzee5e26762020-10-13 16:11:07 -07001
Jared Smolens62a7b7f2022-03-19 05:42:27 +00002// Copyright (c) 2020-2022, ARM Limited.
Eric Kunzee5e26762020-10-13 16:11:07 -07003//
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#include <stdio.h>
17
Eric Kunzee5e26762020-10-13 16:11:07 -070018#include "model_common.h"
19#include "ops/op_factory.h"
20#include "subgraph_traverser.h"
21#include "tosa_serialization_handler.h"
22#include <Eigen/CXX11/Tensor>
23#include <iostream>
24
Kevin Chengcd79f0e2021-06-03 15:00:34 -070025#include <fstream>
26#include <nlohmann/json.hpp>
27
Kevin Cheng10096742021-10-20 19:51:41 +000028#define MODEL_VERSION_MAJOR 0
Eric Kunzea8206e32022-08-29 16:30:16 -070029#define MODEL_VERSION_MINOR 40
Kevin Cheng10096742021-10-20 19:51:41 +000030#define MODEL_VERSION_PATCH 0
Eric Kunzea8206e32022-08-29 16:30:16 -070031#define MODEL_VERSION_DRAFT false
Kevin Cheng10096742021-10-20 19:51:41 +000032
Eric Kunzee5e26762020-10-13 16:11:07 -070033using namespace TosaReference;
34using namespace tosa;
Kevin Chengcd79f0e2021-06-03 15:00:34 -070035using json = nlohmann::json;
Eric Kunzee5e26762020-10-13 16:11:07 -070036
37// Global instantiation of configuration and debug objects
38func_config_t g_func_config;
39func_debug_t g_func_debug;
40
Kevin Chengcd79f0e2021-06-03 15:00:34 -070041int initTestDesc(json& test_desc);
42int readInputTensors(SubgraphTraverser& gt, json test_desc);
43int writeFinalTensors(SubgraphTraverser& gt, json test_desc);
44int loadGraph(TosaSerializationHandler& tsh, json test_desc);
Eric Kunzee5e26762020-10-13 16:11:07 -070045
Eric Kunze286f8342022-06-22 11:30:23 -070046int main(int argc, char** argv)
Eric Kunzee5e26762020-10-13 16:11:07 -070047{
Kevin Cheng10096742021-10-20 19:51:41 +000048 TosaVersion model_version(MODEL_VERSION_MAJOR, MODEL_VERSION_MINOR, MODEL_VERSION_PATCH, MODEL_VERSION_DRAFT);
49
Eric Kunzee5e26762020-10-13 16:11:07 -070050 // Initialize configuration and debug subsystems
Eric Kunze286f8342022-06-22 11:30:23 -070051 g_func_debug.init_debug(0);
Eric Kunzee5e26762020-10-13 16:11:07 -070052
Eric Kunze286f8342022-06-22 11:30:23 -070053 if (func_model_parse_cmd_line(g_func_config, g_func_debug, argc, argv, model_version.to_string().c_str()))
Eric Kunzee5e26762020-10-13 16:11:07 -070054 {
55 return 1;
56 }
57
Kevin Cheng10096742021-10-20 19:51:41 +000058 TosaSerializationHandler tsh;
59 TosaVersion::compat_t is_compat = model_version.is_compatible(tsh.GetVersion());
60 switch (is_compat)
61 {
62 case TosaVersion::compat_t::COMPLETELY_COMPATIBLE:
63 break;
64 case TosaVersion::compat_t::PARTIALLY_COMPATIBLE:
65 printf("WARNING: Reference model version %s is partially compatible with serializer version %s\n",
66 model_version.to_string().c_str(), tsh.GetVersion().to_string().c_str());
67 break;
68 case TosaVersion::compat_t::NOT_COMPATIBLE:
69 printf("ERROR: Reference model version %s is not compatible with serializer version %s\n",
70 model_version.to_string().c_str(), tsh.GetVersion().to_string().c_str());
71 return TOSA_VERSION_MISMATCH;
72 }
73
Kevin Chengcd79f0e2021-06-03 15:00:34 -070074 json test_desc;
75
76 // Initialize test descriptor
77 if (initTestDesc(test_desc))
78 {
Kevin Cheng903763c2021-09-28 16:14:52 -070079 FATAL_ERROR("Unable to load test json");
Kevin Chengcd79f0e2021-06-03 15:00:34 -070080 }
81
82 if (loadGraph(tsh, test_desc))
Eric Kunzee5e26762020-10-13 16:11:07 -070083 {
Kevin Cheng903763c2021-09-28 16:14:52 -070084 FATAL_ERROR("Unable to load graph");
Eric Kunzee5e26762020-10-13 16:11:07 -070085 }
86
Eric Kunzee5e26762020-10-13 16:11:07 -070087 SubgraphTraverser main_gt(tsh.GetMainBlock(), &tsh);
88
89 if (main_gt.initializeGraph())
90 {
Kevin Chengacb550f2021-06-29 15:32:19 -070091 WARNING("Unable to initialize main graph traverser.");
92 goto done;
Eric Kunzee5e26762020-10-13 16:11:07 -070093 }
94
95 if (main_gt.linkTensorsAndNodes())
96 {
Kevin Cheng903763c2021-09-28 16:14:52 -070097 WARNING("Failed to link tensors and nodes");
98 goto done;
Eric Kunzee5e26762020-10-13 16:11:07 -070099 }
100
101 if (main_gt.validateGraph())
102 {
Kevin Cheng6097c3d2021-09-23 15:25:24 -0700103 WARNING("Failed to validate graph. Evaluation aborted.");
Kevin Cheng6097c3d2021-09-23 15:25:24 -0700104 goto done;
Eric Kunzee5e26762020-10-13 16:11:07 -0700105 }
106
Kevin Chengcc61be32021-10-14 17:09:57 -0700107 if (main_gt.allocateTensor())
108 {
109 WARNING("Failed to allocate tensor. Evaluation aborted.");
110 goto done;
111 }
112
Eric Kunzee5e26762020-10-13 16:11:07 -0700113 if (g_func_config.validate_only)
114 {
115 goto done;
116 }
117
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700118 if (readInputTensors(main_gt, test_desc))
Eric Kunzee5e26762020-10-13 16:11:07 -0700119 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700120 FATAL_ERROR("Unable to read input tensors");
Eric Kunzee5e26762020-10-13 16:11:07 -0700121 }
122
123 if (g_func_config.eval)
124 {
125
Kevin Chengacb550f2021-06-29 15:32:19 -0700126 // evaluateAll() returns 1 if graph evaluation is forced to be terminated earlier.
Eric Kunzee5e26762020-10-13 16:11:07 -0700127 if (main_gt.evaluateAll())
128 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700129 ASSERT_MSG(main_gt.getGraphStatus() != GraphStatus::TOSA_VALID,
130 "Upon evaluateAll() returning 1, graph can not be VALID.");
131 }
132 else
133 {
134 ASSERT_MSG(main_gt.getGraphStatus() == GraphStatus::TOSA_VALID ||
135 main_gt.getGraphStatus() == GraphStatus::TOSA_UNPREDICTABLE,
136 "Upon evaluateAll() returning 0, graph can only be VALID/UNPREDICTABLE.");
Eric Kunzee5e26762020-10-13 16:11:07 -0700137 }
138
Kevin Chengacb550f2021-06-29 15:32:19 -0700139 // Only generate output tensor if graph is valid.
140 if (main_gt.getGraphStatus() == GraphStatus::TOSA_VALID)
Eric Kunzee5e26762020-10-13 16:11:07 -0700141 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700142 // make sure output tensor is evaluated and show its value
143 int num_output_tensors = main_gt.getNumOutputTensors();
144 bool all_output_valid = true;
145 for (int i = 0; i < num_output_tensors; i++)
Eric Kunzee5e26762020-10-13 16:11:07 -0700146 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700147 const Tensor* ct = main_gt.getOutputTensor(i);
148 ASSERT_MEM(ct);
149 if (!ct->getIsValid())
Eric Kunzee5e26762020-10-13 16:11:07 -0700150 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700151 ct->dumpTensorParams(g_func_debug.func_debug_file);
152 if (DEBUG_ENABLED(DEBUG_VERB_HIGH, GT))
153 {
154 ct->dumpTensor(g_func_debug.func_debug_file);
155 }
156 all_output_valid = false;
Eric Kunzee5e26762020-10-13 16:11:07 -0700157 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700158 }
Kevin Chengacb550f2021-06-29 15:32:19 -0700159 if (!all_output_valid)
Eric Kunzee5e26762020-10-13 16:11:07 -0700160 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700161 main_gt.dumpGraph(g_func_debug.func_debug_file);
Kevin Cheng903763c2021-09-28 16:14:52 -0700162 FATAL_ERROR(
Kevin Chengacb550f2021-06-29 15:32:19 -0700163 "SubgraphTraverser \"main\" error: Output tensors are not all valid at the end of evaluation.");
164 }
165
166 if (g_func_config.output_tensors)
167 {
168 if (writeFinalTensors(main_gt, test_desc))
169 {
170 WARNING("Errors encountered in saving output tensors");
171 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700172 }
173 }
174 }
175
176done:
Kevin Chengacb550f2021-06-29 15:32:19 -0700177 switch (main_gt.getGraphStatus())
178 {
179 case GraphStatus::TOSA_VALID:
180 // Result is valid.
181 break;
182 case GraphStatus::TOSA_UNPREDICTABLE:
183 fprintf(stderr, "Graph result: UNPREDICTABLE.\n");
184 break;
185 case GraphStatus::TOSA_ERROR:
186 fprintf(stderr, "Graph result: ERROR.\n");
187 break;
188 default:
189 fprintf(stderr, "Unknown graph status code=%d.\n", (int)main_gt.getGraphStatus());
190 }
191
Eric Kunze286f8342022-06-22 11:30:23 -0700192 g_func_debug.fini_debug();
Eric Kunzee5e26762020-10-13 16:11:07 -0700193
Kevin Chengacb550f2021-06-29 15:32:19 -0700194 return (int)main_gt.getGraphStatus();
Eric Kunzee5e26762020-10-13 16:11:07 -0700195}
196
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700197int loadGraph(TosaSerializationHandler& tsh, json test_desc)
Eric Kunzee5e26762020-10-13 16:11:07 -0700198{
199 char graph_fullname[1024];
200
Eric Kunze286f8342022-06-22 11:30:23 -0700201 snprintf(graph_fullname, sizeof(graph_fullname), "%s/%s", g_func_config.flatbuffer_dir.c_str(),
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700202 test_desc["tosa_file"].get<std::string>().c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700203
204 if (strlen(graph_fullname) <= 2)
205 {
Eric Kunze286f8342022-06-22 11:30:23 -0700206 func_model_print_help();
Kevin Cheng903763c2021-09-28 16:14:52 -0700207 FATAL_ERROR("Missing required argument: Check \"tosa_file\" in .json specified by -Ctosa_desc=");
Eric Kunzee5e26762020-10-13 16:11:07 -0700208 }
209
210 const char JSON_EXT[] = ".json";
211 int is_json = 0;
212 {
213 // look for JSON file extension
214 size_t suffix_len = strlen(JSON_EXT);
215 size_t str_len = strlen(graph_fullname);
216
217 if (str_len > suffix_len && strncasecmp(graph_fullname + (str_len - suffix_len), JSON_EXT, suffix_len) == 0)
218 {
219 is_json = 1;
220 }
221 }
222
223 if (is_json)
224 {
Eric Kunze286f8342022-06-22 11:30:23 -0700225 if (tsh.LoadFileSchema(g_func_config.operator_fbs.c_str()))
Eric Kunzee5e26762020-10-13 16:11:07 -0700226 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700227 FATAL_ERROR("\nJSON file detected. Unable to load TOSA flatbuffer schema from: %s\nCheck -Coperator_fbs=",
Eric Kunze286f8342022-06-22 11:30:23 -0700228 g_func_config.operator_fbs.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700229 }
230
231 if (tsh.LoadFileJson(graph_fullname))
232 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700233 FATAL_ERROR("\nError loading JSON graph file: %s\nCheck -Ctest_desc=, -Ctosa_file= and -Cflatbuffer_dir=",
234 graph_fullname);
Eric Kunzee5e26762020-10-13 16:11:07 -0700235 }
236 }
237 else
238 {
239 if (tsh.LoadFileTosaFlatbuffer(graph_fullname))
240 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700241 FATAL_ERROR(
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700242 "\nError loading TOSA flatbuffer file: %s\nCheck -Ctest_desc=, -Ctosa_file= and -Cflatbuffer_dir=",
243 graph_fullname);
Eric Kunzee5e26762020-10-13 16:11:07 -0700244 }
245 }
246
247 return 0;
248}
249
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700250int readInputTensors(SubgraphTraverser& gt, json test_desc)
Eric Kunzee5e26762020-10-13 16:11:07 -0700251{
252 int tensorCount = gt.getNumInputTensors();
253 Tensor* tensor;
254 char filename[1024];
255
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700256 try
Eric Kunzee5e26762020-10-13 16:11:07 -0700257 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700258 if ((tensorCount != (int)test_desc["ifm_name"].size()) || (tensorCount != (int)test_desc["ifm_file"].size()))
Eric Kunzee5e26762020-10-13 16:11:07 -0700259 {
Eric Kunze286f8342022-06-22 11:30:23 -0700260 WARNING("Number of input tensors(%d) doesn't match name(%ld)/file(%ld) in test descriptor.", tensorCount,
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700261 test_desc["ifm_name"].size(), test_desc["ifm_file"].size());
Eric Kunzee5e26762020-10-13 16:11:07 -0700262 return 1;
263 }
264
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700265 for (int i = 0; i < tensorCount; i++)
Eric Kunzee5e26762020-10-13 16:11:07 -0700266 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700267 tensor = gt.getInputTensorByName(test_desc["ifm_name"][i].get<std::string>());
268 if (!tensor)
Eric Kunzee5e26762020-10-13 16:11:07 -0700269 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700270 WARNING("Unable to find input tensor %s", test_desc["ifm_name"][i].get<std::string>().c_str());
271 return 1;
272 }
273
Eric Kunze286f8342022-06-22 11:30:23 -0700274 snprintf(filename, sizeof(filename), "%s/%s", g_func_config.flatbuffer_dir.c_str(),
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700275 test_desc["ifm_file"][i].get<std::string>().c_str());
276
277 DEBUG_MED(GT, "Loading input tensor %s from filename: %s", tensor->getName().c_str(), filename);
278
Kevin Chengcc61be32021-10-14 17:09:57 -0700279 if (!tensor->is_allocated())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700280 {
Kevin Chengcc61be32021-10-14 17:09:57 -0700281 WARNING("Tensor %s is not allocated before being initialized", tensor->getName().c_str());
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700282 return 1;
283 }
284
285 if (tensor->readFromNpyFile(filename))
286 {
287 WARNING("Unable to read input tensor %s from filename: %s", tensor->getName().c_str(), filename);
288 tensor->dumpTensorParams(g_func_debug.func_debug_file);
289 return 1;
290 }
291
292 // Push ready consumers to the next node list
293 for (auto gn : tensor->getConsumers())
294 {
295 if (gn->hasAllInputsReady() && !gn->getOnNextNodeList())
296 {
297 gt.addToNextNodeList(gn);
298 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700299 }
300 }
301 }
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700302 catch (nlohmann::json::type_error& e)
303 {
304 WARNING("Fail accessing test descriptor: %s", e.what());
305 return 1;
306 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700307
308 if (DEBUG_ENABLED(DEBUG_VERB_HIGH, GT))
309 {
310 gt.dumpNextNodeList(g_func_debug.func_debug_file);
311 }
312
313 return 0;
314}
315
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700316int writeFinalTensors(SubgraphTraverser& gt, json test_desc)
Eric Kunzee5e26762020-10-13 16:11:07 -0700317{
318 int tensorCount = gt.getNumOutputTensors();
319 const Tensor* tensor;
320 char filename[1024];
321
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700322 try
Eric Kunzee5e26762020-10-13 16:11:07 -0700323 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700324 if ((tensorCount != (int)test_desc["ofm_name"].size()) || (tensorCount != (int)test_desc["ofm_file"].size()))
Eric Kunzee5e26762020-10-13 16:11:07 -0700325 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700326 WARNING("Number of output tensors(%d) doesn't match name(%ld)/file(%ld) in test descriptor.", tensorCount,
327 test_desc["ofm_name"].size(), test_desc["ofm_file"].size());
Eric Kunzee5e26762020-10-13 16:11:07 -0700328 return 1;
329 }
330
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700331 for (int i = 0; i < tensorCount; i++)
Eric Kunzee5e26762020-10-13 16:11:07 -0700332 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700333 tensor = gt.getOutputTensorByName(test_desc["ofm_name"][i].get<std::string>());
334 if (!tensor)
335 {
336 WARNING("Unable to find output tensor %s", test_desc["ofm_name"][i].get<std::string>().c_str());
337 return 1;
338 }
339
Eric Kunze286f8342022-06-22 11:30:23 -0700340 snprintf(filename, sizeof(filename), "%s/%s", g_func_config.output_dir.c_str(),
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700341 test_desc["ofm_file"][i].get<std::string>().c_str());
342
343 DEBUG_MED(GT, "Writing output tensor[%d] %s to filename: %s", i, tensor->getName().c_str(), filename);
344
345 if (tensor->writeToNpyFile(filename))
346 {
347 WARNING("Unable to write output tensor[%d] %s to filename: %s", i, tensor->getName().c_str(), filename);
348 return 1;
349 }
350 }
351 }
352 catch (nlohmann::json::type_error& e)
353 {
354 WARNING("Fail accessing test descriptor: %s", e.what());
355 return 1;
356 }
357
358 return 0;
359}
360
361// Read "foo,bar,..." and return std::vector({foo, bar, ...})
362std::vector<std::string> parseFromString(std::string raw_str)
363{
364 bool last_pair = false;
365 std::string::size_type start = 0, end;
366 std::string name;
367
368 std::vector<std::string> result;
369 do
370 {
371 end = raw_str.find(',', start);
372 if (end == std::string::npos)
373 last_pair = true;
374
375 name = raw_str.substr(start, end);
376
377 result.push_back(name);
378
379 start = end + 1; // skip comma
380 } while (!last_pair);
381
382 return result;
383}
384
385int initTestDesc(json& test_desc)
386{
387 std::ifstream ifs(g_func_config.test_desc);
388
389 if (ifs.good())
390 {
391 try
392 {
393 test_desc = nlohmann::json::parse(ifs);
394 }
395 catch (nlohmann::json::parse_error& e)
396 {
397 WARNING("Error parsing test descriptor json: %s", e.what());
Eric Kunzee5e26762020-10-13 16:11:07 -0700398 return 1;
399 }
400 }
Jared Smolens62a7b7f2022-03-19 05:42:27 +0000401 else
402 {
Eric Kunze286f8342022-06-22 11:30:23 -0700403 WARNING("Cannot open input file: %s", g_func_config.test_desc.c_str());
Jared Smolens62a7b7f2022-03-19 05:42:27 +0000404 return 1;
405 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700406
Kevin Chengd5934142021-06-28 16:23:24 -0700407 // Overwrite flatbuffer_dir/output_dir with dirname(g_func_config.test_desc) if it's not specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700408 if (g_func_config.flatbuffer_dir.empty() || g_func_config.output_dir.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700409 {
Eric Kunze286f8342022-06-22 11:30:23 -0700410 std::string test_dir = g_func_config.test_desc.substr(0, g_func_config.test_desc.find_last_of("/\\"));
411 if (g_func_config.flatbuffer_dir.empty())
Kevin Chengd5934142021-06-28 16:23:24 -0700412 {
Eric Kunze286f8342022-06-22 11:30:23 -0700413 g_func_config.flatbuffer_dir = test_dir;
Kevin Chengd5934142021-06-28 16:23:24 -0700414 }
Eric Kunze286f8342022-06-22 11:30:23 -0700415 if (g_func_config.output_dir.empty())
Kevin Chengd5934142021-06-28 16:23:24 -0700416 {
Eric Kunze286f8342022-06-22 11:30:23 -0700417 g_func_config.output_dir = test_dir;
Kevin Chengd5934142021-06-28 16:23:24 -0700418 }
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700419 }
420
421 // Overwrite test_desc["tosa_file"] if -Ctosa_file= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700422 if (!g_func_config.tosa_file.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700423 {
Eric Kunze286f8342022-06-22 11:30:23 -0700424 test_desc["tosa_file"] = g_func_config.tosa_file;
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700425 }
426
427 // Overwrite test_desc["ifm_name"] if -Cifm_name= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700428 if (!g_func_config.ifm_name.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700429 {
Eric Kunze286f8342022-06-22 11:30:23 -0700430 std::vector<std::string> ifm_name_vec = parseFromString(g_func_config.ifm_name);
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700431 test_desc["ifm_name"] = ifm_name_vec;
432 }
433
434 // Overwrite test_desc["ifm_file"] if -Cifm_file= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700435 if (!g_func_config.ifm_file.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700436 {
Eric Kunze286f8342022-06-22 11:30:23 -0700437 std::vector<std::string> ifm_file_vec = parseFromString(g_func_config.ifm_file);
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700438 test_desc["ifm_file"] = ifm_file_vec;
439 }
440
441 // Overwrite test_desc["ofm_name"] if -Cofm_name= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700442 if (!g_func_config.ofm_name.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700443 {
Eric Kunze286f8342022-06-22 11:30:23 -0700444 std::vector<std::string> ofm_name_vec = parseFromString(g_func_config.ofm_name);
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700445 test_desc["ofm_name"] = ofm_name_vec;
446 }
447
448 // Overwrite test_desc["ofm_file"] if -Cofm_file= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700449 if (!g_func_config.ofm_file.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700450 {
Eric Kunze286f8342022-06-22 11:30:23 -0700451 std::vector<std::string> ofm_file_vec = parseFromString(g_func_config.ofm_file);
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700452 test_desc["ofm_file"] = ofm_file_vec;
453 }
454
Eric Kunzee5e26762020-10-13 16:11:07 -0700455 return 0;
456}