nmsis_bench.h 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. * Copyright (c) 2019 Nuclei Limited. All rights reserved.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the License); you may
  7. * not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an AS IS BASIS, WITHOUT
  14. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. #ifndef __NMSIS_BENCH__
  19. #define __NMSIS_BENCH__
  20. /*!
  21. * @file nmsis_bench.h
  22. * @brief benchmark and helper related API for Nuclei N/NX Core
  23. */
  24. #ifdef __cplusplus
  25. extern "C" {
  26. #endif
  27. #include "core_feature_base.h"
  28. #include <stdio.h>
  29. /**
  30. * \defgroup NMSIS_Core_Bench_Helpers NMSIS Bench and Test Related Helper Functions
  31. * \ingroup NMSIS_Core
  32. * \brief Functions that used to do benchmark and test suite.
  33. * \details
  34. *
  35. * NMSIS benchmark and test related helper functions are provided to help do benchmark
  36. * and test case pass/fail assertion.
  37. *
  38. * If you want to do calculate cpu cycle cost of a process, you can use BENCH_xxx macros
  39. * defined in this.
  40. *
  41. * In a single c source code file, you should include `nmsis_bench.h`, and then you should place `BENCH_DECLARE_VAR();`
  42. * before call other BENCH_xxx macros. If you want to start to do benchmark, you should only call `BENCH_INIT();`
  43. * once in your source code, and then place `BENCH_START(proc_name);` and `BENCH_END(proc_name)` before
  44. * and after the process you want to measure. You can refer to `<nuclei-sdk>/application/baremetal/demo_dsp`
  45. * for how to use it.
  46. *
  47. * If you want to disable the benchmark calculation, you can place `#define DISABLE_NMSIS_BENCH`
  48. * before include `nmsis_bench.h`
  49. *
  50. * If in your c test source code, you can add `NMSIS_TEST_PASS();` and `NMSIS_TEST_FAIL();` to mark c test
  51. * is pass or fail.
  52. *
  53. * @{
  54. */
  55. /**
  56. * \brief Prepare benchmark environment
  57. * \details
  58. * Prepare benchmark required environment, such as turn on necessary units
  59. * like vpu, cycle, instret counters, hpm counters
  60. */
  61. __STATIC_FORCEINLINE void __prepare_bench_env(void)
  62. {
  63. #ifdef __riscv_vector
  64. __RV_CSR_SET(CSR_MSTATUS, MSTATUS_VS);
  65. #endif
  66. __enable_all_counter();
  67. }
  68. #ifndef READ_CYCLE
  69. /** Read run cycle of cpu */
  70. #define READ_CYCLE __get_rv_cycle
  71. #endif
  72. #ifndef DISABLE_NMSIS_BENCH
  73. /** Declare benchmark required variables, need to be placed above all BENCH_xxx macros in each c source code if BENCH_xxx used */
  74. #define BENCH_DECLARE_VAR() static volatile uint32_t _bc_sttcyc, _bc_endcyc, _bc_usecyc, _bc_sumcyc, _bc_lpcnt, _bc_ercd;
  75. /** Initialize benchmark environment, need to called in before other BENCH_xxx macros are called */
  76. #define BENCH_INIT() printf("Benchmark initialized\n"); \
  77. __prepare_bench_env(); \
  78. _bc_ercd = 0; _bc_sumcyc = 0;
  79. /** Reset benchmark sum cycle and use cycle for proc */
  80. #define BENCH_RESET(proc) _bc_sumcyc = 0; _bc_usecyc = 0; _bc_lpcnt = 0; _bc_ercd = 0;
  81. /** Start to do benchmark for proc, and record start cycle, and reset error code */
  82. #define BENCH_START(proc) _bc_ercd = 0; \
  83. _bc_sttcyc = READ_CYCLE();
  84. /** Sample a benchmark for proc, and record this start -> sample cost cycle, and accumulate it to sum cycle */
  85. #define BENCH_SAMPLE(proc) _bc_endcyc = READ_CYCLE(); \
  86. _bc_usecyc = _bc_endcyc - _bc_sttcyc; \
  87. _bc_sumcyc += _bc_usecyc; _bc_lpcnt += 1;
  88. /** Mark end of benchmark for proc, and calc used cycle, and print it */
  89. #define BENCH_END(proc) BENCH_SAMPLE(proc); \
  90. printf("CSV, %s, %lu\n", #proc, (unsigned long)_bc_usecyc);
  91. /** Mark stop of benchmark, start -> sample -> sample -> stop, and print the sum cycle of a proc */
  92. #define BENCH_STOP(proc) printf("CSV, %s, %lu\n", #proc, (unsigned long)_bc_sumcyc);
  93. /** Show statistics of benchmark, format: STAT, proc, loopcnt, sumcyc */
  94. #define BENCH_STAT(proc) printf("STAT, %s, %lu, %lu\n", #proc, (unsigned long)_bc_lpcnt, (unsigned long)_bc_sumcyc);
  95. /** Get benchmark use cycle */
  96. #define BENCH_GET_USECYC() (_bc_usecyc)
  97. /** Get benchmark sum cycle */
  98. #define BENCH_GET_SUMCYC() (_bc_sumcyc)
  99. /** Get benchmark loop count */
  100. #define BENCH_GET_LPCNT() (_bc_lpcnt)
  101. /** Mark benchmark for proc is errored */
  102. #define BENCH_ERROR(proc) _bc_ercd = 1;
  103. /** Show the status of the benchmark */
  104. #define BENCH_STATUS(proc) if (_bc_ercd) { \
  105. printf("ERROR, %s\n", #proc); \
  106. } else { \
  107. printf("SUCCESS, %s\n", #proc); \
  108. }
  109. #else
  110. #define BENCH_DECLARE_VAR() static volatile uint32_t _bc_ercd, _bc_lpcnt;
  111. #define BENCH_INIT() _bc_ercd = 0; __prepare_bench_env();
  112. #define BENCH_RESET(proc)
  113. #define BENCH_START(proc) _bc_ercd = 0;
  114. #define BENCH_SAMPLE(proc) _bc_lpcnt += 1;
  115. #define BENCH_END(proc)
  116. #define BENCH_STOP(proc)
  117. #define BENCH_STAT(proc)
  118. #define BENCH_GET_USECYC() (0)
  119. #define BENCH_GET_SUMCYC() (0)
  120. #define BENCH_GET_LPCNT() (_bc_lpcnt)
  121. #define BENCH_ERROR(proc) _bc_ercd = 1;
  122. #define BENCH_STATUS(proc) if (_bc_ercd) { \
  123. printf("ERROR, %s\n", #proc); \
  124. } else { \
  125. printf("SUCCESS, %s\n", #proc); \
  126. }
  127. #endif
  128. // NMSIS Helpers
  129. #ifndef DISABLE_NMSIS_HELPER
  130. /** Mark test or application passed */
  131. #define NMSIS_TEST_PASS() printf("\nNMSIS_TEST_PASS\n");
  132. /** Mark test or application failed */
  133. #define NMSIS_TEST_FAIL() printf("\nNMSIS_TEST_FAIL\n");
  134. #else
  135. #define NMSIS_TEST_PASS()
  136. #define NMSIS_TEST_FAIL()
  137. #endif
  138. /** @} */ /* End of Doxygen Group NMSIS_Core_Bench_Helpers */
  139. #ifdef __cplusplus
  140. }
  141. #endif
  142. #endif /* __NMSIS_BENCH__ */