From e5e2676409a936431f87d31fb74d825257b20804 Mon Sep 17 00:00:00 2001 From: Eric Kunze Date: Tue, 13 Oct 2020 16:11:07 -0700 Subject: Initial checkin of TOSA reference_model and tests Change-Id: I2f8e7fa63e2ae40203e57d2cc8814bde3b312cb6 Signed-off-by: Eric Kunze --- reference_model/src/func_config.cc | 632 +++++++++++++++++++++++++++++++++++++ 1 file changed, 632 insertions(+) create mode 100644 reference_model/src/func_config.cc (limited to 'reference_model/src/func_config.cc') diff --git a/reference_model/src/func_config.cc b/reference_model/src/func_config.cc new file mode 100644 index 0000000..bd1ce32 --- /dev/null +++ b/reference_model/src/func_config.cc @@ -0,0 +1,632 @@ + +// Copyright (c) 2020, ARM Limited. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "func_config.h" +#include "func_debug.h" + +#define MAX_NAME_LEN 128 +#define MAX_DESC_LEN 128 + +#ifndef ARG_ERROR +#define ARG_ERROR(...) \ + fprintf(stderr, "ERROR: "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + return 1; +#endif + +// Parameter base name string table +const char* config_base_name_table[] = { +#define DEF_UNIT_START(UNIT) +#define DEF_UNIT_END(UNIT) +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) #NAME, +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) #NAME, +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) #NAME, +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) #NAME, +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR +#undef DEF_UNIT_OPTION +}; + +// Parameter description table +const char* config_param_desc_table[] = { +#define DEF_UNIT_START(UNIT) +#define DEF_UNIT_END(UNIT) +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) #DESC, +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) #DESC, +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) #DESC, +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) #DESC, +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR +}; + +// String table and enum for the option hierarchy level/sub-levels +// (no leaf options). Attribute at the top level have "BASE" as their +// enum value and an empty string for the value. +const char* config_hier_str_table[] = { + "", +#define DEF_UNIT_START(UNIT) #UNIT, +#define DEF_UNIT_END(UNIT) /**/ +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) /**/ +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) /**/ +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) /**/ +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) /**/ +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR +}; + +typedef enum config_hier_enum_t +{ + BASE, +#define DEF_UNIT_START(UNIT) CURRENT_UNIT, +#define DEF_UNIT_END(UNIT) /**/ +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) /**/ +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) /**/ +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) /**/ +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) /**/ +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR + + MAX_CONFIG_HIER +} config_hier_enum_t; + +// Mapping from a leaf parameter index to the +// position in the hierarchy. +config_hier_enum_t config_hierarchy_map[] = { +#define DEF_UNIT_START(UNIT) +#define DEF_UNIT_END(UNIT) +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) BASE, +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) BASE, +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) CURRENT_UNIT, +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) CURRENT_UNIT, +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR +}; + +#define CONFIG_PARAMETER_COUNT (sizeof(config_hierarchy_map) / sizeof(config_hier_enum_t)) + +// Dynamically generated at initialization +char** config_param_str_table = nullptr; + +// Initialize the configuration data structures +int func_model_init_config() +{ + // Initialize string table (builds the hierarchical names) + config_param_str_table = (char**)calloc(CONFIG_PARAMETER_COUNT, sizeof(char*)); + ASSERT_MEM(config_param_str_table); + + for (uint32_t i = 0; i < CONFIG_PARAMETER_COUNT; i++) + { + size_t len = strlen(config_base_name_table[i]) + 1; + if (config_hierarchy_map[i] != BASE) + { + ASSERT_MSG(config_hierarchy_map[i] <= MAX_CONFIG_HIER, + "Configuration parameter\'s hierarchy is out of bounds"); + len += strlen(config_hier_str_table[config_hierarchy_map[i]]) + 1; + } + config_param_str_table[i] = (char*)calloc(len, 1); + ASSERT_MEM(config_param_str_table[i]); + ASSERT_MSG(len < MAX_NAME_LEN, "option expanded name is too long: %s", config_base_name_table[i]); + + if (config_hierarchy_map[i] != BASE) + { + snprintf(config_param_str_table[i], len, "%s.%s", config_hier_str_table[config_hierarchy_map[i]], + config_base_name_table[i]); + } + else + { + snprintf(config_param_str_table[i], len, "%s", config_base_name_table[i]); + } + } + + return 0; +} + +int func_model_set_default_config(func_config_t* func_config) +{ + // Set default values in the global configuration data structure + bzero(func_config, sizeof(*func_config)); + +#define DEF_UNIT_START(UNIT) +#define DEF_UNIT_END(UNIT) +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) func_config->NAME = (DEFAULT); +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) strncpy(func_config->NAME, (DEFAULT), (LEN)-1); +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) func_config->UNIT.NAME = (DEFAULT); +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) strncpy(func_config->UNIT.NAME, (DEFAULT), (LEN)-1); +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR + + return 0; +} + +int func_model_config_cleanup() +{ + uint32_t i; + + if (!config_param_str_table) + return 1; + + for (i = 0; i < CONFIG_PARAMETER_COUNT; i++) + { + free(config_param_str_table[i]); + } + + free(config_param_str_table); + config_param_str_table = nullptr; + + return 0; +} + +int func_model_config_set_option(func_config_t* func_config, const char* name, const char* value) +{ + // Increment an index variable on each parameter position + // so that we can index both the position struct through the macro and the + // array of parameter names through a simple array of strings. + int param_idx = 0; + char* endptr; + + // TODO: does not handle strings yet. Can set magic values on FMT to + // choose a string copy vs strtoull +#define DEF_UNIT_START(UNIT) +#define DEF_UNIT_END(UNIT) +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) \ + if (!strcmp(config_param_str_table[param_idx], name)) \ + { \ + func_config->NAME = (uint64_t)strtoll(value, &endptr, 0); \ + if (endptr == value) \ + { \ + ARG_ERROR("Cannot parse option: %s = %s", name, value); \ + } \ + return 0; \ + } \ + param_idx++; + +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) \ + if (!strcmp(config_param_str_table[param_idx], name)) \ + { \ + if (strlen(value) >= LEN) \ + { \ + ARG_ERROR("Option value is too long: %s = %s", name, value); \ + } \ + strncpy(func_config->NAME, value, (LEN)-1); \ + return 0; \ + } \ + param_idx++; + +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) \ + if (!strcmp(config_param_str_table[param_idx], name)) \ + { \ + func_config->UNIT.NAME = (uint64_t)strtoll(value, &endptr, 0); \ + if (endptr == value) \ + { \ + ARG_ERROR("Cannot parse option: %s = %s", name, value); \ + } \ + return 0; \ + } \ + param_idx++; + +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) \ + if (!strcmp(config_param_str_table[param_idx], name)) \ + { \ + if (strlen(value) >= LEN) \ + { \ + ARG_ERROR("Option value is too long: %s = %s", name, value); \ + } \ + strncpy(func_config->UNIT.NAME, value, (LEN)-1); \ + return 0; \ + } \ + param_idx++; + +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR + + // No match! + ARG_ERROR("Cannot find option: %s", name); + + return 1; +} + +int func_model_config_get_option_by_name(func_config_t* func_config, const char* name, uint64_t* val) +{ + // Increment an index variable on each parameter position + // so that we can index both the position struct through the macro and the + // array of parameter names through a simple array of strings. + int param_idx = 0; + +#define DEF_UNIT_START(UNIT) +#define DEF_UNIT_END(UNIT) + +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) param_idx++; + +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, FMT, DEFAULT) param_idx++; + +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) \ + if (!strcmp(config_param_str_table[param_idx], name)) \ + { \ + *val = func_config->NAME; \ + return 0; \ + } \ + param_idx++; + +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) \ + if (!strcmp(config_param_str_table[param_idx], name)) \ + { \ + *val = func_config->UNIT.NAME; \ + return 0; \ + } \ + param_idx++; + +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR + // No match! + return 1; +} +int func_model_config_get_str_option_by_name(func_config_t* func_config, + const char* name, + char* value, + const uint32_t len) +{ + // Increment an index variable on each parameter position + // so that we can index both the position struct through the macro and the + // array of parameter names through a simple array of strings. + int param_idx = 0; + +#define DEF_UNIT_START(UNIT) +#define DEF_UNIT_END(UNIT) +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) \ + if (!strcmp(config_param_str_table[param_idx], name)) \ + { \ + strncpy(value, func_config->NAME, len - 1); \ + return 0; \ + } \ + param_idx++; + +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) \ + if (!strcmp(config_param_str_table[param_idx], name)) \ + { \ + strncpy(value, func_config->UNIT.NAME, len - 1); \ + return 0; \ + } \ + param_idx++; + +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) param_idx++; + +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) param_idx++; + +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR + // No match! + return 1; +} + +int func_config_print_config_help(FILE* out) +{ + fprintf(out, "%-40s %s\n", "Option", "Description"); + fprintf(out, "%-40s %s\n", "------", "-----------"); + + for (uint32_t i = 0; i < CONFIG_PARAMETER_COUNT; i++) + { + fprintf(out, "-C%-40s %s\n", config_param_str_table[i], config_param_desc_table[i]); + } + + fprintf(out, "\n"); + + return 0; +} + +int func_model_print_config(func_config_t* func_config, FILE* out) +{ +#define DEF_UNIT_START(UNIT) +#define DEF_UNIT_END(UNIT) +#define DEF_OPTION(NAME, DESC, TYPE, FMT, DEFAULT) fprintf(out, "%-40s = " FMT "\n", #NAME, func_config->NAME); +#define DEF_UNIT_OPTION(UNIT, NAME, DESC, TYPE, FMT, DEFAULT) \ + fprintf(out, "%-40s = " FMT "\n", #UNIT "." #NAME, func_config->UNIT.NAME); +#define DEF_OPTION_STR(NAME, DESC, LEN, DEFAULT) fprintf(out, "%-40s = %s\n", #NAME, func_config->NAME); +#define DEF_UNIT_OPTION_STR(UNIT, NAME, DESC, LEN, DEFAULT) \ + fprintf(out, "%-40s = %s\n", #UNIT "." #NAME, func_config->UNIT.NAME); + +#define FOF_HEX "0x%llx" +#define FOF_DEC "%" PRIu32 +#define FOF_DECU64 "%" PRIu64 + +#include "func_config.def" +#undef DEF_UNIT_START +#undef DEF_UNIT_END +#undef DEF_OPTION +#undef DEF_UNIT_OPTION +#undef DEF_OPTION_STR +#undef DEF_UNIT_OPTION_STR + + return 0; +} + +static const char* programname; + +void func_model_print_debug_masks(FILE* out) +{ + fprintf(out, "\t List of components:\n"); +#define DEBUG_MODE(string, value) fprintf(out, "\t\t" #string "\n"); +#include "debug_modes.def" +#undef DEBUG_MODE +} + +int func_model_print_help(FILE* out) +{ + fprintf(out, "TOSA Reference Model help\n\n"); + + fprintf(out, + "Usage: %s [-c] [-C ] [-d ] [-h] [-i ] [-l ] [-F " + "]\n", + programname); + fprintf(out, "\t-c - Print list of config options\n"); + fprintf(out, "\t-C - modify config option to \n"); + fprintf(out, "\t-d - parse as file of config options\n"); + fprintf(out, "\t-h - show this help message and exit\n"); + fprintf( + out, + "\t-i , - set input tensor to the values from \n"); + fprintf(out, "\t-l - set log verbosity\n"); + fprintf(out, "\t-o - set debug log file\n"); + fprintf(out, "\n"); + + func_config_print_config_help(stdout); + + return 0; +} + +static const char* get_arg_text(int& index, const int argc, const char** argv) +{ + if (strlen(argv[index]) > 2) + { + return argv[index] + 2; + } + + if ((index + 1 == argc) || (argv[index + 1][0] == '-')) + { + fprintf(stderr, "No option value found for option %s\n", argv[index]); + return ""; + } + + index++; + return argv[index]; +} + +// Read the command line arguments +int func_model_parse_cmd_line(func_config_t* func_config, func_debug_t* func_debug, const int argc, const char** argv) +{ + int i; + programname = argv[0]; + for (i = 1; i < argc; i++) + { + // All command line arguments must begin with -X where X is a recognized character + if (strlen(argv[i]) < 2 || argv[i][0] != '-') + { + func_model_print_help(stderr); + ARG_ERROR("Command line argument at position %d not valid: %s", i, argv[i]); + } + + switch (argv[i][1]) + { + // Model parameters may be overridden with the -Cname=value switch + case 'c': + func_config_print_config_help(stderr); + return 1; + + case 'C': + { + const char *name = nullptr, *value = nullptr; + + // Break the string into name and value parts + name = get_arg_text(i, argc, argv); + value = strchr(name, '='); + + if (value == nullptr) + { + func_model_print_help(stderr); + ARG_ERROR("Cannot parse -C argument at position %d: %s", i, argv[i]); + } + + *const_cast(value) = 0; + + if (func_model_config_set_option(func_config, name, value + 1)) + { + func_model_print_help(stderr); + ARG_ERROR("Cannot parse -C argument at position %d: %s", i, argv[i]); + } + break; + } + + case 'd': + case 'D': + { + func_debug_set_mask(func_debug, get_arg_text(i, argc, argv)); + break; + } + case 'F': + { + // Read a flat configuration file + if (func_model_parse_flat_config_file(func_config, get_arg_text(i, argc, argv))) + return 1; + + break; + } + case 'h': + func_model_print_help(stderr); + return 1; + + case 'i': + { + // shortcut for '-Cinput_tensor=' + if (func_model_config_set_option(func_config, "input_tensor", get_arg_text(i, argc, argv))) + { + func_model_print_help(stderr); + ARG_ERROR("Cannot set input tensor config value"); + } + break; + } + case 'l': + { + // Debug verbosity/logging level + func_debug_set_verbosity(func_debug, get_arg_text(i, argc, argv)); + break; + } + case 'o': + { + func_debug_set_file(func_debug, get_arg_text(i, argc, argv)); + break; + } + default: + func_model_print_help(stderr); + ARG_ERROR("Unrecognized argument at position %d: %s", i, argv[i]); + } + } + + return 0; +} + +int func_model_parse_flat_config_file(func_config_t* func_config, const char* filename) +{ + const int MAX_LINE_LEN = 1024; + + FILE* infile = nullptr; + char line_buf[MAX_LINE_LEN]; + int line = 1; + + infile = fopen(filename, "r"); + + if (infile == nullptr) + { + ARG_ERROR("Cannot open config file: %s\n", filename); + } + + while (fgets(line_buf, MAX_LINE_LEN - 1, infile) != nullptr) + { + char *name = line_buf, *value = nullptr, *comment = nullptr, *ptr = nullptr; + + // Remove comments + comment = strchr(line_buf, '#'); + + if (comment) + *comment = 0; + + // Break the string into name and value parts + name = line_buf; + + // Remove leading whitespace + while (*name && isspace(*name)) + name++; + + // Empty line? + if (*name == 0) + { + line++; + continue; + } + + value = strchr(name, '='); + + // Missing value + if (value == nullptr) + { + ARG_ERROR("Cannot parse parameter in %s at line %d: %s", filename, line, line_buf); + } + + // Remove the = + *value = 0; + value++; + + // Trim off any whitespace at the end of the value + ptr = value; + while (*ptr != 0 && !isspace(*ptr)) + ptr++; + *ptr = 0; + + // Include a nested file + if (!strcmp(name, "include")) + { + if (func_model_parse_flat_config_file(func_config, value)) + return 1; + line++; + continue; + } + + if (func_model_config_set_option(func_config, name, value)) + { + func_model_print_help(stderr); + ARG_ERROR("Cannot set parameter in %s at line %d: %s", filename, line, line_buf) + } + + line++; + } + + fclose(infile); + + return 0; +} -- cgit v1.2.1