mirror of
https://github.com/intel/isa-l.git
synced 2025-12-07 18:23:59 +01:00
crc: add cold cache test
To benchmark a cold cache scenario, the option `--cold` has been added as a parameter of the CRC benchmark application, where the addresses of the input buffers are randomize within a 1GB preallocated memory buffer. Signed-off-by: Pablo de Lara <pablo.de.lara.guarch@intel.com>
This commit is contained in:
committed by
Tomasz Kantecki
parent
e97c91547f
commit
8735bb4e20
@@ -90,68 +90,200 @@ static const crc_type_t CRC64_TYPES[] = { CRC64_ECMA_REFL, CRC64_ECMA_NORM,
|
||||
CRC64_ROCKSOFT_REFL, CRC64_ROCKSOFT_NORM };
|
||||
static const size_t CRC64_TYPES_LEN = 8;
|
||||
|
||||
#define COLD_CACHE_TEST_MEM (1024 * 1024 * 1024)
|
||||
#define COLD_CACHE_MIN_LEN (1024)
|
||||
|
||||
// Define function pointer types for CRC functions with standard parameter format (seed, buffer,
|
||||
// len)
|
||||
typedef uint32_t (*crc32_func_t)(uint32_t seed, const uint8_t *buf, uint64_t len);
|
||||
typedef uint16_t (*crc16_func_t)(uint16_t seed, const uint8_t *buf, uint64_t len);
|
||||
typedef uint64_t (*crc64_func_t)(uint64_t seed, const uint8_t *buf, uint64_t len);
|
||||
|
||||
// Result type enumeration
|
||||
typedef enum { RESULT_CRC32 = 0, RESULT_CRC16, RESULT_CRC64 } crc_result_type_t;
|
||||
|
||||
// Structure to define CRC function tables with standard parameter signature
|
||||
typedef struct {
|
||||
crc_type_t type; // CRC type ID
|
||||
const char *name; // Function name for output
|
||||
void *func; // Regular optimized function
|
||||
void *func_base; // Base (non-optimized) function
|
||||
crc_result_type_t result_type; // Type of result value
|
||||
} crc_func_info_t;
|
||||
|
||||
// Wrapper functions for CRC functions with non-standard parameter order
|
||||
// ISCSI CRC wrapper that adapts (buffer, len, seed) to standard (seed, buffer, len) format
|
||||
static uint32_t
|
||||
crc32_iscsi_wrapped(const uint32_t seed, const uint8_t *buf, const uint64_t len)
|
||||
{
|
||||
// Cast to match the expected function signature
|
||||
return crc32_iscsi((unsigned char *) buf, (int) len, seed);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
crc32_iscsi_base_wrapped(const uint32_t seed, const uint8_t *buf, const uint64_t len)
|
||||
{
|
||||
// Cast to match the expected function signature
|
||||
return crc32_iscsi_base((unsigned char *) buf, (int) len, seed);
|
||||
}
|
||||
|
||||
// Table of CRC functions with standard parameter format (seed, buffer, len)
|
||||
static const crc_func_info_t CRC_FUNCS_TABLE[] = {
|
||||
// CRC32 functions
|
||||
{ CRC32_GZIP_REFL, "crc32_gzip_refl", (void *) crc32_gzip_refl,
|
||||
(void *) crc32_gzip_refl_base, RESULT_CRC32 },
|
||||
{ CRC32_IEEE, "crc32_ieee", (void *) crc32_ieee, (void *) crc32_ieee_base, RESULT_CRC32 },
|
||||
{ CRC32_ISCSI, "crc32_iscsi", (void *) crc32_iscsi_wrapped,
|
||||
(void *) crc32_iscsi_base_wrapped, RESULT_CRC32 },
|
||||
// CRC16 functions
|
||||
{ CRC16_T10DIF, "crc16_t10dif", (void *) crc16_t10dif, (void *) crc16_t10dif_base,
|
||||
RESULT_CRC16 },
|
||||
// CRC64 functions
|
||||
{ CRC64_ECMA_REFL, "crc64_ecma_refl", (void *) crc64_ecma_refl,
|
||||
(void *) crc64_ecma_refl_base, RESULT_CRC64 },
|
||||
{ CRC64_ECMA_NORM, "crc64_ecma_norm", (void *) crc64_ecma_norm,
|
||||
(void *) crc64_ecma_norm_base, RESULT_CRC64 },
|
||||
{ CRC64_ISO_REFL, "crc64_iso_refl", (void *) crc64_iso_refl, (void *) crc64_iso_refl_base,
|
||||
RESULT_CRC64 },
|
||||
{ CRC64_ISO_NORM, "crc64_iso_norm", (void *) crc64_iso_norm, (void *) crc64_iso_norm_base,
|
||||
RESULT_CRC64 },
|
||||
{ CRC64_JONES_REFL, "crc64_jones_refl", (void *) crc64_jones_refl,
|
||||
(void *) crc64_jones_refl_base, RESULT_CRC64 },
|
||||
{ CRC64_JONES_NORM, "crc64_jones_norm", (void *) crc64_jones_norm,
|
||||
(void *) crc64_jones_norm_base, RESULT_CRC64 },
|
||||
{ CRC64_ROCKSOFT_REFL, "crc64_rocksoft_refl", (void *) crc64_rocksoft_refl,
|
||||
(void *) crc64_rocksoft_refl_base, RESULT_CRC64 },
|
||||
{ CRC64_ROCKSOFT_NORM, "crc64_rocksoft_norm", (void *) crc64_rocksoft_norm,
|
||||
(void *) crc64_rocksoft_norm_base, RESULT_CRC64 },
|
||||
};
|
||||
|
||||
// Number of entries in the CRC function table
|
||||
static const size_t CRC_FUNCS_TABLE_SIZE = sizeof(CRC_FUNCS_TABLE) / sizeof(CRC_FUNCS_TABLE[0]);
|
||||
|
||||
// Helper function to run benchmark for standard CRC function
|
||||
static void
|
||||
run_standard_crc_benchmark(struct perf *start, const crc_func_info_t *func_info,
|
||||
const int run_base_version, const uint8_t *buffer, const size_t len,
|
||||
const int csv_output, const int use_cold_cache, uint8_t **buffer_list,
|
||||
const size_t num_buffers)
|
||||
{
|
||||
const char *function_suffix = run_base_version ? "_base" : "";
|
||||
const char *crc_type_str = func_info->name;
|
||||
|
||||
union {
|
||||
crc32_func_t crc32;
|
||||
crc16_func_t crc16;
|
||||
crc64_func_t crc64;
|
||||
void *ptr;
|
||||
} func;
|
||||
|
||||
// Get appropriate function pointer based on base version flag
|
||||
func.ptr = run_base_version ? func_info->func_base : func_info->func;
|
||||
|
||||
// Execute benchmark based on result type with appropriate benchmark macro
|
||||
if (use_cold_cache && buffer_list) {
|
||||
size_t current_buffer_idx = 0;
|
||||
|
||||
switch (func_info->result_type) {
|
||||
case RESULT_CRC32:
|
||||
BENCHMARK_COLD(start, BENCHMARK_TIME,
|
||||
current_buffer_idx = (current_buffer_idx + 1) % num_buffers,
|
||||
func.crc32(TEST_SEED, buffer_list[current_buffer_idx], len));
|
||||
break;
|
||||
case RESULT_CRC16:
|
||||
BENCHMARK_COLD(start, BENCHMARK_TIME,
|
||||
current_buffer_idx = (current_buffer_idx + 1) % num_buffers,
|
||||
func.crc16(TEST_SEED, buffer_list[current_buffer_idx], len));
|
||||
break;
|
||||
case RESULT_CRC64:
|
||||
BENCHMARK_COLD(start, BENCHMARK_TIME,
|
||||
current_buffer_idx = (current_buffer_idx + 1) % num_buffers,
|
||||
func.crc64(TEST_SEED, buffer_list[current_buffer_idx], len));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Standard warm-cache benchmark
|
||||
switch (func_info->result_type) {
|
||||
case RESULT_CRC32:
|
||||
BENCHMARK(start, BENCHMARK_TIME, func.crc32(TEST_SEED, buffer, len));
|
||||
break;
|
||||
case RESULT_CRC16:
|
||||
BENCHMARK(start, BENCHMARK_TIME, func.crc16(TEST_SEED, buffer, len));
|
||||
break;
|
||||
case RESULT_CRC64:
|
||||
BENCHMARK(start, BENCHMARK_TIME, func.crc64(TEST_SEED, buffer, len));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Print results in appropriate format
|
||||
if (csv_output) {
|
||||
#ifdef USE_RDTSC
|
||||
// When USE_RDTSC is defined, report total cycles per buffer
|
||||
double cycles = (double) get_base_elapsed(start);
|
||||
double cycles_per_buffer = cycles / (double) start->iterations;
|
||||
printf("%s%s,%zu,%.0f\n", crc_type_str, function_suffix, len, cycles_per_buffer);
|
||||
#else
|
||||
// Calculate throughput in MB/s
|
||||
double time_elapsed = get_time_elapsed(start);
|
||||
long long total_units = start->iterations * (long long) len;
|
||||
double throughput = ((double) total_units) / (1000000 * time_elapsed);
|
||||
printf("%s%s,%zu,%.2f\n", crc_type_str, function_suffix, len, throughput);
|
||||
#endif
|
||||
} else {
|
||||
printf("%s%s : ", crc_type_str, function_suffix);
|
||||
perf_print(*start, (long long) len);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to run a specific CRC benchmark
|
||||
static void
|
||||
run_benchmark(void *buf, size_t len, crc_type_t type, int run_base_version, int csv_output)
|
||||
run_benchmark(const void *buf, const size_t len, const crc_type_t type, const int run_base_version,
|
||||
const int csv_output, const int use_cold_cache)
|
||||
{
|
||||
struct perf start;
|
||||
perf_init(&start);
|
||||
uint8_t *buffer = (uint8_t *) buf; // Proper casting to match function signatures
|
||||
const char *crc_type_str = "";
|
||||
const char *function_suffix = run_base_version ? "_base" : "";
|
||||
|
||||
// For result storage
|
||||
uint32_t crc32_result = 0;
|
||||
uint16_t crc16_result = 0;
|
||||
uint64_t crc64_result = 0;
|
||||
// For cold cache benchmarking
|
||||
uint8_t **buffer_list = NULL;
|
||||
size_t num_buffers = 0;
|
||||
|
||||
// Create list of random buffer address within the large memory space already allocated for
|
||||
// cold cache tests
|
||||
if (use_cold_cache) {
|
||||
num_buffers = COLD_CACHE_TEST_MEM / len;
|
||||
|
||||
buffer_list = (uint8_t **) malloc(num_buffers * sizeof(uint8_t *));
|
||||
if (!buffer_list) {
|
||||
printf("Failed to allocate memory for cold cache buffers\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < num_buffers; i++)
|
||||
buffer_list[i] = buffer + len * (rand() % num_buffers);
|
||||
}
|
||||
|
||||
// First check if this is a standard CRC function that can use the table
|
||||
for (size_t i = 0; i < CRC_FUNCS_TABLE_SIZE; i++) {
|
||||
if (CRC_FUNCS_TABLE[i].type == type) {
|
||||
run_standard_crc_benchmark(&start, &CRC_FUNCS_TABLE[i], run_base_version,
|
||||
buffer, len, csv_output, use_cold_cache,
|
||||
buffer_list, num_buffers);
|
||||
if (buffer_list)
|
||||
free(buffer_list);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer_list)
|
||||
free(buffer_list);
|
||||
|
||||
// Handle special cases that don't fit the standard parameter format
|
||||
switch (type) {
|
||||
// CRC32 types
|
||||
case CRC32_GZIP_REFL:
|
||||
crc_type_str = "crc32_gzip_refl";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc32_result = crc32_gzip_refl_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc32_result = crc32_gzip_refl(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC32_IEEE:
|
||||
crc_type_str = "crc32_ieee";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc32_result = crc32_ieee_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc32_result = crc32_ieee(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC32_ISCSI:
|
||||
crc_type_str = "crc32_iscsi";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc32_result = crc32_iscsi_base(buffer, (int) len, TEST_SEED));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc32_result = crc32_iscsi(buffer, (int) len, TEST_SEED));
|
||||
}
|
||||
break;
|
||||
|
||||
// CRC16 types
|
||||
case CRC16_T10DIF:
|
||||
crc_type_str = "crc16_t10dif";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc16_result = crc16_t10dif_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc16_result = crc16_t10dif(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC16_T10DIF_COPY: {
|
||||
case CRC16_T10DIF_COPY:
|
||||
crc_type_str = "crc16_t10dif_copy";
|
||||
uint8_t *dst_buf = malloc(len);
|
||||
if (!dst_buf) {
|
||||
@@ -163,107 +295,15 @@ run_benchmark(void *buf, size_t len, crc_type_t type, int run_base_version, int
|
||||
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc16_result =
|
||||
crc16_t10dif_copy_base(TEST_SEED, dst_buf, buffer, len));
|
||||
crc16_t10dif_copy_base(TEST_SEED, dst_buf, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc16_result =
|
||||
crc16_t10dif_copy(TEST_SEED, dst_buf, buffer, len));
|
||||
crc16_t10dif_copy(TEST_SEED, dst_buf, buffer, len));
|
||||
}
|
||||
free(dst_buf);
|
||||
} break;
|
||||
|
||||
// CRC64 types
|
||||
case CRC64_ECMA_REFL:
|
||||
crc_type_str = "crc64_ecma_refl";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_ecma_refl_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_ecma_refl(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC64_ECMA_NORM:
|
||||
crc_type_str = "crc64_ecma_norm";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_ecma_norm_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_ecma_norm(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC64_ISO_REFL:
|
||||
crc_type_str = "crc64_iso_refl";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_iso_refl_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_iso_refl(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC64_ISO_NORM:
|
||||
crc_type_str = "crc64_iso_norm";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_iso_norm_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_iso_norm(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC64_JONES_REFL:
|
||||
crc_type_str = "crc64_jones_refl";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_jones_refl_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_jones_refl(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC64_JONES_NORM:
|
||||
crc_type_str = "crc64_jones_norm";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_jones_norm_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_jones_norm(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC64_ROCKSOFT_REFL:
|
||||
crc_type_str = "crc64_rocksoft_refl";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_rocksoft_refl_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_rocksoft_refl(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
case CRC64_ROCKSOFT_NORM:
|
||||
crc_type_str = "crc64_rocksoft_norm";
|
||||
if (run_base_version) {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_rocksoft_norm_base(TEST_SEED, buffer, len));
|
||||
} else {
|
||||
BENCHMARK(&start, BENCHMARK_TIME,
|
||||
crc64_result = crc64_rocksoft_norm(TEST_SEED, buffer, len));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Invalid CRC type\n");
|
||||
printf("Error: CRC type %d not found or not implemented\n", type);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -284,11 +324,6 @@ run_benchmark(void *buf, size_t len, crc_type_t type, int run_base_version, int
|
||||
printf("%s%s : ", crc_type_str, function_suffix);
|
||||
perf_print(start, (long long) len);
|
||||
}
|
||||
|
||||
// Prevent results from being unused
|
||||
(void) crc32_result;
|
||||
(void) crc16_result;
|
||||
(void) crc64_result;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -323,12 +358,12 @@ print_help(void)
|
||||
{
|
||||
printf("Usage: crc_funcs_perf [options]\n");
|
||||
printf(" -h, --help Show this help message\n");
|
||||
printf(" -t, --type=TYPE CRC type to benchmark\n");
|
||||
printf(" -t, --type TYPE CRC type to benchmark\n");
|
||||
print_crc_types();
|
||||
printf(" If no value is provided, lists available types and "
|
||||
"exits\n");
|
||||
printf(" -b, --base Include base (non-optimized) versions in benchmark\n");
|
||||
printf(" -r, --range=MIN:STEP:MAX Run tests with buffer sizes from MIN to MAX in STEP "
|
||||
printf(" -r, --range MIN:STEP:MAX Run tests with buffer sizes from MIN to MAX in STEP "
|
||||
"increments\n");
|
||||
printf(" If STEP starts with '*', it's treated as a multiplier\n");
|
||||
printf(" Size values can include K (KB) or M (MB) suffix\n");
|
||||
@@ -336,7 +371,7 @@ print_help(void)
|
||||
printf(" --range=1K:1K:16K (1KB to 16KB in 1KB steps)\n");
|
||||
printf(" --range=1K:*2:16K (1KB, 2KB, 4KB, 8KB, 16KB)\n");
|
||||
printf(" --range=1M:1M:32M (1MB to 32MB in 1MB steps)\n");
|
||||
printf(" -s, --sizes=SIZE1,SIZE2,... Run tests with specified comma-separated buffer "
|
||||
printf(" -s, --sizes SIZE1,SIZE2,... Run tests with specified comma-separated buffer "
|
||||
"sizes\n");
|
||||
printf(" Example: --sizes=1024,4096,8192,16384\n");
|
||||
printf(" Size values can include K (KB) or M (MB) suffix\n");
|
||||
@@ -344,6 +379,8 @@ print_help(void)
|
||||
printf(" If no size option is provided, default size (%d) is used\n",
|
||||
DEFAULT_TEST_LEN);
|
||||
printf(" -c, --csv Output results in CSV format\n");
|
||||
printf(" --cold Use cold cache for benchmarks (buffer not in cache, "
|
||||
"t10dif_copy not supported)\n");
|
||||
}
|
||||
|
||||
// Helper function to parse string input for CRC type
|
||||
@@ -413,7 +450,7 @@ parse_size_value(const char *const size_str)
|
||||
char *str_copy = strdup(size_str);
|
||||
|
||||
// Check for size suffixes (K for KB, M for MB)
|
||||
int len = strlen(str_copy);
|
||||
const int len = strlen(str_copy);
|
||||
if (len > 0) {
|
||||
// Convert to uppercase for case-insensitive comparison
|
||||
char last_char = toupper(str_copy[len - 1]);
|
||||
@@ -446,9 +483,9 @@ parse_size_value(const char *const size_str)
|
||||
|
||||
// Helper function to run benchmarks for a specific CRC type (range version)
|
||||
static void
|
||||
run_crc_type_range(crc_type_t type, void *buf, size_t min_len, size_t max_len,
|
||||
const int is_multiplicative, const size_t abs_step, int csv_output,
|
||||
int include_base)
|
||||
run_crc_type_range(const crc_type_t type, const void *buf, const size_t min_len,
|
||||
const size_t max_len, const int is_multiplicative, const size_t abs_step,
|
||||
const int csv_output, const int include_base, const int use_cold_cache)
|
||||
{
|
||||
static const char *const type_names[] = {
|
||||
"GZIP Reflected CRC32", "IEEE CRC32", "iSCSI CRC32",
|
||||
@@ -467,9 +504,9 @@ run_crc_type_range(crc_type_t type, void *buf, size_t min_len, size_t max_len,
|
||||
printf("\n Buffer size: %zu bytes\n", len);
|
||||
}
|
||||
|
||||
run_benchmark(buf, len, type, 0, csv_output);
|
||||
run_benchmark(buf, len, type, 0, csv_output, use_cold_cache);
|
||||
if (include_base)
|
||||
run_benchmark(buf, len, type, 1, csv_output);
|
||||
run_benchmark(buf, len, type, 1, csv_output, use_cold_cache);
|
||||
|
||||
// Update length based on step type
|
||||
if (is_multiplicative) {
|
||||
@@ -482,8 +519,9 @@ run_crc_type_range(crc_type_t type, void *buf, size_t min_len, size_t max_len,
|
||||
|
||||
// Helper function to run benchmarks for a specific CRC type with range of sizes
|
||||
static void
|
||||
benchmark_crc_type_range(crc_type_t crc_type, void *buf, size_t min_len, size_t max_len,
|
||||
ssize_t step_len, int csv_output, int include_base)
|
||||
benchmark_crc_type_range(const crc_type_t crc_type, const void *buf, const size_t min_len,
|
||||
const size_t max_len, const ssize_t step_len, const int csv_output,
|
||||
const int include_base, const int use_cold_cache)
|
||||
{
|
||||
const int is_multiplicative = (step_len < 0);
|
||||
const size_t abs_step = is_multiplicative ? -step_len : step_len;
|
||||
@@ -495,7 +533,7 @@ benchmark_crc_type_range(crc_type_t crc_type, void *buf, size_t min_len, size_t
|
||||
|
||||
for (size_t i = 0; i < CRC32_TYPES_LEN; i++) {
|
||||
run_crc_type_range(CRC32_TYPES[i], buf, min_len, max_len, is_multiplicative,
|
||||
abs_step, csv_output, include_base);
|
||||
abs_step, csv_output, include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,7 +543,7 @@ benchmark_crc_type_range(crc_type_t crc_type, void *buf, size_t min_len, size_t
|
||||
|
||||
for (size_t i = 0; i < CRC16_TYPES_LEN; i++) {
|
||||
run_crc_type_range(CRC16_TYPES[i], buf, min_len, max_len, is_multiplicative,
|
||||
abs_step, csv_output, include_base);
|
||||
abs_step, csv_output, include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -515,7 +553,7 @@ benchmark_crc_type_range(crc_type_t crc_type, void *buf, size_t min_len, size_t
|
||||
|
||||
for (size_t i = 0; i < CRC64_TYPES_LEN; i++) {
|
||||
run_crc_type_range(CRC64_TYPES[i], buf, min_len, max_len, is_multiplicative,
|
||||
abs_step, csv_output, include_base);
|
||||
abs_step, csv_output, include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,14 +561,15 @@ benchmark_crc_type_range(crc_type_t crc_type, void *buf, size_t min_len, size_t
|
||||
if (crc_type != CRC_ALL && crc_type != CRC32_ALL && crc_type != CRC16_ALL &&
|
||||
crc_type != CRC64_ALL) {
|
||||
run_crc_type_range(crc_type, buf, min_len, max_len, is_multiplicative, abs_step,
|
||||
csv_output, include_base);
|
||||
csv_output, include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to run benchmarks for a specific CRC type with list of sizes
|
||||
static void
|
||||
run_crc_type_size_list(crc_type_t type, void *buf, const size_t *size_list, const int size_count,
|
||||
int csv_output, int include_base)
|
||||
run_crc_type_size_list(const crc_type_t type, const void *buf, const size_t *size_list,
|
||||
const int size_count, const int csv_output, const int include_base,
|
||||
const int use_cold_cache)
|
||||
{
|
||||
static const char *const type_names[] = {
|
||||
"GZIP Reflected CRC32", "IEEE CRC32", "iSCSI CRC32",
|
||||
@@ -549,16 +588,16 @@ run_crc_type_size_list(crc_type_t type, void *buf, const size_t *size_list, cons
|
||||
printf("\n Buffer size: %zu bytes\n", size_list[i]);
|
||||
}
|
||||
|
||||
run_benchmark(buf, size_list[i], type, 0, csv_output);
|
||||
run_benchmark(buf, size_list[i], type, 0, csv_output, use_cold_cache);
|
||||
if (include_base)
|
||||
run_benchmark(buf, size_list[i], type, 1, csv_output);
|
||||
run_benchmark(buf, size_list[i], type, 1, csv_output, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to run benchmarks for a specific CRC type with default size
|
||||
static void
|
||||
run_crc_type_default(crc_type_t type, void *buf, const size_t test_len, int csv_output,
|
||||
int include_base)
|
||||
run_crc_type_default(const crc_type_t type, const void *buf, const size_t test_len,
|
||||
const int csv_output, const int include_base, const int use_cold_cache)
|
||||
{
|
||||
static const char *const type_names[] = {
|
||||
"GZIP Reflected CRC32", "IEEE CRC32", "iSCSI CRC32",
|
||||
@@ -576,15 +615,15 @@ run_crc_type_default(crc_type_t type, void *buf, const size_t test_len, int csv_
|
||||
printf("\n Buffer size: %zu bytes\n", test_len);
|
||||
}
|
||||
|
||||
run_benchmark(buf, test_len, type, 0, csv_output);
|
||||
run_benchmark(buf, test_len, type, 0, csv_output, use_cold_cache);
|
||||
if (include_base)
|
||||
run_benchmark(buf, test_len, type, 1, csv_output);
|
||||
run_benchmark(buf, test_len, type, 1, csv_output, use_cold_cache);
|
||||
}
|
||||
|
||||
// Helper function to run benchmarks for a specific CRC type with default size
|
||||
static void
|
||||
benchmark_crc_type_default(crc_type_t crc_type, void *buf, const size_t test_len, int csv_output,
|
||||
int include_base)
|
||||
benchmark_crc_type_default(const crc_type_t crc_type, const void *buf, const size_t test_len,
|
||||
const int csv_output, const int include_base, const int use_cold_cache)
|
||||
{
|
||||
// Run selected benchmarks based on crc_type
|
||||
if (crc_type == CRC_ALL || crc_type == CRC32_ALL) {
|
||||
@@ -593,7 +632,7 @@ benchmark_crc_type_default(crc_type_t crc_type, void *buf, const size_t test_len
|
||||
|
||||
for (size_t i = 0; i < CRC32_TYPES_LEN; i++) {
|
||||
run_crc_type_default(CRC32_TYPES[i], buf, test_len, csv_output,
|
||||
include_base);
|
||||
include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -603,7 +642,7 @@ benchmark_crc_type_default(crc_type_t crc_type, void *buf, const size_t test_len
|
||||
|
||||
for (size_t i = 0; i < CRC16_TYPES_LEN; i++) {
|
||||
run_crc_type_default(CRC16_TYPES[i], buf, test_len, csv_output,
|
||||
include_base);
|
||||
include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,21 +652,23 @@ benchmark_crc_type_default(crc_type_t crc_type, void *buf, const size_t test_len
|
||||
|
||||
for (size_t i = 0; i < CRC64_TYPES_LEN; i++) {
|
||||
run_crc_type_default(CRC64_TYPES[i], buf, test_len, csv_output,
|
||||
include_base);
|
||||
include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
// If none of the above, run just the specific CRC type
|
||||
if (crc_type != CRC_ALL && crc_type != CRC32_ALL && crc_type != CRC16_ALL &&
|
||||
crc_type != CRC64_ALL) {
|
||||
run_crc_type_default(crc_type, buf, test_len, csv_output, include_base);
|
||||
run_crc_type_default(crc_type, buf, test_len, csv_output, include_base,
|
||||
use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to run benchmarks for a specific CRC type with list of sizes
|
||||
static void
|
||||
benchmark_crc_type_size_list(crc_type_t crc_type, void *buf, const size_t *size_list,
|
||||
const int size_count, int csv_output, int include_base)
|
||||
benchmark_crc_type_size_list(const crc_type_t crc_type, const void *buf, const size_t *size_list,
|
||||
const int size_count, const int csv_output, const int include_base,
|
||||
const int use_cold_cache)
|
||||
{
|
||||
// Run selected benchmarks based on crc_type
|
||||
if (crc_type == CRC_ALL || crc_type == CRC32_ALL) {
|
||||
@@ -636,7 +677,7 @@ benchmark_crc_type_size_list(crc_type_t crc_type, void *buf, const size_t *size_
|
||||
|
||||
for (size_t i = 0; i < CRC32_TYPES_LEN; i++) {
|
||||
run_crc_type_size_list(CRC32_TYPES[i], buf, size_list, size_count,
|
||||
csv_output, include_base);
|
||||
csv_output, include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,7 +687,7 @@ benchmark_crc_type_size_list(crc_type_t crc_type, void *buf, const size_t *size_
|
||||
|
||||
for (size_t i = 0; i < CRC16_TYPES_LEN; i++) {
|
||||
run_crc_type_size_list(CRC16_TYPES[i], buf, size_list, size_count,
|
||||
csv_output, include_base);
|
||||
csv_output, include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,7 +697,7 @@ benchmark_crc_type_size_list(crc_type_t crc_type, void *buf, const size_t *size_
|
||||
|
||||
for (size_t i = 0; i < CRC64_TYPES_LEN; i++) {
|
||||
run_crc_type_size_list(CRC64_TYPES[i], buf, size_list, size_count,
|
||||
csv_output, include_base);
|
||||
csv_output, include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -664,20 +705,24 @@ benchmark_crc_type_size_list(crc_type_t crc_type, void *buf, const size_t *size_
|
||||
if (crc_type != CRC_ALL && crc_type != CRC32_ALL && crc_type != CRC16_ALL &&
|
||||
crc_type != CRC64_ALL) {
|
||||
run_crc_type_size_list(crc_type, buf, size_list, size_count, csv_output,
|
||||
include_base);
|
||||
include_base, use_cold_cache);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char *const *argv)
|
||||
main(const int argc, char *const argv[])
|
||||
{
|
||||
void *buf;
|
||||
crc_type_t crc_type = CRC_ALL;
|
||||
int include_base = 0;
|
||||
int csv_output = 0; // Flag for CSV output mode
|
||||
size_t test_len = DEFAULT_TEST_LEN;
|
||||
int csv_output = 0; // Default to human-readable output
|
||||
int include_base = 0; // Don't include base versions by default
|
||||
int use_cold_cache = 0; // Don't use cold cache by default
|
||||
crc_type_t crc_type = CRC_ALL; // Default to all CRC types
|
||||
void *buf = NULL;
|
||||
|
||||
// Size range options
|
||||
size_t min_len = DEFAULT_TEST_LEN;
|
||||
size_t max_len = DEFAULT_TEST_LEN;
|
||||
int use_range = 0;
|
||||
size_t min_len = 0, max_len = 0;
|
||||
ssize_t step_len = 0; // Using signed type to indicate additive vs multiplicative
|
||||
|
||||
// For comma-separated sizes option
|
||||
@@ -703,6 +748,12 @@ main(int argc, const char *const *argv)
|
||||
include_base = 1;
|
||||
}
|
||||
|
||||
// Cold cache option
|
||||
else if (strcmp(argv[i], "--cold") == 0) {
|
||||
use_cold_cache = 1;
|
||||
printf("Cold cache option enabled\n");
|
||||
}
|
||||
|
||||
// Type option
|
||||
else if ((strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--type") == 0)) {
|
||||
if (i + 1 < argc && argv[i + 1][0] != '-') {
|
||||
@@ -869,6 +920,9 @@ main(int argc, const char *const *argv)
|
||||
#endif
|
||||
}
|
||||
|
||||
if (use_cold_cache)
|
||||
test_len = COLD_CACHE_TEST_MEM;
|
||||
|
||||
if (posix_memalign(&buf, 64, test_len)) {
|
||||
printf("alloc error: Fail\n");
|
||||
return -1;
|
||||
@@ -880,6 +934,11 @@ main(int argc, const char *const *argv)
|
||||
|
||||
// Process according to chosen CRC type and size options
|
||||
if (use_range) {
|
||||
if (use_cold_cache && min_len <= COLD_CACHE_MIN_LEN)
|
||||
printf("Error: Cold cache tests require buffer sizes larger than "
|
||||
"%u bytes.",
|
||||
COLD_CACHE_MIN_LEN);
|
||||
|
||||
// Use range-based sizes
|
||||
if (!csv_output) {
|
||||
printf("Running benchmarks with size range from %zu to %zu\n", min_len,
|
||||
@@ -888,20 +947,26 @@ main(int argc, const char *const *argv)
|
||||
|
||||
// Call the benchmark function for specific type with range parameters
|
||||
benchmark_crc_type_range(crc_type, buf, min_len, max_len, step_len, csv_output,
|
||||
include_base);
|
||||
include_base, use_cold_cache);
|
||||
|
||||
} else if (use_size_list) {
|
||||
if (use_cold_cache && size_list[0] <= COLD_CACHE_MIN_LEN)
|
||||
printf("Error: Cold cache tests require buffer sizes larger than "
|
||||
"%u bytes.",
|
||||
COLD_CACHE_MIN_LEN);
|
||||
|
||||
// Use list of specific sizes
|
||||
|
||||
// Call the benchmark function for specific type with size list parameters
|
||||
benchmark_crc_type_size_list(crc_type, buf, size_list, size_count, csv_output,
|
||||
include_base);
|
||||
include_base, use_cold_cache);
|
||||
|
||||
} else {
|
||||
// Use default size or single size specified
|
||||
|
||||
// Call the benchmark function for specific type with default size
|
||||
benchmark_crc_type_default(crc_type, buf, test_len, csv_output, include_base);
|
||||
benchmark_crc_type_default(crc_type, buf, test_len, csv_output, include_base,
|
||||
use_cold_cache);
|
||||
}
|
||||
|
||||
if (!csv_output) {
|
||||
|
||||
@@ -188,6 +188,7 @@ perf_init(struct perf *p)
|
||||
p->start = 0;
|
||||
p->stop = 0;
|
||||
p->run_total = 0;
|
||||
p->iterations = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -299,6 +300,71 @@ estimate_perf_iterations(struct perf *p, unsigned long long runs, unsigned long
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define CALIBRATE_COLD(PERF, SETUP_CODE, FUNC_CALL) \
|
||||
do { \
|
||||
unsigned long long _i, _iter = 1; \
|
||||
perf_start((PERF)); \
|
||||
(SETUP_CODE); \
|
||||
(FUNC_CALL); \
|
||||
perf_pause((PERF)); \
|
||||
\
|
||||
while (get_base_elapsed((PERF)) < CALIBRATE_TIME) { \
|
||||
_iter = estimate_perf_iterations((PERF), _iter, 2 * CALIBRATE_TIME); \
|
||||
perf_start((PERF)); \
|
||||
for (_i = 0; _i < _iter; _i++) { \
|
||||
(SETUP_CODE); \
|
||||
(FUNC_CALL); \
|
||||
} \
|
||||
perf_stop((PERF)); \
|
||||
} \
|
||||
((PERF))->iterations = _iter; \
|
||||
} while (0)
|
||||
|
||||
#define PERFORMANCE_TEST_COLD(PERF, RUN_TIME, SETUP_CODE, FUNC_CALL) \
|
||||
do { \
|
||||
unsigned long long _i, _iter = ((PERF))->iterations; \
|
||||
unsigned long long _run_total = (RUN_TIME); \
|
||||
_run_total *= UNIT_SCALE; \
|
||||
_iter = estimate_perf_iterations((PERF), _iter, _run_total); \
|
||||
((PERF))->iterations = 0; \
|
||||
perf_start((PERF)); \
|
||||
for (_i = 0; _i < _iter; _i++) { \
|
||||
(SETUP_CODE); \
|
||||
(FUNC_CALL); \
|
||||
} \
|
||||
perf_pause((PERF)); \
|
||||
((PERF))->iterations += _iter; \
|
||||
\
|
||||
if (get_base_elapsed((PERF)) < _run_total && \
|
||||
BENCHMARK_TYPE == BENCHMARK_MIN_TIME) { \
|
||||
_iter = estimate_perf_iterations((PERF), _iter, \
|
||||
_run_total - get_base_elapsed((PERF)) + \
|
||||
(UNIT_SCALE / 16)); \
|
||||
perf_continue((PERF)); \
|
||||
for (_i = 0; _i < _iter; _i++) { \
|
||||
(SETUP_CODE); \
|
||||
(FUNC_CALL); \
|
||||
} \
|
||||
perf_pause((PERF)); \
|
||||
((PERF))->iterations += _iter; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define BENCHMARK_COLD(PERF, RUN_TIME, SETUP_CODE, FUNC_CALL) \
|
||||
do { \
|
||||
if ((RUN_TIME) > 0) { \
|
||||
CALIBRATE_COLD((PERF), (SETUP_CODE), (FUNC_CALL)); \
|
||||
PERFORMANCE_TEST_COLD((PERF), (RUN_TIME), (SETUP_CODE), (FUNC_CALL)); \
|
||||
\
|
||||
} else { \
|
||||
((PERF))->iterations = 1; \
|
||||
perf_start((PERF)); \
|
||||
(SETUP_CODE); \
|
||||
(FUNC_CALL); \
|
||||
perf_stop((PERF)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#ifdef USE_CYCLES
|
||||
static inline void
|
||||
perf_print(struct perf p, long long unit_count)
|
||||
|
||||
Reference in New Issue
Block a user