blob: 5c2735dae2a7574158e93f7b3faa0e0a3de0460b [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
Matthew Sloyanba5fad32022-09-26 13:31:43 +010016#include "model_runner.h"
17#include "version.h"
Eric Kunzee5e26762020-10-13 16:11:07 -070018
Matthew Sloyanba5fad32022-09-26 13:31:43 +010019#include "command_line_utils.h"
Eric Kunzee5e26762020-10-13 16:11:07 -070020#include "ops/op_factory.h"
21#include "subgraph_traverser.h"
22#include "tosa_serialization_handler.h"
James Ward24dbc422022-10-19 12:20:31 +010023#include "arith_util.h"
Eric Kunzee5e26762020-10-13 16:11:07 -070024
Kevin Chengcd79f0e2021-06-03 15:00:34 -070025#include <fstream>
Matthew Sloyanba5fad32022-09-26 13:31:43 +010026#include <iostream>
27#include <stdio.h>
28#include <Eigen/CXX11/Tensor>
Kevin Chengcd79f0e2021-06-03 15:00:34 -070029#include <nlohmann/json.hpp>
30
Eric Kunzee5e26762020-10-13 16:11:07 -070031using namespace TosaReference;
32using namespace tosa;
Kevin Chengcd79f0e2021-06-03 15:00:34 -070033using json = nlohmann::json;
Eric Kunzee5e26762020-10-13 16:11:07 -070034
Kevin Chengcd79f0e2021-06-03 15:00:34 -070035int initTestDesc(json& test_desc);
36int readInputTensors(SubgraphTraverser& gt, json test_desc);
37int writeFinalTensors(SubgraphTraverser& gt, json test_desc);
38int loadGraph(TosaSerializationHandler& tsh, json test_desc);
Eric Kunzee5e26762020-10-13 16:11:07 -070039
Eric Kunze286f8342022-06-22 11:30:23 -070040int main(int argc, char** argv)
Eric Kunzee5e26762020-10-13 16:11:07 -070041{
Matthew Sloyanba5fad32022-09-26 13:31:43 +010042 TosaVersion model_version(TOSA_REFERENCE_MODEL_VERSION_MAJOR,
43 TOSA_REFERENCE_MODEL_VERSION_MINOR,
44 TOSA_REFERENCE_MODEL_VERSION_PATCH,
45 TOSA_REFERENCE_MODEL_VERSION_DRAFT);
Kevin Cheng10096742021-10-20 19:51:41 +000046
Eric Kunzee5e26762020-10-13 16:11:07 -070047 // Initialize configuration and debug subsystems
Eric Kunze286f8342022-06-22 11:30:23 -070048 g_func_debug.init_debug(0);
Eric Kunzee5e26762020-10-13 16:11:07 -070049
Eric Kunze286f8342022-06-22 11:30:23 -070050 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 -070051 {
52 return 1;
53 }
54
Kevin Cheng10096742021-10-20 19:51:41 +000055 TosaSerializationHandler tsh;
56 TosaVersion::compat_t is_compat = model_version.is_compatible(tsh.GetVersion());
57 switch (is_compat)
58 {
59 case TosaVersion::compat_t::COMPLETELY_COMPATIBLE:
60 break;
61 case TosaVersion::compat_t::PARTIALLY_COMPATIBLE:
62 printf("WARNING: Reference model version %s is partially compatible with serializer version %s\n",
63 model_version.to_string().c_str(), tsh.GetVersion().to_string().c_str());
64 break;
65 case TosaVersion::compat_t::NOT_COMPATIBLE:
66 printf("ERROR: Reference model version %s is not compatible with serializer version %s\n",
67 model_version.to_string().c_str(), tsh.GetVersion().to_string().c_str());
68 return TOSA_VERSION_MISMATCH;
69 }
70
James Ward24dbc422022-10-19 12:20:31 +010071 g_func_config.float_is_big_endian = float_is_big_endian();
72
Kevin Chengcd79f0e2021-06-03 15:00:34 -070073 json test_desc;
74
75 // Initialize test descriptor
76 if (initTestDesc(test_desc))
77 {
Kevin Cheng903763c2021-09-28 16:14:52 -070078 FATAL_ERROR("Unable to load test json");
Kevin Chengcd79f0e2021-06-03 15:00:34 -070079 }
80
81 if (loadGraph(tsh, test_desc))
Eric Kunzee5e26762020-10-13 16:11:07 -070082 {
Kevin Cheng903763c2021-09-28 16:14:52 -070083 FATAL_ERROR("Unable to load graph");
Eric Kunzee5e26762020-10-13 16:11:07 -070084 }
85
Eric Kunzee5e26762020-10-13 16:11:07 -070086 SubgraphTraverser main_gt(tsh.GetMainBlock(), &tsh);
87
88 if (main_gt.initializeGraph())
89 {
Kevin Chengacb550f2021-06-29 15:32:19 -070090 WARNING("Unable to initialize main graph traverser.");
91 goto done;
Eric Kunzee5e26762020-10-13 16:11:07 -070092 }
93
94 if (main_gt.linkTensorsAndNodes())
95 {
Kevin Cheng903763c2021-09-28 16:14:52 -070096 WARNING("Failed to link tensors and nodes");
97 goto done;
Eric Kunzee5e26762020-10-13 16:11:07 -070098 }
99
100 if (main_gt.validateGraph())
101 {
Kevin Cheng6097c3d2021-09-23 15:25:24 -0700102 WARNING("Failed to validate graph. Evaluation aborted.");
Kevin Cheng6097c3d2021-09-23 15:25:24 -0700103 goto done;
Eric Kunzee5e26762020-10-13 16:11:07 -0700104 }
105
Kevin Chengcc61be32021-10-14 17:09:57 -0700106 if (main_gt.allocateTensor())
107 {
108 WARNING("Failed to allocate tensor. Evaluation aborted.");
109 goto done;
110 }
111
Eric Kunzee5e26762020-10-13 16:11:07 -0700112 if (g_func_config.validate_only)
113 {
114 goto done;
115 }
116
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700117 if (readInputTensors(main_gt, test_desc))
Eric Kunzee5e26762020-10-13 16:11:07 -0700118 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700119 FATAL_ERROR("Unable to read input tensors");
Eric Kunzee5e26762020-10-13 16:11:07 -0700120 }
121
122 if (g_func_config.eval)
123 {
124
Kevin Chengacb550f2021-06-29 15:32:19 -0700125 // evaluateAll() returns 1 if graph evaluation is forced to be terminated earlier.
Eric Kunzee5e26762020-10-13 16:11:07 -0700126 if (main_gt.evaluateAll())
127 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700128 ASSERT_MSG(main_gt.getGraphStatus() != GraphStatus::TOSA_VALID,
129 "Upon evaluateAll() returning 1, graph can not be VALID.");
130 }
131 else
132 {
133 ASSERT_MSG(main_gt.getGraphStatus() == GraphStatus::TOSA_VALID ||
134 main_gt.getGraphStatus() == GraphStatus::TOSA_UNPREDICTABLE,
135 "Upon evaluateAll() returning 0, graph can only be VALID/UNPREDICTABLE.");
Eric Kunzee5e26762020-10-13 16:11:07 -0700136 }
137
Kevin Chengacb550f2021-06-29 15:32:19 -0700138 // Only generate output tensor if graph is valid.
139 if (main_gt.getGraphStatus() == GraphStatus::TOSA_VALID)
Eric Kunzee5e26762020-10-13 16:11:07 -0700140 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700141 // make sure output tensor is evaluated and show its value
142 int num_output_tensors = main_gt.getNumOutputTensors();
143 bool all_output_valid = true;
144 for (int i = 0; i < num_output_tensors; i++)
Eric Kunzee5e26762020-10-13 16:11:07 -0700145 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700146 const Tensor* ct = main_gt.getOutputTensor(i);
147 ASSERT_MEM(ct);
148 if (!ct->getIsValid())
Eric Kunzee5e26762020-10-13 16:11:07 -0700149 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700150 ct->dumpTensorParams(g_func_debug.func_debug_file);
151 if (DEBUG_ENABLED(DEBUG_VERB_HIGH, GT))
152 {
153 ct->dumpTensor(g_func_debug.func_debug_file);
154 }
155 all_output_valid = false;
Eric Kunzee5e26762020-10-13 16:11:07 -0700156 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700157 }
Kevin Chengacb550f2021-06-29 15:32:19 -0700158 if (!all_output_valid)
Eric Kunzee5e26762020-10-13 16:11:07 -0700159 {
Kevin Chengacb550f2021-06-29 15:32:19 -0700160 main_gt.dumpGraph(g_func_debug.func_debug_file);
Kevin Cheng903763c2021-09-28 16:14:52 -0700161 FATAL_ERROR(
Kevin Chengacb550f2021-06-29 15:32:19 -0700162 "SubgraphTraverser \"main\" error: Output tensors are not all valid at the end of evaluation.");
163 }
164
165 if (g_func_config.output_tensors)
166 {
167 if (writeFinalTensors(main_gt, test_desc))
168 {
169 WARNING("Errors encountered in saving output tensors");
170 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700171 }
172 }
173 }
174
175done:
Kevin Chengacb550f2021-06-29 15:32:19 -0700176 switch (main_gt.getGraphStatus())
177 {
178 case GraphStatus::TOSA_VALID:
179 // Result is valid.
180 break;
181 case GraphStatus::TOSA_UNPREDICTABLE:
182 fprintf(stderr, "Graph result: UNPREDICTABLE.\n");
183 break;
184 case GraphStatus::TOSA_ERROR:
185 fprintf(stderr, "Graph result: ERROR.\n");
186 break;
187 default:
188 fprintf(stderr, "Unknown graph status code=%d.\n", (int)main_gt.getGraphStatus());
189 }
190
Eric Kunze286f8342022-06-22 11:30:23 -0700191 g_func_debug.fini_debug();
Eric Kunzee5e26762020-10-13 16:11:07 -0700192
Kevin Chengacb550f2021-06-29 15:32:19 -0700193 return (int)main_gt.getGraphStatus();
Eric Kunzee5e26762020-10-13 16:11:07 -0700194}
195
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700196int loadGraph(TosaSerializationHandler& tsh, json test_desc)
Eric Kunzee5e26762020-10-13 16:11:07 -0700197{
198 char graph_fullname[1024];
199
Eric Kunze286f8342022-06-22 11:30:23 -0700200 snprintf(graph_fullname, sizeof(graph_fullname), "%s/%s", g_func_config.flatbuffer_dir.c_str(),
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700201 test_desc["tosa_file"].get<std::string>().c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700202
203 if (strlen(graph_fullname) <= 2)
204 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700205 FATAL_ERROR("Missing required argument: Check \"tosa_file\" in .json specified by -Ctosa_desc=");
Eric Kunzee5e26762020-10-13 16:11:07 -0700206 }
207
208 const char JSON_EXT[] = ".json";
209 int is_json = 0;
210 {
211 // look for JSON file extension
212 size_t suffix_len = strlen(JSON_EXT);
213 size_t str_len = strlen(graph_fullname);
214
215 if (str_len > suffix_len && strncasecmp(graph_fullname + (str_len - suffix_len), JSON_EXT, suffix_len) == 0)
216 {
217 is_json = 1;
218 }
219 }
220
221 if (is_json)
222 {
Eric Kunze286f8342022-06-22 11:30:23 -0700223 if (tsh.LoadFileSchema(g_func_config.operator_fbs.c_str()))
Eric Kunzee5e26762020-10-13 16:11:07 -0700224 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700225 FATAL_ERROR("\nJSON file detected. Unable to load TOSA flatbuffer schema from: %s\nCheck -Coperator_fbs=",
Eric Kunze286f8342022-06-22 11:30:23 -0700226 g_func_config.operator_fbs.c_str());
Eric Kunzee5e26762020-10-13 16:11:07 -0700227 }
228
229 if (tsh.LoadFileJson(graph_fullname))
230 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700231 FATAL_ERROR("\nError loading JSON graph file: %s\nCheck -Ctest_desc=, -Ctosa_file= and -Cflatbuffer_dir=",
232 graph_fullname);
Eric Kunzee5e26762020-10-13 16:11:07 -0700233 }
234 }
235 else
236 {
237 if (tsh.LoadFileTosaFlatbuffer(graph_fullname))
238 {
Kevin Cheng903763c2021-09-28 16:14:52 -0700239 FATAL_ERROR(
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700240 "\nError loading TOSA flatbuffer file: %s\nCheck -Ctest_desc=, -Ctosa_file= and -Cflatbuffer_dir=",
241 graph_fullname);
Eric Kunzee5e26762020-10-13 16:11:07 -0700242 }
243 }
244
245 return 0;
246}
247
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700248int readInputTensors(SubgraphTraverser& gt, json test_desc)
Eric Kunzee5e26762020-10-13 16:11:07 -0700249{
250 int tensorCount = gt.getNumInputTensors();
251 Tensor* tensor;
252 char filename[1024];
253
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700254 try
Eric Kunzee5e26762020-10-13 16:11:07 -0700255 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700256 if ((tensorCount != (int)test_desc["ifm_name"].size()) || (tensorCount != (int)test_desc["ifm_file"].size()))
Eric Kunzee5e26762020-10-13 16:11:07 -0700257 {
Eric Kunze286f8342022-06-22 11:30:23 -0700258 WARNING("Number of input tensors(%d) doesn't match name(%ld)/file(%ld) in test descriptor.", tensorCount,
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700259 test_desc["ifm_name"].size(), test_desc["ifm_file"].size());
Eric Kunzee5e26762020-10-13 16:11:07 -0700260 return 1;
261 }
262
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700263 for (int i = 0; i < tensorCount; i++)
Eric Kunzee5e26762020-10-13 16:11:07 -0700264 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700265 tensor = gt.getInputTensorByName(test_desc["ifm_name"][i].get<std::string>());
266 if (!tensor)
Eric Kunzee5e26762020-10-13 16:11:07 -0700267 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700268 WARNING("Unable to find input tensor %s", test_desc["ifm_name"][i].get<std::string>().c_str());
269 return 1;
270 }
271
Eric Kunze286f8342022-06-22 11:30:23 -0700272 snprintf(filename, sizeof(filename), "%s/%s", g_func_config.flatbuffer_dir.c_str(),
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700273 test_desc["ifm_file"][i].get<std::string>().c_str());
274
275 DEBUG_MED(GT, "Loading input tensor %s from filename: %s", tensor->getName().c_str(), filename);
276
Kevin Chengcc61be32021-10-14 17:09:57 -0700277 if (!tensor->is_allocated())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700278 {
Kevin Chengcc61be32021-10-14 17:09:57 -0700279 WARNING("Tensor %s is not allocated before being initialized", tensor->getName().c_str());
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700280 return 1;
281 }
282
283 if (tensor->readFromNpyFile(filename))
284 {
285 WARNING("Unable to read input tensor %s from filename: %s", tensor->getName().c_str(), filename);
286 tensor->dumpTensorParams(g_func_debug.func_debug_file);
287 return 1;
288 }
289
290 // Push ready consumers to the next node list
291 for (auto gn : tensor->getConsumers())
292 {
293 if (gn->hasAllInputsReady() && !gn->getOnNextNodeList())
294 {
295 gt.addToNextNodeList(gn);
296 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700297 }
298 }
299 }
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700300 catch (nlohmann::json::type_error& e)
301 {
302 WARNING("Fail accessing test descriptor: %s", e.what());
303 return 1;
304 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700305
306 if (DEBUG_ENABLED(DEBUG_VERB_HIGH, GT))
307 {
308 gt.dumpNextNodeList(g_func_debug.func_debug_file);
309 }
310
311 return 0;
312}
313
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700314int writeFinalTensors(SubgraphTraverser& gt, json test_desc)
Eric Kunzee5e26762020-10-13 16:11:07 -0700315{
316 int tensorCount = gt.getNumOutputTensors();
317 const Tensor* tensor;
318 char filename[1024];
319
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700320 try
Eric Kunzee5e26762020-10-13 16:11:07 -0700321 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700322 if ((tensorCount != (int)test_desc["ofm_name"].size()) || (tensorCount != (int)test_desc["ofm_file"].size()))
Eric Kunzee5e26762020-10-13 16:11:07 -0700323 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700324 WARNING("Number of output tensors(%d) doesn't match name(%ld)/file(%ld) in test descriptor.", tensorCount,
325 test_desc["ofm_name"].size(), test_desc["ofm_file"].size());
Eric Kunzee5e26762020-10-13 16:11:07 -0700326 return 1;
327 }
328
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700329 for (int i = 0; i < tensorCount; i++)
Eric Kunzee5e26762020-10-13 16:11:07 -0700330 {
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700331 tensor = gt.getOutputTensorByName(test_desc["ofm_name"][i].get<std::string>());
332 if (!tensor)
333 {
334 WARNING("Unable to find output tensor %s", test_desc["ofm_name"][i].get<std::string>().c_str());
335 return 1;
336 }
337
Eric Kunze286f8342022-06-22 11:30:23 -0700338 snprintf(filename, sizeof(filename), "%s/%s", g_func_config.output_dir.c_str(),
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700339 test_desc["ofm_file"][i].get<std::string>().c_str());
340
341 DEBUG_MED(GT, "Writing output tensor[%d] %s to filename: %s", i, tensor->getName().c_str(), filename);
342
343 if (tensor->writeToNpyFile(filename))
344 {
345 WARNING("Unable to write output tensor[%d] %s to filename: %s", i, tensor->getName().c_str(), filename);
346 return 1;
347 }
348 }
349 }
350 catch (nlohmann::json::type_error& e)
351 {
352 WARNING("Fail accessing test descriptor: %s", e.what());
353 return 1;
354 }
355
356 return 0;
357}
358
359// Read "foo,bar,..." and return std::vector({foo, bar, ...})
360std::vector<std::string> parseFromString(std::string raw_str)
361{
362 bool last_pair = false;
363 std::string::size_type start = 0, end;
364 std::string name;
365
366 std::vector<std::string> result;
367 do
368 {
369 end = raw_str.find(',', start);
370 if (end == std::string::npos)
371 last_pair = true;
372
373 name = raw_str.substr(start, end);
374
375 result.push_back(name);
376
377 start = end + 1; // skip comma
378 } while (!last_pair);
379
380 return result;
381}
382
383int initTestDesc(json& test_desc)
384{
385 std::ifstream ifs(g_func_config.test_desc);
386
387 if (ifs.good())
388 {
389 try
390 {
391 test_desc = nlohmann::json::parse(ifs);
392 }
393 catch (nlohmann::json::parse_error& e)
394 {
395 WARNING("Error parsing test descriptor json: %s", e.what());
Eric Kunzee5e26762020-10-13 16:11:07 -0700396 return 1;
397 }
398 }
Jared Smolens62a7b7f2022-03-19 05:42:27 +0000399 else
400 {
Eric Kunze286f8342022-06-22 11:30:23 -0700401 WARNING("Cannot open input file: %s", g_func_config.test_desc.c_str());
Jared Smolens62a7b7f2022-03-19 05:42:27 +0000402 return 1;
403 }
Eric Kunzee5e26762020-10-13 16:11:07 -0700404
Kevin Chengd5934142021-06-28 16:23:24 -0700405 // Overwrite flatbuffer_dir/output_dir with dirname(g_func_config.test_desc) if it's not specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700406 if (g_func_config.flatbuffer_dir.empty() || g_func_config.output_dir.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700407 {
Eric Kunze286f8342022-06-22 11:30:23 -0700408 std::string test_dir = g_func_config.test_desc.substr(0, g_func_config.test_desc.find_last_of("/\\"));
409 if (g_func_config.flatbuffer_dir.empty())
Kevin Chengd5934142021-06-28 16:23:24 -0700410 {
Eric Kunze286f8342022-06-22 11:30:23 -0700411 g_func_config.flatbuffer_dir = test_dir;
Kevin Chengd5934142021-06-28 16:23:24 -0700412 }
Eric Kunze286f8342022-06-22 11:30:23 -0700413 if (g_func_config.output_dir.empty())
Kevin Chengd5934142021-06-28 16:23:24 -0700414 {
Eric Kunze286f8342022-06-22 11:30:23 -0700415 g_func_config.output_dir = test_dir;
Kevin Chengd5934142021-06-28 16:23:24 -0700416 }
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700417 }
418
419 // Overwrite test_desc["tosa_file"] if -Ctosa_file= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700420 if (!g_func_config.tosa_file.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700421 {
Eric Kunze286f8342022-06-22 11:30:23 -0700422 test_desc["tosa_file"] = g_func_config.tosa_file;
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700423 }
424
425 // Overwrite test_desc["ifm_name"] if -Cifm_name= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700426 if (!g_func_config.ifm_name.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700427 {
Eric Kunze286f8342022-06-22 11:30:23 -0700428 std::vector<std::string> ifm_name_vec = parseFromString(g_func_config.ifm_name);
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700429 test_desc["ifm_name"] = ifm_name_vec;
430 }
431
432 // Overwrite test_desc["ifm_file"] if -Cifm_file= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700433 if (!g_func_config.ifm_file.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700434 {
Eric Kunze286f8342022-06-22 11:30:23 -0700435 std::vector<std::string> ifm_file_vec = parseFromString(g_func_config.ifm_file);
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700436 test_desc["ifm_file"] = ifm_file_vec;
437 }
438
439 // Overwrite test_desc["ofm_name"] if -Cofm_name= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700440 if (!g_func_config.ofm_name.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700441 {
Eric Kunze286f8342022-06-22 11:30:23 -0700442 std::vector<std::string> ofm_name_vec = parseFromString(g_func_config.ofm_name);
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700443 test_desc["ofm_name"] = ofm_name_vec;
444 }
445
446 // Overwrite test_desc["ofm_file"] if -Cofm_file= specified.
Eric Kunze286f8342022-06-22 11:30:23 -0700447 if (!g_func_config.ofm_file.empty())
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700448 {
Eric Kunze286f8342022-06-22 11:30:23 -0700449 std::vector<std::string> ofm_file_vec = parseFromString(g_func_config.ofm_file);
Kevin Chengcd79f0e2021-06-03 15:00:34 -0700450 test_desc["ofm_file"] = ofm_file_vec;
451 }
452
Eric Kunzee5e26762020-10-13 16:11:07 -0700453 return 0;
454}