diff --git a/tests/unit/tests/eviction/lru.c/lru_iter.c b/tests/unit/tests/eviction/lru.c/lru_iter.c new file mode 100644 index 0000000..8d97492 --- /dev/null +++ b/tests/unit/tests/eviction/lru.c/lru_iter.c @@ -0,0 +1,481 @@ +/* + * src/eviction/lru.c + * lru_iter_next + * + * INSERT HERE LIST OF FUNCTIONS YOU WANT TO LEAVE + * ONE FUNCTION PER LINE + * lru_iter_init + * _lru_next_evp + * _lru_evp_is_empty + * _lru_evp_set_empty + * _lru_evp_all_empty + * ocf_rotate_right + * + */ + +#undef static + +#undef inline + + +#include +#include +#include +#include +#include "print_desc.h" + +#include "eviction.h" +#include "lru.h" +#include "ops.h" +#include "../utils/utils_cleaner.h" +#include "../utils/utils_cache_line.h" +#include "../concurrency/ocf_concurrency.h" +#include "../mngt/ocf_mngt_common.h" +#include "../engine/engine_zero.h" +#include "../ocf_request.h" + +#include "eviction/lru.c/lru_iter_generated_wraps.c" + +//#define DEBUG + +ocf_cache_line_t test_cases[10 * OCF_NUM_EVICTION_LISTS][OCF_NUM_EVICTION_LISTS][20]; +unsigned num_cases = 20; + +void write_test_case_description(void) +{ + unsigned i, j, l; + unsigned test_case = 0; + + // case 0 - all lists empty + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + test_cases[0][i][test_case] = -1; + } + + // case 1 - all lists with single element + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + test_cases[0][i][test_case] = 10 * i; + test_cases[1][i][test_case] = -1; + } + + // case 2 - all lists have between 1 and 5 elements, increasingly + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned num_elements = 1 + i / (OCF_NUM_EVICTION_LISTS / 4); + + for (j = 0; j < num_elements; j++) + test_cases[j][i][test_case] = 10 * i + j; + test_cases[j][i][test_case] = -1; + } + + // case 3 - all lists have between 1 and 5 elements, modulo index + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned num_elements = 1 + (i % 5); + + for (j = 0; j < num_elements; j++) + test_cases[j][i][test_case] = 10 * i + j; + test_cases[j][i][test_case] = -1; + } + + // case 4 - all lists have between 0 and 4 elements, increasingly + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned num_elements = i / (OCF_NUM_EVICTION_LISTS / 4); + + for (j = 0; j < num_elements; j++) + test_cases[j][i][test_case] = 10 * i + j; + test_cases[j][i][test_case] = -1; + } + + // case 5 - all lists have between 0 and 4 elements, modulo index + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned num_elements = (i % 5); + + for (j = 0; j < num_elements; j++) + test_cases[j][i][test_case] = 10 * i + j; + test_cases[j][i][test_case] = -1; + } + + // case 6 - list length increasing by 1 from 0 + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned num_elements = i; + + for (j = 0; j < num_elements; j++) + test_cases[j][i][test_case] = OCF_NUM_EVICTION_LISTS * i + j; + test_cases[j][i][test_case] = -1; + } + + // case 7 - list length increasing by 1 from 1 + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned num_elements = i + 1; + + for (j = 0; j < num_elements; j++) + test_cases[j][i][test_case] = 2 * OCF_NUM_EVICTION_LISTS * i + j; + test_cases[j][i][test_case] = -1; + } + + // case 8 - list length increasing by 4 from 0 + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned num_elements = 4 * i; + + for (j = 0; j < num_elements; j++) + test_cases[j][i][test_case] = 4 * OCF_NUM_EVICTION_LISTS * i + j; + test_cases[j][i][test_case] = -1; + } + + // case 9 - list length increasing by 4 from 1 + test_case++; + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned num_elements = 4 * i + 1; + + for (j = 0; j < num_elements; j++) + test_cases[j][i][test_case] = 5 * OCF_NUM_EVICTION_LISTS * i + j; + test_cases[j][i][test_case] = -1; + } + + // cases 10-19: cases 0-9 rotated right by 4 + l = test_case; + test_case++; + while(test_case < 2 * (l + 1)) { + unsigned matching_case = test_case - l - 1; + + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + unsigned curr_list = (i + 4) % OCF_NUM_EVICTION_LISTS; + j = 0; + while(test_cases[j][i][matching_case] != -1) { + test_cases[j][curr_list][test_case] = + test_cases[j][i][matching_case]; + j++; + } + test_cases[j][curr_list][test_case] = -1; + } + test_case++; + } + +#ifdef DEBUG + for (test_case = 0; test_case < num_cases; test_case++) { + print_message("test case no %d\n", test_case); + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) { + print_message("list %02u: ", i); + j = 0; + while (test_cases[j][i][test_case] != -1) { + print_message("%u ", test_cases[j][i][test_case]); + j++; + } + print_message("\n"); + } + print_message("========\n\n"); + } +#endif +} + +unsigned current_case; + +struct ocf_lru_list list; + +struct ocf_lru_list *__wrap_evp_lru_get_list(struct ocf_user_part *part, + uint32_t evp, bool clean) +{ + unsigned i = 0; + + while (test_cases[i][evp][current_case] != -1) + i++; + + if (i == 0) { + list.head = -1; + list.tail = -1; + list.num_nodes = 0; + } else { + list.head = test_cases[0][evp][current_case]; + list.tail = test_cases[i - 1][evp][current_case]; + list.num_nodes = i; + } + + return &list; +} + +inline struct ocf_lru_list *__wrap_evp_get_cline_list(ocf_cache_t cache, + ocf_cache_line_t cline) +{ + return __wrap_evp_lru_get_list(NULL, cline % OCF_NUM_EVICTION_LISTS, true); +} + + +union eviction_policy_meta policy; + +union eviction_policy_meta *__wrap_ocf_metadata_get_eviction_policy( + struct ocf_cache *cache, ocf_cache_line_t line) +{ + unsigned i, j; + + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) + { + j = 0; + + while (test_cases[j][i][current_case] != -1) { + if (test_cases[j][i][current_case] == line) { + if (j == 0) { + policy.lru.prev = -1; + } else { + policy.lru.prev = + test_cases[j - 1][i][current_case]; + } + + policy.lru.next = test_cases[j + 1][i][current_case]; +#ifdef DEBUG + print_message("[%u] next %u prev %u\n", + line, policy.lru.next, + policy.lru.prev); +#endif + return &policy; + } + j++; + } + + } + + print_message("use case %d cache line %d not found\n", + current_case, line); + assert(false); +} + + +static void _lru_run_test(unsigned test_case) +{ + unsigned start_pos; + current_case = test_case; + + for (start_pos = 0; start_pos < OCF_NUM_EVICTION_LISTS; start_pos++) + { + struct ocf_lru_iter iter; + ocf_cache_line_t cache_line, expected_cache_line; + unsigned curr_evp = start_pos; + unsigned pos[OCF_NUM_EVICTION_LISTS]; + unsigned i; + + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) + { + pos[i] = -1; + while(test_cases[pos[i] + 1][i][test_case] != -1) + pos[i]++; + } + + lru_iter_init(&iter, NULL, NULL, start_pos, false); + + do { + /* get cacheline from iterator */ + cache_line = lru_iter_next(&iter); + + /* check what is expected to be returned from iterator */ + if (pos[curr_evp] == -1) { + i = 1; + while (i < OCF_NUM_EVICTION_LISTS && + pos[(curr_evp + i) % OCF_NUM_EVICTION_LISTS] + == -1) { + i++; + } + if (i == OCF_NUM_EVICTION_LISTS) { + /* reached end of lists */ + expected_cache_line = -1; + } else { + curr_evp = (curr_evp + i) % OCF_NUM_EVICTION_LISTS; + expected_cache_line = test_cases[pos[curr_evp]] + [curr_evp][test_case]; + pos[curr_evp]--; + } + } else { + expected_cache_line = test_cases[pos[curr_evp]] + [curr_evp][test_case]; + pos[curr_evp]--; + } + + assert_int_equal(cache_line, expected_cache_line); + + curr_evp = (curr_evp + 1) % OCF_NUM_EVICTION_LISTS; + } while (cache_line != -1); + + /* make sure all cachelines are visited */ + for (i = 0; i < OCF_NUM_EVICTION_LISTS; i++) + { + assert_int_equal((unsigned)-1, pos[i]); + } + } +} + +static void lru_iter_next_test00(void **state) +{ + print_test_description("lru iter test case 00\n"); + _lru_run_test(0); + return; +} + +static void lru_iter_next_test01(void **state) +{ + print_test_description("lru iter test case 01\n"); + _lru_run_test(1); + return; +} + +static void lru_iter_next_test02(void **state) +{ + print_test_description("lru iter test case 02\n"); + _lru_run_test(2); + return; +} + +static void lru_iter_next_test03(void **state) +{ + print_test_description("lru iter test case 03\n"); + _lru_run_test(3); + return; +} + +static void lru_iter_next_test04(void **state) +{ + print_test_description("lru iter test case 04\n"); + _lru_run_test(4); + return; +} + +static void lru_iter_next_test05(void **state) +{ + + print_test_description("lru iter test case 05\n"); + _lru_run_test(5); + return; +} + +static void lru_iter_next_test06(void **state) +{ + print_test_description("lru iter test case 06\n"); + _lru_run_test(6); + return; +} + +static void lru_iter_next_test07(void **state) +{ + print_test_description("lru iter test case 07\n"); + _lru_run_test(7); + return; +} + +static void lru_iter_next_test08(void **state) +{ + print_test_description("lru iter test case 08\n"); + _lru_run_test(8); + return; +} + +static void lru_iter_next_test09(void **state) +{ + print_test_description("lru iter test case 09\n"); + _lru_run_test(9); + return; +} + +static void lru_iter_next_test10(void **state) +{ + print_test_description("lru iter test case 00\n"); + _lru_run_test(10); + return; +} + +static void lru_iter_next_test11(void **state) +{ + print_test_description("lru iter test case 11\n"); + _lru_run_test(11); + return; +} + +static void lru_iter_next_test12(void **state) +{ + print_test_description("lru iter test case 12\n"); + _lru_run_test(12); + return; +} + +static void lru_iter_next_test13(void **state) +{ + print_test_description("lru iter test case 13\n"); + _lru_run_test(13); + return; +} + +static void lru_iter_next_test14(void **state) +{ + print_test_description("lru iter test case 14\n"); + _lru_run_test(14); + return; +} + +static void lru_iter_next_test15(void **state) +{ + print_test_description("lru iter test case 15\n"); + _lru_run_test(15); + return; +} + +static void lru_iter_next_test16(void **state) +{ + print_test_description("lru iter test case 16\n"); + _lru_run_test(16); + return; +} + +static void lru_iter_next_test17(void **state) +{ + print_test_description("lru iter test case 17\n"); + _lru_run_test(17); + return; +} + +static void lru_iter_next_test18(void **state) +{ + print_test_description("lru iter test case 18\n"); + _lru_run_test(18); + return; +} + +static void lru_iter_next_test19(void **state) +{ + print_test_description("lru iter test case 19\n"); + _lru_run_test(19); + return; +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test(lru_iter_next_test00), + cmocka_unit_test(lru_iter_next_test01), + cmocka_unit_test(lru_iter_next_test02), + cmocka_unit_test(lru_iter_next_test03), + cmocka_unit_test(lru_iter_next_test04), + cmocka_unit_test(lru_iter_next_test05), + cmocka_unit_test(lru_iter_next_test06), + cmocka_unit_test(lru_iter_next_test07), + cmocka_unit_test(lru_iter_next_test08), + cmocka_unit_test(lru_iter_next_test09), + cmocka_unit_test(lru_iter_next_test10), + cmocka_unit_test(lru_iter_next_test11), + cmocka_unit_test(lru_iter_next_test12), + cmocka_unit_test(lru_iter_next_test13), + cmocka_unit_test(lru_iter_next_test14), + cmocka_unit_test(lru_iter_next_test15), + cmocka_unit_test(lru_iter_next_test16), + cmocka_unit_test(lru_iter_next_test17), + cmocka_unit_test(lru_iter_next_test18), + cmocka_unit_test(lru_iter_next_test19) + }; + + print_message("Unit test for lru_iter_next\n"); + + write_test_case_description(); + + return cmocka_run_group_tests(tests, NULL, NULL); +}