diff --git a/Makefile b/Makefile index 9a6a9cb..bb8bf9b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-lm -g -Wall -O0 +CFLAGS=-lm -g -Wall -O1 build/main: src/main.c src/repetition_tester.c build/nop_loop.o src/rprof.h mkdir -p build diff --git a/src/main.c b/src/main.c index ef35cf9..781f63d 100644 --- a/src/main.c +++ b/src/main.c @@ -9,7 +9,9 @@ #include "rprof.h" #include "main_read_file.c" -#include "main_write_bytes.c" +#include "main_write_bytes_asm.c" +#include "main_write_all_bytes.c" +#include "main_malloc_read.c" int main(int argc, char **argv) { if (argc < 2) { @@ -19,8 +21,10 @@ int main(int argc, char **argv) { char *test_name = argv[1]; - if (!strncmp(test_name, "write_bytes", sizeof("write_bytes"))) { - return main_test_write_bytes(); + if (!strncmp(test_name, "write_bytes_asm", sizeof("write_bytes_asm"))) { + return main_test_write_bytes_asm(); + } else if (!strncmp(test_name, "write_all_bytes", sizeof("write_bytes"))) { + return main_test_write_all_bytes(); } else if (!strncmp(test_name, "read_file", sizeof("read_file"))) { if (argc < 3) { printf("Usage: %s read_file \n", argv[0]); @@ -28,6 +32,13 @@ int main(int argc, char **argv) { } return main_test_read_file(argv[2]); + } else if (!strncmp(test_name, "malloc_read", sizeof("malloc_read"))) { + if (argc < 3) { + printf("Usage: %s malloc_read \n", argv[0]); + return -1; + } + + return main_test_malloc_read(argv[2]); } else { printf("ERROR: Unknown test case '%s'\n", test_name); return -1; diff --git a/src/main_malloc_read.c b/src/main_malloc_read.c new file mode 100644 index 0000000..4f107e7 --- /dev/null +++ b/src/main_malloc_read.c @@ -0,0 +1,114 @@ +#include +#include +#include +#include + +#include "utils.c" +#include "repetition_tester.c" + +static void read_malloc_file_with_fread(bool should_alloc, struct repetitor *repetitor, uint8_t *buffer, uint64_t buffer_size, char *filename) { + alloc_buffer(should_alloc, &buffer, buffer_size); + + FILE *file = fopen(filename, "r"); + + uint64_t read_amount = 0; + while (read_amount < buffer_size) { + repetitor_measure_start(repetitor); + int result = fread(&buffer[read_amount], 1, buffer_size - read_amount, file); + repetitor_measure_stop(repetitor, result > 0 ? result : 0); + + if (result <= 0) { + printf("ERROR: Failed to read from file\n"); + break; + } + + read_amount += result; + } + + fclose(file); + + free_buffer(should_alloc, buffer); +} + +static void read_malloc_file_with_read(bool should_alloc, struct repetitor *repetitor, uint8_t *buffer, uint64_t buffer_size, char *filename) { + alloc_buffer(should_alloc, &buffer, buffer_size); + + int file = open(filename, O_RDONLY); + + uint64_t read_amount = 0; + while (read_amount < buffer_size) { + repetitor_measure_start(repetitor); + int result = read(file, &buffer[read_amount], buffer_size - read_amount); + repetitor_measure_stop(repetitor, result > 0 ? result : 0); + + if (result <= 0) { + printf("ERROR: Failed to read from file\n"); + break; + } + + read_amount += result; + } + + close(file); + + free_buffer(should_alloc, buffer); +} + +int main_test_malloc_read(char *filename) { + typedef void (*read_file_b)(bool should_alloc, struct repetitor *repetitor, uint8_t *buffer, uint64_t buffer_size, char *filename); + struct testcase { + char *name; + read_file_b cb; + }; + + struct testcase cases[] = { + { .name = "read()", .cb = read_malloc_file_with_fread }, + { .name = "fread()", .cb = read_malloc_file_with_read }, + }; + + struct repetitor repetitor = {}; + repetitor_init(&repetitor); + printf("CPU Frequency: %ldHz (~%.2fGHz)\n", repetitor.cpu_freq, (float)repetitor.cpu_freq/(1000*1000*1000)); + + uint64_t file_size = get_file_size(filename); + uint8_t *buffer = malloc(sizeof(uint8_t) * file_size); + memset(buffer, 0, file_size); // Touch memory, so OS would be forced to page in the memory + + while (repeat_cycle_times(&repetitor, 3)) { + for (int i = 0; i < ARRAY_LEN(cases); i++) { + struct testcase *testcase = &cases[i]; + + // With malloc + { + repetitor_clear(&repetitor); + + while (repetitor_repeat(&repetitor, 3)) { + repetitor_start(&repetitor); + testcase->cb(true, &repetitor, buffer, file_size, filename); + repetitor_stop(&repetitor); + } + + char label[256]; + snprintf(label, sizeof(label), "%s + malloc", testcase->name); + repetitor_print_results_label(&repetitor, label); + } + + // Without malloc + { + repetitor_clear(&repetitor); + + while (repetitor_repeat(&repetitor, 1)) { + repetitor_start(&repetitor); + testcase->cb(false, &repetitor, buffer, file_size, filename); + repetitor_stop(&repetitor); + } + + char label[256]; + snprintf(label, sizeof(label), "%s + no malloc", testcase->name); + repetitor_print_results_label(&repetitor, label); + } + } + } + + return 0; +} diff --git a/src/main_read_file.c b/src/main_read_file.c index 76d46dc..3b254f5 100644 --- a/src/main_read_file.c +++ b/src/main_read_file.c @@ -3,20 +3,17 @@ #include #include +#include "utils.c" #include "repetition_tester.c" -uint64_t get_file_size(const char *filename) { - struct stat result; - stat(filename, &result); - return result.st_size; -} - -void read_file_with_fread(uint8_t *buffer, uint64_t buffer_size, char *filename) { +void read_file_with_fread(struct repetitor *repetitor, uint8_t *buffer, uint64_t buffer_size, char *filename) { FILE *file = fopen(filename, "r"); uint64_t read_amount = 0; while (read_amount < buffer_size) { + repetitor_measure_start(repetitor); int result = fread(&buffer[read_amount], 1, buffer_size - read_amount, file); + repetitor_measure_stop(repetitor, result > 0 ? result : 0); if (result <= 0) { printf("ERROR: Failed to read from file\n"); @@ -29,12 +26,14 @@ void read_file_with_fread(uint8_t *buffer, uint64_t buffer_size, char *filename) fclose(file); } -void read_file_with_read(uint8_t *buffer, uint64_t buffer_size, char *filename) { +void read_file_with_read(struct repetitor *repetitor, uint8_t *buffer, uint64_t buffer_size, char *filename) { int file = open(filename, O_RDONLY); uint64_t read_amount = 0; while (read_amount < buffer_size) { + repetitor_measure_start(repetitor); int result = read(file, &buffer[read_amount], buffer_size - read_amount); + repetitor_measure_stop(repetitor, result > 0 ? result : 0); if (result <= 0) { printf("ERROR: Failed to read from file\n"); @@ -48,7 +47,7 @@ void read_file_with_read(uint8_t *buffer, uint64_t buffer_size, char *filename) } int main_test_read_file(char *filename) { - typedef void (*read_file_b)(uint8_t *buffer, uint64_t buffer_size, char *filename); + typedef void (*read_file_b)(struct repetitor *repetitor, uint8_t *buffer, uint64_t buffer_size, char *filename); struct testcase { char *name; read_file_b cb; @@ -66,15 +65,15 @@ int main_test_read_file(char *filename) { uint64_t file_size = get_file_size(filename); uint8_t *buffer = malloc(sizeof(uint8_t) * file_size); - while (repeat_forever(&repetitor)) { + while (repeat_cycle_times(&repetitor, 3)) { for (int i = 0; i < ARRAY_LEN(cases); i++) { struct testcase *testcase = &cases[i]; repetitor_clear(&repetitor); while (repetitor_repeat(&repetitor, 1)) { repetitor_start(&repetitor); - testcase->cb(buffer, file_size, filename); - repetitor_stop(&repetitor, file_size); + testcase->cb(&repetitor, buffer, file_size, filename); + repetitor_stop(&repetitor); } repetitor_print_results_label(&repetitor, testcase->name); diff --git a/src/main_write_all_bytes.c b/src/main_write_all_bytes.c new file mode 100644 index 0000000..fdbfa6d --- /dev/null +++ b/src/main_write_all_bytes.c @@ -0,0 +1,42 @@ +#include "repetition_tester.c" +#include "utils.c" + +static void test_write_to_all_bytes(struct repetitor *repetitor, uint8_t *buffer, uint64_t buffer_size, bool should_alloc) { + repetitor_clear(repetitor); + + while (repetitor_repeat(repetitor, 2)) { + repetitor_start(repetitor); + alloc_buffer(should_alloc, &buffer, buffer_size); + + repetitor_measure_start(repetitor); + for (int i = 0; i < buffer_size; i++) { + buffer[i] = (uint8_t)i; + } + repetitor_measure_stop(repetitor, buffer_size); + + free_buffer(should_alloc, buffer); + repetitor_stop(repetitor); + } +} + +int main_test_write_all_bytes() { + + struct repetitor repetitor = {}; + repetitor_init(&repetitor); + printf("CPU Frequency: %ldHz (~%.2fGHz)\n", repetitor.cpu_freq, (float)repetitor.cpu_freq/(1000*1000*1000)); + + uint64_t byte_count = 4096 * (1024 * 8); + uint8_t *buffer = malloc(sizeof(uint8_t) * byte_count); + memset(buffer, 0, byte_count); // Touch memory, so OS would be forced to page in the memory + + while (repeat_cycle_forever(&repetitor)) { + test_write_to_all_bytes(&repetitor, buffer, byte_count, false); + repetitor_print_results_label(&repetitor, "write to all bytes + no malloc"); + + test_write_to_all_bytes(&repetitor, buffer, byte_count, true); + repetitor_print_results_label(&repetitor, "write to all bytes + malloc"); + } + + return 0; +} + diff --git a/src/main_write_bytes.c b/src/main_write_bytes_asm.c similarity index 86% rename from src/main_write_bytes.c rename to src/main_write_bytes_asm.c index e005f36..b6aee6c 100644 --- a/src/main_write_bytes.c +++ b/src/main_write_bytes_asm.c @@ -1,7 +1,7 @@ #include "repetition_tester.c" #include "nop_loop.h" -int main_test_write_bytes() { +int main_test_write_bytes_asm() { typedef void (*write_bytes_cb)(uint8_t *buffer, uint64_t byte_count); struct testcase { char *name; @@ -27,8 +27,10 @@ int main_test_write_bytes() { while (repetitor_repeat(&repetitor, 2)) { repetitor_start(&repetitor); + repetitor_measure_start(&repetitor); testcase->cb(buffer, byte_count); - repetitor_stop(&repetitor, byte_count); + repetitor_measure_stop(&repetitor, byte_count); + repetitor_stop(&repetitor); } repetitor_print_results_label(&repetitor, testcase->name); diff --git a/src/repetition_tester.c b/src/repetition_tester.c index 63520d7..2443a53 100644 --- a/src/repetition_tester.c +++ b/src/repetition_tester.c @@ -12,6 +12,7 @@ struct repetitor { uint64_t repetition_count; uint64_t time_taken; uint64_t page_faults; + uint64_t byte_count; uint64_t total_time_taken; uint64_t total_page_faults; @@ -42,6 +43,7 @@ void repetitor_clear(struct repetitor *repetitor) { repetitor->time_taken = 0; repetitor->page_faults = 0; + repetitor->byte_count = 0; repetitor->total_page_faults = 0; repetitor->total_time_taken = 0; @@ -64,38 +66,44 @@ void repetitor_init(struct repetitor *repetitor) { repetitor_clear(repetitor); } -void repetitor_start(struct repetitor *repetitor) { +void repetitor_measure_start(struct repetitor *repetitor) { repetitor->page_faults -= read_page_faults(); repetitor->time_taken -= rprof_read_cpu_timer(); } -void repetitor_stop(struct repetitor *repetitor, uint64_t byte_count) { +void repetitor_measure_stop(struct repetitor *repetitor, int byte_count) { repetitor->time_taken += rprof_read_cpu_timer(); repetitor->page_faults += read_page_faults(); + repetitor->byte_count += byte_count; +} +void repetitor_start(struct repetitor *repetitor) { + repetitor->time_taken = 0; + repetitor->page_faults = 0; + repetitor->byte_count = 0; +} + +void repetitor_stop(struct repetitor *repetitor) { if (repetitor->repetition_count == 0) { repetitor->max_time_taken = repetitor->time_taken; repetitor->max_page_faults = repetitor->page_faults; - repetitor->max_byte_count = byte_count; + repetitor->max_byte_count = repetitor->byte_count; repetitor->min_time_taken = repetitor->time_taken; repetitor->min_page_faults = repetitor->page_faults; - repetitor->min_byte_count = byte_count; + repetitor->min_byte_count = repetitor->byte_count; } else { repetitor->max_time_taken = max_uint64(repetitor->max_time_taken, repetitor->time_taken); repetitor->max_page_faults = max_uint64(repetitor->max_page_faults, repetitor->page_faults); - repetitor->max_byte_count = max_uint64(repetitor->max_byte_count, byte_count); + repetitor->max_byte_count = max_uint64(repetitor->max_byte_count, repetitor->byte_count); repetitor->min_time_taken = min_uint64(repetitor->min_time_taken, repetitor->time_taken); repetitor->min_page_faults = min_uint64(repetitor->min_page_faults, repetitor->page_faults); - repetitor->min_byte_count = min_uint64(repetitor->min_byte_count, byte_count); + repetitor->min_byte_count = min_uint64(repetitor->min_byte_count, repetitor->byte_count); } repetitor->total_time_taken += repetitor->time_taken; repetitor->total_page_faults += repetitor->page_faults; - repetitor->total_byte_count += byte_count; + repetitor->total_byte_count += repetitor->byte_count; repetitor->repetition_count += 1; - - repetitor->time_taken = 0; - repetitor->page_faults = 0; } bool repetitor_repeat(struct repetitor *repetitor, float timeout_seconds) { @@ -121,7 +129,17 @@ bool repetitor_repeat(struct repetitor *repetitor, float timeout_seconds) { return true; } -bool repeat_forever(struct repetitor *repetitor) { +bool repeat_cycle_forever(struct repetitor *repetitor) { + repetitor->repeat_cycle += 1; + printf("======= Cycle %ld ================================\n", repetitor->repeat_cycle); + return true; +} + +bool repeat_cycle_times(struct repetitor *repetitor, int max_cycles) { + if (repetitor->repeat_cycle >= max_cycles) { + return false; + } + repetitor->repeat_cycle += 1; printf("======= Cycle %ld ================================\n", repetitor->repeat_cycle); return true; diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..4a94946 --- /dev/null +++ b/src/utils.c @@ -0,0 +1,27 @@ +#ifndef UTILS_ +#define UTILS_ + +#include +#include +#include +#include + +uint64_t get_file_size(const char *filename) { + struct stat result; + stat(filename, &result); + return result.st_size; +} + +static void alloc_buffer(bool should_alloc, uint8_t **buffer, uint64_t buffer_size) { + if (should_alloc) { + *buffer = malloc(sizeof(uint8_t) * buffer_size); + } +} + +static void free_buffer(bool should_alloc, uint8_t *buffer) { + if (should_alloc) { + free(buffer); + } +} + +#endif //UTILS_