benchmarks: let size of table columns adapts to contents
This commit is contained in:
parent
7a63ad86aa
commit
5d514218ac
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
#include "benchmark_tools.h"
|
#include "benchmark_tools.h"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@ -26,7 +27,9 @@
|
|||||||
# define BENCHMARK_TIMER_LIBC
|
# define BENCHMARK_TIMER_LIBC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct benchmark_timer
|
/* Benchmark timers */
|
||||||
|
|
||||||
|
struct benchmark_timer
|
||||||
{
|
{
|
||||||
#ifdef BENCHMARK_TIMER_WINDOWS
|
#ifdef BENCHMARK_TIMER_WINDOWS
|
||||||
LARGE_INTEGER start_time;
|
LARGE_INTEGER start_time;
|
||||||
@ -34,7 +37,8 @@ typedef struct benchmark_timer
|
|||||||
#elif defined(BENCHMARK_TIMER_LIBC)
|
#elif defined(BENCHMARK_TIMER_LIBC)
|
||||||
clock_t start_tick;
|
clock_t start_tick;
|
||||||
#endif
|
#endif
|
||||||
} benchmark_timer_t;
|
};
|
||||||
|
typedef struct benchmark_timer benchmark_timer_t;
|
||||||
|
|
||||||
static void benchmark_timer_start(benchmark_timer_t* timer)
|
static void benchmark_timer_start(benchmark_timer_t* timer)
|
||||||
{
|
{
|
||||||
@ -72,6 +76,151 @@ static int64_t benchmark_timer_elapsed_ms(const benchmark_timer_t* timer)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Wraps around formatted printing functions */
|
||||||
|
|
||||||
|
/*! Wrapp around sprintf() to be used with gprintf_func_exec_time() */
|
||||||
|
static void sprintf_wrap(void* cookie, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsprintf((char*)cookie, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Wrap around printf() to be used with gprintf_func_exec_time() */
|
||||||
|
static void printf_wrap(void* cookie, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
GMIO_UNUSED(cookie);
|
||||||
|
va_start(args, fmt);
|
||||||
|
vprintf(fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Typedef on pointer to printf-wrap functions(eg. sprintf_wrap()) */
|
||||||
|
typedef void (*func_gprintf_t)(void*, const char*, ...);
|
||||||
|
|
||||||
|
|
||||||
|
/* Utilities */
|
||||||
|
|
||||||
|
/*! Calls printf(str) \p n times */
|
||||||
|
static void print_string_n(const char* str, size_t n)
|
||||||
|
{
|
||||||
|
size_t i; /* for-loop index*/
|
||||||
|
for (i = 0; i < n; ++i)
|
||||||
|
printf(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Safe wrapper around strlen() for NULL strings */
|
||||||
|
GMIO_INLINE size_t safe_strlen(const char* str)
|
||||||
|
{
|
||||||
|
return str != NULL ? strlen(str) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Returns the maximum of two size_t values */
|
||||||
|
GMIO_INLINE size_t size_t_max(size_t lhs, size_t rhs)
|
||||||
|
{
|
||||||
|
return lhs > rhs ? lhs : rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! String representation of the unit used for execution time */
|
||||||
|
static const char* unit_time_str = "ms";
|
||||||
|
|
||||||
|
/*! Generic formatted print of some execution time */
|
||||||
|
static void gprintf_func_exec_time(
|
||||||
|
/* Annex data for func_gprintf (ex: char* for sprintf()) */
|
||||||
|
void* cookie,
|
||||||
|
/* Function ptr on a printf wrap (ex: sprintf_wrap()) */
|
||||||
|
func_gprintf_t func_gprintf,
|
||||||
|
/* Width of the print column, if any (can be == 0) */
|
||||||
|
size_t width_column,
|
||||||
|
/* Execution time, in ms */
|
||||||
|
size_t time_ms,
|
||||||
|
/* Valid execution time ? */
|
||||||
|
gmio_bool_t has_time)
|
||||||
|
{
|
||||||
|
if (has_time) {
|
||||||
|
char str_time[128] = {0};
|
||||||
|
/* TODO: %ull is not accepted by mingw, find a fix(maybe %ul64) */
|
||||||
|
sprintf(str_time, "%u%s", (unsigned)time_ms, unit_time_str);
|
||||||
|
if (width_column > 0)
|
||||||
|
func_gprintf(cookie, "%-*s", width_column, str_time);
|
||||||
|
else
|
||||||
|
func_gprintf(cookie, "%s", str_time);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const char n_a[] = "N/A";
|
||||||
|
if (width_column > 0)
|
||||||
|
func_gprintf(cookie, "%-*s", width_column, n_a);
|
||||||
|
else
|
||||||
|
func_gprintf(cookie, "%s", n_a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Helper for printf() around gprintf_func_exec_time() */
|
||||||
|
static void printf_func_exec_time(
|
||||||
|
size_t width_column,
|
||||||
|
size_t time_ms,
|
||||||
|
gmio_bool_t has_time)
|
||||||
|
{
|
||||||
|
gprintf_func_exec_time(
|
||||||
|
NULL, &printf_wrap, width_column, time_ms, has_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Returns the strlen of the longest tag string */
|
||||||
|
static size_t find_maxlen_cmp_result_tag(benchmark_cmp_result_array_t res_array)
|
||||||
|
{
|
||||||
|
size_t max_len = 0;
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < res_array.count; ++i) {
|
||||||
|
const size_t len = safe_strlen(res_array.ptr[i].tag);
|
||||||
|
max_len = size_t_max(len, max_len);
|
||||||
|
}
|
||||||
|
return max_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Writes in output args the func1 execution informations */
|
||||||
|
static void select_cmp_result_func1_exec_infos(
|
||||||
|
const benchmark_cmp_result_t* cmp, size_t* time, gmio_bool_t* has_time)
|
||||||
|
{
|
||||||
|
*time = cmp->func1_exec_time_ms;
|
||||||
|
*has_time = cmp->has_func1_exec_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Writes in output args the func2 execution informations */
|
||||||
|
static void select_cmp_result_func2_exec_infos(
|
||||||
|
const benchmark_cmp_result_t* cmp, size_t* time, gmio_bool_t* has_time)
|
||||||
|
{
|
||||||
|
*time = cmp->func2_exec_time_ms;
|
||||||
|
*has_time = cmp->has_func2_exec_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Typedef on pointer to functions like select_cmp_result_funcX_exec_infos() */
|
||||||
|
typedef void (*func_select_cmp_result_func_exec_infos_t)(
|
||||||
|
const benchmark_cmp_result_t*, size_t*, gmio_bool_t*);
|
||||||
|
|
||||||
|
/*! Returns the strlen of the longest execution time string */
|
||||||
|
static size_t find_maxlen_cmp_result_func_exec_time(
|
||||||
|
benchmark_cmp_result_array_t res_array,
|
||||||
|
func_select_cmp_result_func_exec_infos_t func_select_exec_infos)
|
||||||
|
{
|
||||||
|
char strbuff[1024] = {0};
|
||||||
|
size_t max_len = 0;
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < res_array.count; ++i) {
|
||||||
|
size_t time = 0;
|
||||||
|
gmio_bool_t has_time = GMIO_FALSE;
|
||||||
|
size_t len = 0;
|
||||||
|
func_select_exec_infos(&res_array.ptr[i], &time, &has_time);
|
||||||
|
gprintf_func_exec_time(strbuff, &sprintf_wrap, 0, time, has_time);
|
||||||
|
len = safe_strlen(strbuff);
|
||||||
|
max_len = size_t_max(len, max_len);
|
||||||
|
}
|
||||||
|
return max_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implementation */
|
||||||
|
|
||||||
benchmark_cmp_result_t benchmark_cmp(benchmark_cmp_arg_t arg)
|
benchmark_cmp_result_t benchmark_cmp(benchmark_cmp_arg_t arg)
|
||||||
{
|
{
|
||||||
benchmark_cmp_result_t result = {0};
|
benchmark_cmp_result_t result = {0};
|
||||||
@ -95,61 +244,56 @@ benchmark_cmp_result_t benchmark_cmp(benchmark_cmp_arg_t arg)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void printf_string_n(const char* str, size_t n)
|
|
||||||
{
|
|
||||||
size_t i; /* for-loop index*/
|
|
||||||
for (i = 0; i < n; ++i)
|
|
||||||
printf(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const int width_tag_col = 20;
|
|
||||||
static const int width_func_col = 10;
|
|
||||||
static const char* unit_time_str = "ms";
|
|
||||||
|
|
||||||
static void printf_func_exec_time(
|
|
||||||
size_t func_exec_time_ms, gmio_bool_t has_func_exec_time)
|
|
||||||
{
|
|
||||||
if (has_func_exec_time) {
|
|
||||||
char str_exec_time[128] = {0};
|
|
||||||
/* TODO: %ull is not accepted by mingw, find a fix(maybe %ul64) */
|
|
||||||
sprintf(str_exec_time, "%u%s", func_exec_time_ms, unit_time_str);
|
|
||||||
printf("%-*s", width_func_col, str_exec_time);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("%-*s", width_func_col, "N/A");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void benchmark_print_results(
|
void benchmark_print_results(
|
||||||
benchmark_print_format_t format,
|
benchmark_print_format_t format,
|
||||||
benchmark_cmp_result_header_t header,
|
benchmark_cmp_result_header_t header,
|
||||||
benchmark_cmp_result_array_t result_array)
|
benchmark_cmp_result_array_t result_array)
|
||||||
{
|
{
|
||||||
if (format == BENCHMARK_PRINT_FORMAT_MARKDOWN) {
|
if (format == BENCHMARK_PRINT_FORMAT_MARKDOWN) {
|
||||||
|
const char* header_comp1 =
|
||||||
|
header.component_1 != NULL ? header.component_1 : "";
|
||||||
|
const char* header_comp2 =
|
||||||
|
header.component_2 != NULL ? header.component_2 : "";
|
||||||
|
const size_t width_tag_col =
|
||||||
|
find_maxlen_cmp_result_tag(result_array);
|
||||||
|
const size_t width_func1_col =
|
||||||
|
size_t_max(
|
||||||
|
find_maxlen_cmp_result_func_exec_time(
|
||||||
|
result_array, &select_cmp_result_func1_exec_infos),
|
||||||
|
safe_strlen(header_comp1));
|
||||||
|
const size_t width_func2_col =
|
||||||
|
size_t_max(
|
||||||
|
find_maxlen_cmp_result_func_exec_time(
|
||||||
|
result_array, &select_cmp_result_func2_exec_infos),
|
||||||
|
safe_strlen(header_comp2));
|
||||||
size_t i; /* for-loop index*/
|
size_t i; /* for-loop index*/
|
||||||
|
|
||||||
/* Print table header */
|
/* Print table header */
|
||||||
printf("%*s | ", width_tag_col, "");
|
printf("%*s | ", (int)width_tag_col, "");
|
||||||
printf("%-*s | ", width_func_col, header.component_1);
|
printf("%-*s | ", (int)width_func1_col, header_comp1);
|
||||||
printf("%-*s\n", width_func_col, header.component_2);
|
printf("%-*s\n", (int)width_func2_col, header_comp2);
|
||||||
|
|
||||||
/* Print separation between header and results */
|
/* Print separation between header and results */
|
||||||
printf_string_n("-", width_tag_col + 1);
|
print_string_n("-", width_tag_col + 1);
|
||||||
printf("|");
|
printf("|");
|
||||||
printf_string_n("-", width_func_col + strlen(unit_time_str));
|
print_string_n("-", width_func1_col + 2);
|
||||||
printf("|");
|
printf("|");
|
||||||
printf_string_n("-", width_func_col + strlen(unit_time_str));
|
print_string_n("-", width_func2_col + 2);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|
||||||
/* Print benchmark result lines */
|
/* Print benchmark result lines */
|
||||||
for (i = 0; i < result_array.count; ++i) {
|
for (i = 0; i < result_array.count; ++i) {
|
||||||
const benchmark_cmp_result_t result = result_array.ptr[i];
|
const benchmark_cmp_result_t result = result_array.ptr[i];
|
||||||
printf("%-*s | ", width_tag_col, result.tag);
|
printf("%-*s | ", (int)width_tag_col, result.tag);
|
||||||
printf_func_exec_time(
|
printf_func_exec_time(
|
||||||
result.func1_exec_time_ms, result.has_func1_exec_time);
|
width_func1_col,
|
||||||
|
result.func1_exec_time_ms,
|
||||||
|
result.has_func1_exec_time);
|
||||||
printf(" | ");
|
printf(" | ");
|
||||||
printf_func_exec_time(
|
printf_func_exec_time(
|
||||||
result.func2_exec_time_ms, result.has_func2_exec_time);
|
width_func2_col,
|
||||||
|
result.func2_exec_time_ms,
|
||||||
|
result.has_func2_exec_time);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,32 +21,47 @@
|
|||||||
|
|
||||||
GMIO_C_LINKAGE_BEGIN
|
GMIO_C_LINKAGE_BEGIN
|
||||||
|
|
||||||
|
/*! Typedef on pointer to function to be benchmarked(execution time) */
|
||||||
typedef void (*benchmark_file_func_t)(const char*);
|
typedef void (*benchmark_file_func_t)(const char*);
|
||||||
|
|
||||||
/* benchmark_cmp */
|
/* benchmark_cmp */
|
||||||
|
|
||||||
|
/*! Describes a comparison benchmark between two functions */
|
||||||
struct benchmark_cmp_arg
|
struct benchmark_cmp_arg
|
||||||
{
|
{
|
||||||
|
/*! Brief description of the comparison(eg. "Write to file") */
|
||||||
const char* tag;
|
const char* tag;
|
||||||
|
/*! Pointer to the 1st function */
|
||||||
benchmark_file_func_t func1;
|
benchmark_file_func_t func1;
|
||||||
|
/*! Argument passed to the 1st function on exec */
|
||||||
const char* func1_filepath;
|
const char* func1_filepath;
|
||||||
|
/*! Pointer to the 2nd function */
|
||||||
benchmark_file_func_t func2;
|
benchmark_file_func_t func2;
|
||||||
|
/*! Argument passed to the 2nd function on exec */
|
||||||
const char* func2_filepath;
|
const char* func2_filepath;
|
||||||
};
|
};
|
||||||
typedef struct benchmark_cmp_arg benchmark_cmp_arg_t;
|
typedef struct benchmark_cmp_arg benchmark_cmp_arg_t;
|
||||||
|
|
||||||
|
/*! Holds the result of the exec time comparison between two functions */
|
||||||
struct benchmark_cmp_result
|
struct benchmark_cmp_result
|
||||||
{
|
{
|
||||||
|
/*! Identifies the comparison */
|
||||||
const char* tag;
|
const char* tag;
|
||||||
|
/*! Execution time(in ms) of the 1st function */
|
||||||
size_t func1_exec_time_ms;
|
size_t func1_exec_time_ms;
|
||||||
|
/*! Is exec time of the 1st function valid ? */
|
||||||
gmio_bool_t has_func1_exec_time;
|
gmio_bool_t has_func1_exec_time;
|
||||||
|
/*! Execution time(in ms) of the 2nd function */
|
||||||
size_t func2_exec_time_ms;
|
size_t func2_exec_time_ms;
|
||||||
|
/*! Is exec time of the 2nd function valid ? */
|
||||||
gmio_bool_t has_func2_exec_time;
|
gmio_bool_t has_func2_exec_time;
|
||||||
};
|
};
|
||||||
typedef struct benchmark_cmp_result benchmark_cmp_result_t;
|
typedef struct benchmark_cmp_result benchmark_cmp_result_t;
|
||||||
|
|
||||||
|
/*! Runs func1 then func2 and measures the respective execution time */
|
||||||
benchmark_cmp_result_t benchmark_cmp(benchmark_cmp_arg_t arg);
|
benchmark_cmp_result_t benchmark_cmp(benchmark_cmp_arg_t arg);
|
||||||
|
|
||||||
|
/*! Runs a batch(array) of comparison benchmarks */
|
||||||
void benchmark_cmp_batch(
|
void benchmark_cmp_batch(
|
||||||
size_t run_count,
|
size_t run_count,
|
||||||
const benchmark_cmp_arg_t* arg_array,
|
const benchmark_cmp_arg_t* arg_array,
|
||||||
@ -63,6 +78,7 @@ enum benchmark_print_format
|
|||||||
};
|
};
|
||||||
typedef enum benchmark_print_format benchmark_print_format_t;
|
typedef enum benchmark_print_format benchmark_print_format_t;
|
||||||
|
|
||||||
|
/*! Array of benchmark_cmp_result */
|
||||||
struct benchmark_cmp_result_array
|
struct benchmark_cmp_result_array
|
||||||
{
|
{
|
||||||
const benchmark_cmp_result_t* ptr;
|
const benchmark_cmp_result_t* ptr;
|
||||||
@ -70,6 +86,7 @@ struct benchmark_cmp_result_array
|
|||||||
};
|
};
|
||||||
typedef struct benchmark_cmp_result_array benchmark_cmp_result_array_t;
|
typedef struct benchmark_cmp_result_array benchmark_cmp_result_array_t;
|
||||||
|
|
||||||
|
/*! Horizontal header labels for benchmark results(by column) */
|
||||||
struct benchmark_cmp_result_header
|
struct benchmark_cmp_result_header
|
||||||
{
|
{
|
||||||
const char* component_1;
|
const char* component_1;
|
||||||
@ -77,6 +94,7 @@ struct benchmark_cmp_result_header
|
|||||||
};
|
};
|
||||||
typedef struct benchmark_cmp_result_header benchmark_cmp_result_header_t;
|
typedef struct benchmark_cmp_result_header benchmark_cmp_result_header_t;
|
||||||
|
|
||||||
|
/*! Prints formatted benchmark results */
|
||||||
void benchmark_print_results(
|
void benchmark_print_results(
|
||||||
benchmark_print_format_t format,
|
benchmark_print_format_t format,
|
||||||
benchmark_cmp_result_header_t header,
|
benchmark_cmp_result_header_t header,
|
||||||
|
Loading…
Reference in New Issue
Block a user