xref: /aosp_15_r20/trusty/kernel/include/shared/lk/trusty_bench_print_tables.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 <lib/unittest/unittest.h>
26 #include <trusty_log.h>
27 
28 /* Max Width ever needed for a cell in the table in horizontal printing*/
29 static size_t trusty_bench_max_column_width;
30 
31 /* Max Width ever needed for a metric cell in the table */
32 static size_t trusty_bench_max_metric_name_width =
33         6 /* strlen("Metric") is the minimum needed*/;
34 
35 /* Max Width ever needed for a Param cell in the table */
36 static size_t trusty_bench_max_param_name_width =
37         5 /* strlen("Param") is the minimum needed*/;
38 
39 /* Max Width ever needed for a Metric Value cell in the table */
40 static size_t trusty_bench_max_metric_digit_width;
41 
reset_vertical_print_widths(void)42 static inline void reset_vertical_print_widths(void) {
43     /* strlen("Metric") is the minimum needed*/
44     trusty_bench_max_metric_name_width = 6;
45     /* strlen("Param") is the minimum needed*/
46     trusty_bench_max_param_name_width = 5;
47     /* Max of strlen of Min/Max/Avg/Cold is the minimum needed*/
48     trusty_bench_max_metric_digit_width = 4;
49 }
50 
51 /**
52  * trusty_bench_print_border - Prints a Dash Sequence of prescribed size sz.
53  * @sz:     Number of Dashes to be printed.
54  */
trusty_bench_print_border(size_t sz)55 static inline void trusty_bench_print_border(size_t sz) {
56     for (size_t i = 0; i < sz; ++i) {
57         trusty_unittest_printf("-");
58     }
59     trusty_unittest_printf("\n");
60 }
61 
62 /**
63  * trusty_bench_center_print - Prints sz char in total, centering val inside it.
64  * If unbalanced, left is one space character smaller
65  * @sz:     Size of the column.
66  * @val:    String to print.
67  */
trusty_bench_center_print(size_t sz,const char * val)68 static inline void trusty_bench_center_print(size_t sz, const char* val) {
69     int spaces = (int)(sz - strlen(val));
70     int left = spaces / 2;
71     int right = spaces - left;
72 
73     for (int i = 0; i < left; ++i) {
74         trusty_unittest_printf(" ");
75     }
76     trusty_unittest_printf("%s", val);
77     for (int i = 0; i < right; ++i) {
78         trusty_unittest_printf(" ");
79     }
80 }
81 
82 /**
83  * trusty_bench_left_print - Prints sz char in total, val on the left of it.
84  * @sz:     Size of the column.
85  * @val:    String to print.
86  */
trusty_bench_left_print(size_t sz,const char * val)87 static inline void trusty_bench_left_print(size_t sz, const char* val) {
88     trusty_unittest_printf("%s%*s", val, (int)(sz - strlen(val)), "");
89 }
90 
91 /**
92  * trusty_bench_print_title - Prints Benchmark Title in dashed box.
93  * @suite:      Suite Name
94  * @bench:      Bench Name
95  * @param:      Param Name
96  */
trusty_bench_print_title(const char * suite,const char * bench,const char * param)97 static inline void trusty_bench_print_title(const char* suite,
98                                             const char* bench,
99                                             const char* param) {
100     char buffer[64];
101 
102     int nb_chars =
103             snprintf(buffer, sizeof(buffer), "RUNNING %s_%s", suite, bench);
104     if (*param != '\0' && nb_chars < (int)sizeof(buffer)) {
105         snprintf(buffer + nb_chars, sizeof(buffer) - nb_chars, "_%s", param);
106     }
107     trusty_bench_print_border(BENCH_TITLE_WIDTH);
108     trusty_bench_center_print(BENCH_TITLE_WIDTH - 1, buffer);
109     trusty_unittest_printf("|\n");
110     trusty_bench_print_border(BENCH_TITLE_WIDTH);
111 }
112 
113 /**
114  * trusty_bench_print_col_header - Prints column header with fixed size padding.
115  * @sz:         Column Width
116  * @name:       Title of the column
117  * @center:     Center text in cell?
118  */
trusty_bench_print_col_header(size_t sz,const char * name,bool center)119 static inline void trusty_bench_print_col_header(size_t sz,
120                                                  const char* name,
121                                                  bool center) {
122     if (center) {
123         trusty_bench_center_print(sz, name);
124     } else {
125         trusty_bench_left_print(sz, name);
126     }
127     trusty_unittest_printf("|");
128 }
129 
130 /**
131  * trusty_bench_print_header - Prints all column headers for a metric summary
132  * table.
133  * @metric_list:    List of metrics aggregated during all BENCH runs
134  */
trusty_bench_print_header(struct list_node * metric_list)135 static inline void trusty_bench_print_header(struct list_node* metric_list) {
136     struct bench_metric_list_node* entry;
137 
138     trusty_unittest_printf("|");
139     trusty_bench_print_col_header(BENCH_LEFTMOST_COL_SIZE, " Metrics ", true);
140     const char* prev_metric = NULL;
141     size_t sz = 0;
142 
143     list_for_every_entry(metric_list, entry, struct bench_metric_list_node,
144                          node) {
145         if (prev_metric == NULL) {
146             prev_metric = entry->name;
147         }
148 
149         if (strcmp(prev_metric, entry->name) != 0) {
150             trusty_bench_print_col_header(sz - 1, prev_metric, true);
151 
152             sz = 0;
153             prev_metric = entry->name;
154         }
155 
156         sz += entry->col_sz + 1;
157     }
158 
159     trusty_bench_print_col_header(sz - 1, prev_metric, true);
160     trusty_unittest_printf("\n");
161 }
162 
163 /**
164  * trusty_bench_compute_widths -    Compute Columns Width and Total Width before
165  *                                  printing anything.
166  * @metric_list:    List of metrics aggregated during all BENCH runs.
167  * @nb_params:      number of parameters in the parameter array.
168  */
trusty_bench_compute_widths(struct list_node * metric_list,size_t nb_params)169 static inline void trusty_bench_compute_widths(struct list_node* metric_list,
170                                                size_t nb_params) {
171     struct bench_metric_list_node* entry;
172 
173     trusty_bench_table_total_width = 0;
174     list_for_every_entry(metric_list, entry, struct bench_metric_list_node,
175                          node) {
176         char buf[BENCH_MAX_COL_SIZE];
177 
178         /* Get the size of the header */
179         /* First must be bigger than the size of the param header if any */
180         size_t column_width = 0;
181 
182         if (nb_params > 1 || trusty_bench_nb_cpu > 1) {
183             if (entry->param_name_cb) {
184                 entry->param_name_cb(buf, sizeof(buf),
185                                      entry->param_idx % entry->nb_params);
186             } else if (trusty_bench_get_param_name_cb) {
187                 trusty_bench_get_param_name_cb(
188                         buf, sizeof(buf), entry->param_idx % entry->nb_params);
189             } else {
190                 snprintf(buf, sizeof(buf), "%zu",
191                          entry->param_idx % entry->nb_params);
192             }
193             size_t param_name_width = strnlen(buf, sizeof(buf));
194 
195             trusty_bench_max_param_name_width =
196                     MAX(trusty_bench_max_param_name_width, param_name_width);
197             trusty_bench_max_column_width =
198                     MAX(trusty_bench_max_column_width, param_name_width);
199             column_width = MAX(column_width, param_name_width);
200         }
201 
202         /* Then must be bigger than the size of the metric header */
203         snprintf(buf, sizeof(buf), "%s", entry->name);
204         size_t metric_name_width = strnlen(buf, sizeof(buf));
205 
206         trusty_bench_max_column_width =
207                 MAX(trusty_bench_max_column_width, metric_name_width);
208         trusty_bench_max_metric_name_width =
209                 MAX(trusty_bench_max_metric_name_width, metric_name_width);
210         column_width = MAX(column_width, metric_name_width);
211 
212         /* Get the size of the max value */
213         trusty_bench_sprint_col_stat(
214                 buf, sizeof(buf), entry->metric.aggregates[BENCH_AGGREGATE_MAX],
215                 entry->name, entry->formatted_value_cb);
216         trusty_bench_max_column_width =
217                 MAX(strnlen(buf, sizeof(buf)), trusty_bench_max_column_width);
218         trusty_bench_max_metric_digit_width = MAX(
219                 trusty_bench_max_metric_digit_width, strnlen(buf, sizeof(buf)));
220 
221         /* Get the size of the min value, because aggregates are signed */
222         trusty_bench_sprint_col_stat(
223                 buf, sizeof(buf), entry->metric.aggregates[BENCH_AGGREGATE_MIN],
224                 entry->name, entry->formatted_value_cb);
225         trusty_bench_max_column_width =
226                 MAX(strnlen(buf, sizeof(buf)), trusty_bench_max_column_width);
227         trusty_bench_max_metric_digit_width = MAX(
228                 trusty_bench_max_metric_digit_width, strnlen(buf, sizeof(buf)));
229         column_width = MAX(column_width, trusty_bench_max_metric_digit_width);
230 
231         /* Check Column is not too big */
232         if (trusty_bench_max_column_width > BENCH_MAX_COL_SIZE) {
233             TLOGE("Column size cannot exceed BENCH_MAX_COL_SIZE: %d",
234                   BENCH_MAX_COL_SIZE);
235             return;
236         }
237 
238         /* Set the size of the column */
239         entry->col_sz = column_width;
240         trusty_bench_table_total_width += column_width + 1;
241     }
242     trusty_bench_table_total_width += BENCH_LEFTMOST_COL_SIZE + 2;
243 }
244 
245 /**
246  * trusty_bench_print_params -   Print all parameter column headers
247  * @metric_list:    List of metrics aggregated during all BENCH runs
248  */
trusty_bench_print_params(struct list_node * metric_list)249 static inline void trusty_bench_print_params(struct list_node* metric_list) {
250     struct bench_metric_list_node* entry;
251 
252     trusty_unittest_printf("|");
253     trusty_bench_print_col_header(BENCH_LEFTMOST_COL_SIZE, " Params ", true);
254     list_for_every_entry(metric_list, entry, struct bench_metric_list_node,
255                          node) {
256         char buf[BENCH_MAX_COL_SIZE];
257 
258         if (entry->param_name_cb) {
259             entry->param_name_cb(buf, sizeof(buf),
260                                  entry->param_idx % entry->nb_params);
261         } else if (trusty_bench_get_param_name_cb) {
262             trusty_bench_get_param_name_cb(buf, sizeof(buf),
263                                            entry->param_idx % entry->nb_params);
264         } else {
265             snprintf(buf, sizeof(buf), "%zu",
266                      entry->param_idx % entry->nb_params);
267         }
268         trusty_bench_print_col_header(entry->col_sz, buf, true);
269     }
270     trusty_unittest_printf("\n");
271 }
272 
273 /**
274  * trusty_bench_print_col_stat -     print the value of one statistical
275  * aggregate in a formatted column
276  * @sz:                 Columns Width
277  * @val:                Value to print
278  * @metric_name:        Metric for which the aggregate stat is to be printed.
279  */
trusty_bench_print_col_stat(size_t sz,int64_t val,const char * metric_name,trusty_bench_get_formatted_value_callback_t value_format_cb)280 static inline void trusty_bench_print_col_stat(
281         size_t sz,
282         int64_t val,
283         const char* metric_name,
284         trusty_bench_get_formatted_value_callback_t value_format_cb) {
285     if (value_format_cb == NULL) {
286         value_format_cb = trusty_bench_get_formatted_value_cb;
287     }
288     if (value_format_cb == NULL) {
289         trusty_unittest_printf("%*" PRId64 "|", (int)sz, val);
290     } else {
291         char buffer[32];
292 
293         value_format_cb(buffer, sizeof(buffer), val, metric_name);
294         if (trusty_bench_validate_numeric(buffer)) {
295             trusty_unittest_printf("%*s|", (int)sz, buffer);
296         } else {
297             trusty_unittest_printf("%*s|", (int)sz, "");
298         }
299     }
300 }
301 
302 /**
303  * trusty_bench_print_stat -     print one list with the value of one
304  * statistical aggregate across all params/metric
305  * @metric_list:    List of metrics aggregated during all BENCH runs
306  * @idx:            Position of the aggregate in the aggregate array
307  * @aggregate_name: Name of the aggregate for the row header on the left
308  */
trusty_bench_print_stat(struct list_node * metric_list,enum bench_aggregate_idx idx,const char * aggregate_name)309 static inline void trusty_bench_print_stat(struct list_node* metric_list,
310                                            enum bench_aggregate_idx idx,
311                                            const char* aggregate_name) {
312     struct bench_metric_list_node* entry;
313 
314     trusty_unittest_printf("|");
315     trusty_bench_print_col_header(BENCH_LEFTMOST_COL_SIZE, aggregate_name,
316                                   true);
317     list_for_every_entry(metric_list, entry, struct bench_metric_list_node,
318                          node) {
319         if (entry->metric.cnt == 0) {
320             trusty_bench_center_print(trusty_bench_max_metric_digit_width, "-");
321             trusty_unittest_printf("|");
322         } else if (idx == BENCH_AGGREGATE_COLD) {
323             trusty_bench_print_col_stat(entry->col_sz, entry->metric.cold,
324                                         entry->name, entry->formatted_value_cb);
325         } else {
326             trusty_bench_print_col_stat(entry->col_sz,
327                                         entry->metric.aggregates[idx],
328                                         entry->name, entry->formatted_value_cb);
329         }
330     }
331     trusty_unittest_printf("\n");
332 }
333 
334 /**
335  * trusty_bench_print_horizontal_metric_list -  Prints a summary table of all
336  * statistical aggregates for all param/metric in the last BENCH
337  * @metric_list:        List of metrics aggregated during all BENCH runs.
338  * @nb_params:          Number of Parameters in the param array of BENCH.
339  * @suite_name:         Name of the Bench Suite
340  * @bench_name:         Name of the Bench
341  */
trusty_bench_print_horizontal_metric_list(struct list_node * metric_list,size_t nb_params,const char * suite_name,const char * bench_name)342 static inline void trusty_bench_print_horizontal_metric_list(
343         struct list_node* metric_list,
344         size_t nb_params,
345         const char* suite_name,
346         const char* bench_name) {
347     trusty_bench_compute_widths(metric_list, nb_params);
348     trusty_bench_print_border(trusty_bench_table_total_width);
349     trusty_bench_print_header(metric_list);
350     trusty_bench_print_border(trusty_bench_table_total_width);
351     if (nb_params > 1 || trusty_bench_nb_cpu > 1) {
352         trusty_bench_print_params(metric_list);
353         trusty_bench_print_border(trusty_bench_table_total_width);
354     }
355 
356     trusty_bench_print_stat(metric_list, BENCH_AGGREGATE_MIN, "min");
357     trusty_bench_print_stat(metric_list, BENCH_AGGREGATE_AVG, "avg");
358     trusty_bench_print_stat(metric_list, BENCH_AGGREGATE_MAX, "max");
359     trusty_bench_print_stat(metric_list, BENCH_AGGREGATE_COLD, "cold");
360 
361     trusty_bench_print_border(trusty_bench_table_total_width);
362 }
363 
364 /**
365  * trusty_bench_print_vertical_metric_list -  Prints a summary table of all
366  * statistical aggregates for all param/metric in the last BENCH
367  * @metric_list:        List of metrics aggregated during all BENCH runs.
368  * @nb_params:          Number of Parameters in the param array of BENCH.
369  * @suite_name:         Name of the Bench Suite
370  * @bench_name:         Name of the Bench
371  */
trusty_bench_print_vertical_metric_list(struct list_node * metric_list,size_t nb_params,const char * suite_name,const char * bench_name)372 static inline void trusty_bench_print_vertical_metric_list(
373         struct list_node* metric_list,
374         size_t nb_params,
375         const char* suite_name,
376         const char* bench_name) {
377     struct bench_metric_list_node* entry;
378 
379     trusty_bench_compute_widths(metric_list, nb_params);
380     size_t width = trusty_bench_max_metric_name_width +
381                    4 * trusty_bench_max_metric_digit_width + 6;
382 
383     /* Need one column for params? */
384     if (nb_params > 1 || trusty_bench_nb_cpu > 1) {
385         width += trusty_bench_max_param_name_width + 1;
386     }
387     trusty_bench_print_border(width);
388     trusty_unittest_printf("|");
389     trusty_bench_print_col_header(trusty_bench_max_metric_name_width, "Metric",
390                                   false);
391     if (nb_params > 1 || trusty_bench_nb_cpu > 1) {
392         trusty_bench_print_col_header(trusty_bench_max_param_name_width,
393                                       "Param", false);
394     }
395     trusty_bench_print_col_header(trusty_bench_max_metric_digit_width, "Min",
396                                   false);
397     trusty_bench_print_col_header(trusty_bench_max_metric_digit_width, "Avg",
398                                   false);
399     trusty_bench_print_col_header(trusty_bench_max_metric_digit_width, "Max",
400                                   false);
401     trusty_bench_print_col_header(trusty_bench_max_metric_digit_width, "Cold",
402                                   false);
403     trusty_unittest_printf("\n");
404 
405     const char* prev_metric = "";
406 
407     list_for_every_entry(metric_list, entry, struct bench_metric_list_node,
408                          node) {
409         if (strcmp(prev_metric, entry->name) != 0) {
410             prev_metric = entry->name;
411             trusty_bench_print_border(width);
412         }
413         trusty_unittest_printf("|");
414         trusty_bench_print_col_header(trusty_bench_max_metric_name_width,
415                                       entry->name, false);
416         if (nb_params > 1 || trusty_bench_nb_cpu > 1) {
417             char buf[BENCH_MAX_COL_SIZE];
418 
419             if (entry->param_name_cb) {
420                 entry->param_name_cb(buf, sizeof(buf),
421                                      entry->param_idx % entry->nb_params);
422             } else if (trusty_bench_get_param_name_cb) {
423                 trusty_bench_get_param_name_cb(
424                         buf, sizeof(buf), entry->param_idx % entry->nb_params);
425             } else {
426                 snprintf(buf, sizeof(buf), "%zu",
427                          entry->param_idx % entry->nb_params);
428             }
429             trusty_bench_print_col_header(trusty_bench_max_param_name_width,
430                                           buf, false);
431         }
432 
433         if (entry->metric.cnt) {
434             trusty_bench_print_col_stat(
435                     trusty_bench_max_metric_digit_width,
436                     entry->metric.aggregates[BENCH_AGGREGATE_MIN], entry->name,
437                     entry->formatted_value_cb);
438             trusty_bench_print_col_stat(
439                     trusty_bench_max_metric_digit_width,
440                     entry->metric.aggregates[BENCH_AGGREGATE_AVG], entry->name,
441                     entry->formatted_value_cb);
442             trusty_bench_print_col_stat(
443                     trusty_bench_max_metric_digit_width,
444                     entry->metric.aggregates[BENCH_AGGREGATE_MAX], entry->name,
445                     entry->formatted_value_cb);
446             trusty_bench_print_col_stat(trusty_bench_max_metric_digit_width,
447                                         entry->metric.cold, entry->name,
448                                         entry->formatted_value_cb);
449         } else {
450             for (int i = 0; i < 4; i++) {
451                 trusty_bench_center_print(trusty_bench_max_metric_digit_width,
452                                           "-");
453                 trusty_unittest_printf("|");
454             }
455         }
456         trusty_unittest_printf("\n");
457     }
458     trusty_bench_print_border(width);
459 }
460