// SPDX-License-Identifier: MPL-2.0
#include "kernel/tests/test_pez.h"
#include "kernel/tests/test_utils.h"
#include "kernel/tests/payloads/test_pez_payload.h"
#include "kernel/log.h"
#include "memory/page.h"
#include "std/mem.h"
static sh_uint64 iter_num=4000;
__attribute__((section(".bss")))
static sh_page_PHYSICAL_ADDRESS address_list[2000];
SH_STATUS sh_test_pez_benchmark_physical(sh_pez_PHYSICAL_PLANE *phys_plane) {
  if (phys_plane==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,SH_TEST_PEZ_TOTAL_TSC_TIME_COUNT*sizeof(sh_tsc_TSC_VALUE));
  sh_mem_set_8((sh_uint8*)address_list,0x00,sizeof(address_list));
  sh_log_test("Benchmarking Pez physical plane...");
  sh_tsc_TSC_VALUE start=0;
  sh_tsc_TSC_VALUE end=0;
  sh_uint16 alloc_single_count=0;
  sh_uint16 unalloc_single_count=1000;
  sh_uint16 alloc_multiple_count=2000;
  sh_uint16 unalloc_multiple_count=3000;
  SH_STATUS status;
  for (sh_iter64 i=0;i<iter_num;i++) {
    sh_uint64 alloc_num=test_pez_physical_alloc[i];
    sh_uint64 alloc_size=test_pez_physical_size[alloc_num];
    if (address_list[alloc_num]==0) {
      sh_page_PHYSICAL_ADDRESS address;
      start=sh_tsc_get_kernel_current_tsc();
      status=sh_pez_alloc_physical_pages(phys_plane,(sh_uint32)alloc_size,&address);
      end=sh_tsc_get_kernel_current_tsc();
      if (alloc_size==1) {
        tsc_value[alloc_single_count]=end-start;
        alloc_single_count++;
      } else {
        tsc_value[alloc_multiple_count]=end-start;
        alloc_multiple_count++;
      }
      if (status!=SH_STATUS_SUCCESS) {
        sh_log_error("Test failed for allocation on Pez physical plane. 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);
        sh_log_ferror(SH_LOG_SOURCE_TEST,"Size: %8u\n",alloc_size);
        sh_log_ferror(SH_LOG_SOURCE_TEST,"Alloc Num: %8u\n",alloc_num);
        sh_pez_debug_physical(phys_plane);
        return SH_STATUS_TEST_FAILED;
      } else {
        address_list[alloc_num]=address;
      }
    } else {
      start=sh_tsc_get_kernel_current_tsc();
      status=sh_pez_free_physical_pages(phys_plane,&address_list[alloc_num],(sh_uint32)alloc_size);
      end=sh_tsc_get_kernel_current_tsc();
      if (alloc_size==1) {
        tsc_value[unalloc_single_count]=end-start;
        unalloc_single_count++;
      } else {
        tsc_value[unalloc_multiple_count]=end-start;
        unalloc_multiple_count++;
      }
      if (status!=SH_STATUS_SUCCESS) {
        sh_log_error("Test failed for free on Pez physical plane. 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);
        sh_log_ferror(SH_LOG_SOURCE_TEST,"Size: %8u\n",alloc_size);
        sh_log_ferror(SH_LOG_SOURCE_TEST,"Alloc Num: %8u\n",alloc_num);
        sh_pez_debug_physical(phys_plane);
        return SH_STATUS_TEST_FAILED;
      }
    }
  }
  sh_test_compute_print_stats("allocations for single page",tsc_value,alloc_single_count,SH_FALSE);
  sh_test_compute_print_stats("free for single page",tsc_value+1000,unalloc_single_count-1000,SH_FALSE);
  sh_test_compute_print_stats("allocations for multiple pages",tsc_value+2000,alloc_multiple_count-2000,SH_FALSE);
  sh_test_compute_print_stats("free for multiple pages",tsc_value+3000,unalloc_multiple_count-3000,SH_FALSE);
  return SH_STATUS_SUCCESS;
}
