// SPDX-License-Identifier: MPL-2.0
#include "kernel/tests/test_radix.h"
#include "kernel/tests/test_utils.h"
#include "kernel/tests/payloads/test_radix_payload.h"
#include "kernel/log.h"
#include "std/mem.h"
static sh_uint64 iter_num=10000;
void sh_test_radix_load_iterations_count(sh_uint64 iterations_num) {
  iter_num=iterations_num;
  return;
}
SH_STATUS sh_test_radix_benchmark(struct sh_slab_radix_node_SLAB_ALLOCATOR *alloc,sh_page_PAGE_TABLE_POOL *ptp) {
  if (alloc==SH_NULLPTR || ptp==SH_NULLPTR) return SH_STATUS_INVALID_PARAMETER;
  sh_tsc_TSC_VALUE *tsc_value=sh_test_get_tsc_values_buffer_ptr();
  sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
  sh_log_test("Benchmarking radix trees subsystem...");
  sh_radix_TREE tree;
  SH_STATUS status=sh_radix_tree_init(alloc,ptp,&tree,16);
  if (status!=SH_STATUS_SUCCESS) {
    sh_log_error("Test failed for initialization of a 16-deep radix tree. See detail below:",SH_LOG_SOURCE_TEST);
    sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
    return SH_STATUS_TEST_FAILED;
  }
  sh_tsc_TSC_VALUE start=0;
  sh_tsc_TSC_VALUE end=0;
  for (sh_iter64 i=0;i<iter_num;i++) {
    start=sh_tsc_get_kernel_current_tsc();
    status=sh_radix_tree_insert_value(alloc,ptp,&tree,test_keys[i],test_values[i]);
    end=sh_tsc_get_kernel_current_tsc();
    tsc_value[i]=end-start;
    if (status!=SH_STATUS_SUCCESS) {
      sh_log_error("Test failed for insertion into radix tree. See detail below:",SH_LOG_SOURCE_TEST);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
      return SH_STATUS_TEST_FAILED;
    }
  }
  sh_test_compute_print_stats("insertions into radix trees",tsc_value,iter_num,SH_FALSE);
  sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
  for (sh_iter64 i=0;i<iter_num;i++) {
    sh_page_VIRTUAL_ADDRESS temp;
    start=sh_tsc_get_kernel_current_tsc();
    status=sh_radix_tree_get_value(&tree,test_keys[i],&temp);
    end=sh_tsc_get_kernel_current_tsc();
    tsc_value[i]=end-start;
    if (status!=SH_STATUS_SUCCESS) {
      sh_log_error("Test failed at status level for reading into radix tree. See detail below:",SH_LOG_SOURCE_TEST);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
      return SH_STATUS_TEST_FAILED;
    }
    if (temp!=test_values[i]) {
      sh_log_error("Test failed at value level for reading into radix tree. See detail below:",SH_LOG_SOURCE_TEST);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Key: %x\n",test_keys[i]);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Expected value: %x\n",test_values[i]);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Obtained value: %x\n",temp);
      return SH_STATUS_TEST_FAILED;
    }
  }
  sh_test_compute_print_stats("reading into radix trees",tsc_value,iter_num,SH_FALSE);
  sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
  for (sh_iter64 i=0;i<iter_num;i++) {
    sh_page_VIRTUAL_ADDRESS temp;
    start=sh_tsc_get_kernel_current_tsc();
    status=sh_radix_tree_search_smallest_min_bound(alloc,&tree,test_search[i],&temp);
    end=sh_tsc_get_kernel_current_tsc();
    tsc_value[i]=end-start;
    if (status!=SH_STATUS_SUCCESS && status!=SH_STATUS_NOT_FOUND) {
      sh_log_error("Test failed for searching value with lower bound key into radix tree. See detail below:",SH_LOG_SOURCE_TEST);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
      return SH_STATUS_TEST_FAILED;
    }
  }
  sh_test_compute_print_stats("searching value with lower bound key",tsc_value,iter_num,SH_FALSE);
  sh_mem_set_8((sh_uint8*)tsc_value,0x00,iter_num);
  for (sh_iter64 i=0;i<iter_num;i++) {
    start=sh_tsc_get_kernel_current_tsc();
    status=sh_radix_tree_delete_value(alloc,&tree,test_keys[i]);
    end=sh_tsc_get_kernel_current_tsc();
    tsc_value[i]=end-start;
    if (status!=SH_STATUS_SUCCESS) {
      sh_log_error("Test failed for deleting value from radix tree. See detail below:",SH_LOG_SOURCE_TEST);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Error code: %8s\n",status);
      sh_log_ferror(SH_LOG_SOURCE_TEST,"Index: %8u\n",i);
      return SH_STATUS_TEST_FAILED;
    }
  }
  sh_test_compute_print_stats("deleting values",tsc_value,iter_num,SH_FALSE);
  return SH_STATUS_SUCCESS;
}
