blob: 0b55c5dc7a219271ac5519479c723926ddaa2e4b [file]
/*
* 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;
}