xref: /aosp_15_r20/trusty/kernel/include/shared/lk/trusty_bench_common.h (revision 344aa361028b423587d4ef3fa52a23d194628137)
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 #pragma once
25 #include <ctype.h>
26 #include <stdio.h>
27 
28 #include <lib/unittest/unittest.h>
29 
30 #include "trusty_bench_option_cb.h"
31 
32 /**
33  * enum bench_aggregate_idx - The position of the calculated aggregate in the
34  * aggregate array of the bench_metric_node
35  * @BENCH_AGGREGATE_MIN: index of the current minimum value for this metric.
36  * @BENCH_AGGREGATE_MAX: index of the current maximum value for this metric.
37  * @BENCH_AGGREGATE_AVG: index of the current average value for this metric.
38  * @BENCH_AGGREGATE_COLD:index of the cold run value for this metric.
39  * @BENCH_NUM_AGGREGATE: Number of available aggregates. Indicates the end of
40  * the enum possible values.
41  */
42 enum bench_aggregate_idx {
43     BENCH_AGGREGATE_MIN = 0,
44     BENCH_AGGREGATE_MAX = 1,
45     BENCH_AGGREGATE_AVG = 2,
46     BENCH_AGGREGATE_COLD = 3,
47     BENCH_NUM_AGGREGATE = 4
48 };
49 
50 /**
51  * struct bench_metric_node - holds current aggregate for the metrics of the
52  * current bench.
53  * @cnt:                Number of BENCH runs already aggregated.
54  * @tot:                Total of all values returned by BENCH_RESULT.
55  * @cold:               Value of the metric for the initial cold run.
56  * @aggregates:         Array of computed aggregates.
57  *                      BENCH_AGGREGATE_MIN: Smallest value returned by
58  * BENCH_RESULT. BENCH_AGGREGATE_MAX: Highest value returned by BENCH_RESULT.
59  *                      BENCH_AGGREGATE_AVG: Average value returned by
60  * BENCH_RESULT.
61  */
62 struct bench_metric_node {
63     size_t cnt;
64     int64_t tot;
65     int64_t cold;
66     int64_t aggregates[BENCH_NUM_AGGREGATE];
67 };
68 
69 /**
70  * struct bench_metric_list_node - holds a metric declared by BENCH_RESULT in
71  * a lk_list node
72  * @node:               List node.
73  * @metric:             Metric values container.
74  * @name:               Name to use in summary table header for this metric.
75  * @param_idx:          index of current param in param array this metric node
76  *                      is aggregating for.
77  * @col_sz:             size in bytes needed to print this column.
78  * @bench_result:       Function pointer holding the BENCH_RESULT body
79  *                      Used to get the value to be aggregate for this metric
80  *                      after each BENCH body run.
81  * @formatted_value_cb: A callback of
82  *                      trusty_bench_get_formatted_value_callback_t type for
83  *                      formatting the result value to a string
84  * @param_name_cb:      A callback of trusty_bench_get_param_name_callback_t
85  *                      type for formatting the param name
86  */
87 struct bench_metric_list_node {
88     struct list_node node;
89     struct bench_metric_node metric;
90     const char* name;
91     size_t param_idx;
92     size_t nb_params;
93     size_t col_sz;
94     int64_t (*bench_result)(void);
95     trusty_bench_get_formatted_value_callback_t formatted_value_cb;
96     trusty_bench_get_param_name_callback_t param_name_cb;
97     trusty_bench_check_results_callback_t check_results_cb;
98 };
99 
100 /*
101  * Some Helper Functions for human readable output.
102  */
103 
104 /* Some hardcoded sizes */
105 #define BENCH_MAX_COL_SIZE 64
106 #define BENCH_LEFTMOST_COL_SIZE 16
107 #define BENCH_TITLE_WIDTH 72
108 
109 /* Total Width of the resulting horizontal Table */
110 static size_t trusty_bench_table_total_width;
111 
112 /**
113  * trusty_bench_validate_numeric - Utility function to parse Google F1 SQL valid
114  * values except NaN and +/-inf
115  *
116  * @s: string to parse
117  *
118  * Return: true if s is a valid double
119  */
trusty_bench_validate_numeric(const char * s)120 static inline bool trusty_bench_validate_numeric(const char* s) {
121     bool found_dot = false;
122     /* ignore initital spaces */
123     while (*s != '\0' && (*s == ' ' || *s == '\t')) {
124         ++s;
125     }
126 
127     /* can optionally start with sign */
128     if (*s == '+' || *s == '-') {
129         ++s;
130     }
131 
132     /* Then digits and one optional dot */
133     while (*s != '\0' && *s != ' ' && *s != '\t') {
134         switch (*s) {
135         case '.':
136             if (found_dot) {
137                 return false;
138             }
139             found_dot = true;
140             break;
141         case 'E':
142         case 'e':
143             found_dot = true;  // dot are not allowed anymore
144 
145             // Start Exponent. Ignore Sign.
146             ++s;
147             if (*s == '+' || *s == '-') {
148                 ++s;
149             }
150             // Make sure there is an exponent after the E+/-.
151             // Let the loop do the increment
152             if (!isdigit(*s)) {
153                 return false;
154             }
155             break;
156         default:
157             // Note: Leading 0 are accepted by SQL SAFE_CAST parsing functions
158             if (!isdigit(*s)) {
159                 return false;
160             }
161             break;
162         }
163         ++s;
164     }
165 
166     /* ignore trailing spaces */
167     while (*s != '\0' && (*s == ' ' || *s == '\t')) {
168         ++s;
169     }
170     if (*s == '\0') {
171         return true;
172     }
173 
174     return false;
175 }
176 
177 /**
178  * trusty_bench_sprint_col_stat -     print the value of one statistical
179  * aggregate in a formatted column
180  * @buffer:             Buffer in which to write the results. Preallocated.
181  * @buffer_len:         Size of the Buffer in bytes.
182  * @val:                Value to print
183  * @metric_name:        Name of the metric for which this value is to be
184  *                      formatted
185  */
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)186 static inline void trusty_bench_sprint_col_stat(
187         char* buffer,
188         size_t buffer_len,
189         int64_t val,
190         const char* metric_name,
191         trusty_bench_get_formatted_value_callback_t value_format_cb) {
192     if (value_format_cb == NULL) {
193         value_format_cb = trusty_bench_get_formatted_value_cb;
194     }
195 
196     if (value_format_cb == NULL) {
197         snprintf(buffer, buffer_len, "%" PRId64, val);
198     } else {
199         value_format_cb(buffer, buffer_len, val, metric_name);
200         EXPECT_EQ(trusty_bench_validate_numeric(buffer), true,
201                   "%s is not a valid double representation.\n", buffer);
202     }
203 }
204 
205 /* Number of CPU on which to bench */
206 static uint8_t trusty_bench_nb_cpu = 1;
207 static size_t trusty_cur_bench_nb_params = 1;
trusty_bench_multi_cpu_param_idx(size_t param_idx)208 static size_t trusty_bench_multi_cpu_param_idx(size_t param_idx) {
209     return param_idx % trusty_cur_bench_nb_params;
210 }
trusty_bench_cpu_idx(size_t param_idx)211 static size_t trusty_bench_cpu_idx(size_t param_idx) {
212     return param_idx / trusty_cur_bench_nb_params;
213 }
214