| /* |
| * Copyright (C) 2023 The Android Open Source Project |
| * |
| * Permission is hereby granted, free of charge, to any person obtaining |
| * a copy of this software and associated documentation files |
| * (the "Software"), to deal in the Software without restriction, |
| * including without limitation the rights to use, copy, modify, merge, |
| * publish, distribute, sublicense, and/or sell copies of the Software, |
| * and to permit persons to whom the Software is furnished to do so, |
| * subject to the following conditions: |
| * |
| * The above copyright notice and this permission notice shall be |
| * included in all copies or substantial portions of the Software. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| #pragma once |
| #include <ctype.h> |
| #include <stdio.h> |
| |
| #include <lib/unittest/unittest.h> |
| |
| #include "trusty_bench_option_cb.h" |
| |
| /** |
| * enum bench_aggregate_idx - The position of the calculated aggregate in the |
| * aggregate array of the bench_metric_node |
| * @BENCH_AGGREGATE_MIN: index of the current minimum value for this metric. |
| * @BENCH_AGGREGATE_MAX: index of the current maximum value for this metric. |
| * @BENCH_AGGREGATE_AVG: index of the current average value for this metric. |
| * @BENCH_AGGREGATE_COLD:index of the cold run value for this metric. |
| * @BENCH_NUM_AGGREGATE: Number of available aggregates. Indicates the end of |
| * the enum possible values. |
| */ |
| enum bench_aggregate_idx { |
| BENCH_AGGREGATE_MIN = 0, |
| BENCH_AGGREGATE_MAX = 1, |
| BENCH_AGGREGATE_AVG = 2, |
| BENCH_AGGREGATE_COLD = 3, |
| BENCH_NUM_AGGREGATE = 4 |
| }; |
| |
| /** |
| * struct bench_metric_node - holds current aggregate for the metrics of the |
| * current bench. |
| * @cnt: Number of BENCH runs already aggregated. |
| * @tot: Total of all values returned by BENCH_RESULT. |
| * @cold: Value of the metric for the initial cold run. |
| * @aggregates: Array of computed aggregates. |
| * BENCH_AGGREGATE_MIN: Smallest value returned by |
| * BENCH_RESULT. BENCH_AGGREGATE_MAX: Highest value returned by BENCH_RESULT. |
| * BENCH_AGGREGATE_AVG: Average value returned by |
| * BENCH_RESULT. |
| */ |
| struct bench_metric_node { |
| size_t cnt; |
| int64_t tot; |
| int64_t cold; |
| int64_t aggregates[BENCH_NUM_AGGREGATE]; |
| }; |
| |
| /** |
| * struct bench_metric_list_node - holds a metric declared by BENCH_RESULT in |
| * a lk_list node |
| * @node: List node. |
| * @metric: Metric values container. |
| * @name: Name to use in summary table header for this metric. |
| * @param_idx: index of current param in param array this metric node |
| * is aggregating for. |
| * @col_sz: size in bytes needed to print this column. |
| * @bench_result: Function pointer holding the BENCH_RESULT body |
| * Used to get the value to be aggregate for this metric |
| * after each BENCH body run. |
| * @formatted_value_cb: A callback of |
| * trusty_bench_get_formatted_value_callback_t type for |
| * formatting the result value to a string |
| * @param_name_cb: A callback of trusty_bench_get_param_name_callback_t |
| * type for formatting the param name |
| */ |
| struct bench_metric_list_node { |
| struct list_node node; |
| struct bench_metric_node metric; |
| const char* name; |
| size_t param_idx; |
| size_t nb_params; |
| size_t col_sz; |
| int64_t (*bench_result)(void); |
| trusty_bench_get_formatted_value_callback_t formatted_value_cb; |
| trusty_bench_get_param_name_callback_t param_name_cb; |
| trusty_bench_check_results_callback_t check_results_cb; |
| }; |
| |
| /* |
| * Some Helper Functions for human readable output. |
| */ |
| |
| /* Some hardcoded sizes */ |
| #define BENCH_MAX_COL_SIZE 64 |
| #define BENCH_LEFTMOST_COL_SIZE 16 |
| #define BENCH_TITLE_WIDTH 72 |
| |
| /* Total Width of the resulting horizontal Table */ |
| static size_t trusty_bench_table_total_width; |
| |
| /** |
| * trusty_bench_validate_numeric - Utility function to parse Google F1 SQL valid |
| * values except NaN and +/-inf |
| * |
| * @s: string to parse |
| * |
| * Return: true if s is a valid double |
| */ |
| static inline bool trusty_bench_validate_numeric(const char* s) { |
| bool found_dot = false; |
| /* ignore initital spaces */ |
| while (*s != '\0' && (*s == ' ' || *s == '\t')) { |
| ++s; |
| } |
| |
| /* can optionally start with sign */ |
| if (*s == '+' || *s == '-') { |
| ++s; |
| } |
| |
| /* Then digits and one optional dot */ |
| while (*s != '\0' && *s != ' ' && *s != '\t') { |
| switch (*s) { |
| case '.': |
| if (found_dot) { |
| return false; |
| } |
| found_dot = true; |
| break; |
| case 'E': |
| case 'e': |
| found_dot = true; // dot are not allowed anymore |
| |
| // Start Exponent. Ignore Sign. |
| ++s; |
| if (*s == '+' || *s == '-') { |
| ++s; |
| } |
| // Make sure there is an exponent after the E+/-. |
| // Let the loop do the increment |
| if (!isdigit(*s)) { |
| return false; |
| } |
| break; |
| default: |
| // Note: Leading 0 are accepted by SQL SAFE_CAST parsing functions |
| if (!isdigit(*s)) { |
| return false; |
| } |
| break; |
| } |
| ++s; |
| } |
| |
| /* ignore trailing spaces */ |
| while (*s != '\0' && (*s == ' ' || *s == '\t')) { |
| ++s; |
| } |
| if (*s == '\0') { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * trusty_bench_sprint_col_stat - print the value of one statistical |
| * aggregate in a formatted column |
| * @buffer: Buffer in which to write the results. Preallocated. |
| * @buffer_len: Size of the Buffer in bytes. |
| * @val: Value to print |
| * @metric_name: Name of the metric for which this value is to be |
| * formatted |
| */ |
| static inline void trusty_bench_sprint_col_stat( |
| char* buffer, |
| size_t buffer_len, |
| int64_t val, |
| const char* metric_name, |
| trusty_bench_get_formatted_value_callback_t value_format_cb) { |
| if (value_format_cb == NULL) { |
| value_format_cb = trusty_bench_get_formatted_value_cb; |
| } |
| |
| if (value_format_cb == NULL) { |
| snprintf(buffer, buffer_len, "%" PRId64, val); |
| } else { |
| value_format_cb(buffer, buffer_len, val, metric_name); |
| EXPECT_EQ(trusty_bench_validate_numeric(buffer), true, |
| "%s is not a valid double representation.\n", buffer); |
| } |
| } |
| |
| /* Number of CPU on which to bench */ |
| static uint8_t trusty_bench_nb_cpu = 1; |
| static size_t trusty_cur_bench_nb_params = 1; |
| static size_t trusty_bench_multi_cpu_param_idx(size_t param_idx) { |
| return param_idx % trusty_cur_bench_nb_params; |
| } |
| static size_t trusty_bench_cpu_idx(size_t param_idx) { |
| return param_idx / trusty_cur_bench_nb_params; |
| } |