From 7ce71012408d961b873d7ad553195341c6d459ce Mon Sep 17 00:00:00 2001 From: Abdelrahman Date: Sat, 23 Sep 2023 23:55:46 +0100 Subject: [PATCH] Add page fault stats to repetition tester --- .../include/repetition_testing/reptester.h | 11 ++++ haversine_02/src/repetition_testing/main.cpp | 58 +++++++++++++++-- .../src/repetition_testing/reptester.cpp | 62 +++++++++++++++++-- 3 files changed, 121 insertions(+), 10 deletions(-) diff --git a/haversine_02/include/repetition_testing/reptester.h b/haversine_02/include/repetition_testing/reptester.h index 60415e3..9a93edd 100644 --- a/haversine_02/include/repetition_testing/reptester.h +++ b/haversine_02/include/repetition_testing/reptester.h @@ -13,6 +13,7 @@ struct reptest_params { struct reptest_results { u64 bytes_read; u64 read_time; + u64 page_faults; }; struct time_stats { @@ -22,6 +23,14 @@ struct time_stats { u64 total_time; }; +struct mem_stats { + u64 min_faults; + u64 max_faults; + u64 avg_faults; + u64 total_bytes; + u64 total_faults; +}; + struct reptester { reptest_params params; @@ -33,6 +42,7 @@ struct reptester { u64 current_run; time_stats tstats; + mem_stats mstats; reptest_results results; }; @@ -55,6 +65,7 @@ void handle_alloc(reptester *tester, alloc_type type); void handle_free(reptester *tester, alloc_type type); void run_func_test(reptester *tester, reptest_func func, const char *func_name, alloc_type type); +u64 page_fault_count(); void print_results(reptester *tester, const char *name); #endif // !REPTESTER_H diff --git a/haversine_02/src/repetition_testing/main.cpp b/haversine_02/src/repetition_testing/main.cpp index 48e1e22..c168108 100644 --- a/haversine_02/src/repetition_testing/main.cpp +++ b/haversine_02/src/repetition_testing/main.cpp @@ -11,6 +11,7 @@ void test_fread(reptester *tester, alloc_type type); void test_read(reptester *tester, alloc_type type); +void test_write(reptester *tester, alloc_type type); u64 get_file_length(FILE *fp); int main(int argc, char *argv[]) { @@ -41,10 +42,17 @@ int main(int argc, char *argv[]) { 1, // current_run { - UINT64_MAX, // min - 0, // max - 0, // avg - 0, // total + UINT64_MAX, // min_time + 0, // max_time + 0, // avg_time + 0, // total_time + }, + { + 0, // min_faults + 0, // max_faults + 0, // avg_faults + 0, // total_bytes + 0, // total_faults }, {}, // results }; @@ -55,7 +63,8 @@ int main(int argc, char *argv[]) { return -1; } - func_data funcs[] = {{{"READ", "READ WITH MALLOC"}, test_read}, + func_data funcs[] = {{{"WRITE", "WRITE WITH MALLOC"}, test_write}, + {{"READ", "READ WITH MALLOC"}, test_read}, {{"FREAD", "FREAD WITH MALLOC"}, test_fread}}; tester.params.read_size = get_file_length(fp); @@ -87,17 +96,23 @@ void test_fread(reptester *tester, alloc_type type) { handle_alloc(tester, type); u64 start = read_cpu_timer(); + u64 fault_count_start = page_fault_count(); + u64 obj_count = fread(tester->params.buffer, tester->params.read_size, tester->params.read_count, fp); + + u64 fault_count_end = page_fault_count(); u64 end = read_cpu_timer(); u64 bytes_read = obj_count * tester->params.read_size; u64 read_time = end - start; + u64 page_faults = fault_count_end - fault_count_start; tester->results = { bytes_read, read_time, + page_faults, }; handle_free(tester, type); @@ -116,15 +131,21 @@ void test_read(reptester *tester, alloc_type type) { i32 fd = fileno(fp); u64 start = read_cpu_timer(); + u64 fault_count_start = page_fault_count(); + u64 bytes_read = read(fd, tester->params.buffer, tester->params.read_size * tester->params.read_count); + + u64 fault_count_end = page_fault_count(); u64 end = read_cpu_timer(); u64 read_time = end - start; + u64 page_faults = fault_count_end - fault_count_start; tester->results = { bytes_read, read_time, + page_faults, }; handle_free(tester, type); @@ -132,6 +153,33 @@ void test_read(reptester *tester, alloc_type type) { fclose(fp); } +void test_write(reptester *tester, alloc_type type) { + handle_alloc(tester, type); + + u64 start = read_cpu_timer(); + u64 fault_count_start = page_fault_count(); + + u64 total_size = tester->params.read_size * tester->params.read_count; + + for (u64 i = 0; i < total_size; ++i) { + tester->params.buffer[i] = '0'; + } + + u64 fault_count_end = page_fault_count(); + u64 end = read_cpu_timer(); + + u64 read_time = end - start; + u64 page_faults = fault_count_end - fault_count_start; + + tester->results = { + total_size, + read_time, + page_faults, + }; + + handle_free(tester, type); +} + u64 get_file_length(FILE *fp) { if (!fp) { return 0; diff --git a/haversine_02/src/repetition_testing/reptester.cpp b/haversine_02/src/repetition_testing/reptester.cpp index 3a9e646..68f9136 100644 --- a/haversine_02/src/repetition_testing/reptester.cpp +++ b/haversine_02/src/repetition_testing/reptester.cpp @@ -3,6 +3,8 @@ #include #include #include +#include +#include void handle_alloc(reptester *tester, alloc_type type) { switch (type) { @@ -43,6 +45,13 @@ void run_func_test(reptester *tester, reptest_func func, const char *func_name, 0, // avg_time 0, // total_time }; + tester->mstats = { + UINT64_MAX, // min_faults + 0, // max_faults + 0, // avg_faults + 0, // total_bytes + 0, // total_faults + }; tester->results = {}; char *buffer = NULL; @@ -66,12 +75,22 @@ void run_func_test(reptester *tester, reptest_func func, const char *func_name, } tester->tstats.total_time += tester->results.read_time; + tester->mstats.total_bytes += tester->results.bytes_read; + tester->mstats.total_faults += tester->results.page_faults; if (tester->results.read_time > tester->tstats.max_time) { tester->tstats.max_time = tester->results.read_time; + tester->mstats.max_faults = tester->results.page_faults; } else if (tester->results.read_time < tester->tstats.min_time) { tester->test_start_time = read_cpu_timer(); tester->tstats.min_time = tester->results.read_time; + tester->mstats.min_faults = tester->results.page_faults; + } + + if (tester->results.page_faults > tester->mstats.max_faults) { + tester->mstats.max_faults = tester->results.page_faults; + } else if (tester->results.page_faults < tester->mstats.min_faults) { + tester->mstats.min_faults = tester->results.page_faults; } tester->test_time_secs = time_in_seconds( @@ -88,24 +107,57 @@ void run_func_test(reptester *tester, reptest_func func, const char *func_name, print_results(tester, func_name); } -void print_results(reptester *tester, const char *name) { - f64 gb = 1024.0 * 1024.0 * 1024.0; +u64 page_fault_count() { + rusage usage; + getrusage(RUSAGE_SELF, &usage); + + return usage.ru_minflt + usage.ru_majflt; +} + +void print_results(reptester *tester, const char *name) { + f64 kb = 1024.0; + f64 gb = kb * kb * kb; + + f64 size_in_kb = + (f64)(tester->params.read_size * tester->params.read_count) / kb; f64 size_in_gb = (f64)(tester->params.read_size * tester->params.read_count) / gb; u64 run_count = tester->current_run - 1; tester->tstats.avg_time = tester->tstats.total_time / run_count; + tester->mstats.avg_faults = tester->mstats.total_faults / run_count; printf("\n%s: %lu runs\n", name, run_count); - printf("MIN: %lu (%fGB/s)\n", tester->tstats.min_time, + + printf("MIN: %lu (%fGB/s)", tester->tstats.min_time, size_in_gb / time_in_seconds(tester->tstats.min_time, tester->cpu_freq)); - printf("MAX: %lu (%fGB/s)\n", tester->tstats.max_time, + if (tester->mstats.min_faults > 0) { + printf(", FAULTS: %lu (%fK/fault)\n", tester->mstats.min_faults, + size_in_kb / tester->mstats.min_faults); + } else { + printf("\n"); + } + + printf("MAX: %lu (%fGB/s)", tester->tstats.max_time, size_in_gb / time_in_seconds(tester->tstats.max_time, tester->cpu_freq)); - printf("AVG: %lu (%fGB/s)\n", tester->tstats.avg_time, + if (tester->mstats.max_faults > 0) { + printf(", FAULTS: %lu (%fK/fault)\n", tester->mstats.max_faults, + size_in_kb / tester->mstats.max_faults); + } else { + printf("\n"); + } + + printf("AVG: %lu (%fGB/s)", tester->tstats.avg_time, size_in_gb / time_in_seconds(tester->tstats.avg_time, tester->cpu_freq)); + if (tester->mstats.avg_faults > 0) { + printf(", FAULTS: %lu (%fK/fault)\n", tester->mstats.avg_faults, + tester->mstats.total_bytes / kb / tester->mstats.avg_faults); + } else { + printf("\n"); + } }