perf.c 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. //
  2. // This module allows performance monitoring by looking at
  3. // the PC at regular intervals and building a histogram
  4. //
  5. // perf.start(start, end, nbins[, pc offset on stack])
  6. // perf.stop() -> total sample, samples outside range, table { addr -> count , .. }
  7. #include "ets_sys.h"
  8. #include "os_type.h"
  9. #include "osapi.h"
  10. #include <stdlib.h>
  11. #include "module.h"
  12. #include "lauxlib.h"
  13. #include "platform.h"
  14. #include "hw_timer.h"
  15. #include "cpu_esp8266.h"
  16. typedef struct {
  17. int ref;
  18. uint32_t start;
  19. uint32_t bucket_shift;
  20. uint32_t bucket_count;
  21. uint32_t total_samples;
  22. uint32_t outside_samples;
  23. uint32_t bucket[1];
  24. } DATA;
  25. static DATA *data;
  26. extern char _flash_used_end[];
  27. #define TIMER_OWNER ((os_param_t) 'p')
  28. static void ICACHE_RAM_ATTR hw_timer_cb(os_param_t p)
  29. {
  30. (void) p;
  31. uint32_t stackaddr;
  32. if (data) {
  33. uint32_t pc;
  34. asm (
  35. "rsr %0, EPC1;" /* read out the EPC */
  36. :"=r"(pc)
  37. );
  38. uint32_t bucket_number = (pc - data->start) >> data->bucket_shift;
  39. if (bucket_number < data->bucket_count) {
  40. data->bucket[bucket_number]++;
  41. } else {
  42. data->outside_samples++;
  43. }
  44. data->total_samples++;
  45. }
  46. }
  47. static int perf_start(lua_State *L)
  48. {
  49. uint32_t start = luaL_optinteger(L, 1, 0x40000000);
  50. uint32_t end = luaL_optinteger(L, 2, (uint32_t) _flash_used_end);
  51. uint32_t bins = luaL_optinteger(L, 3, 1024);
  52. if (end <= start) {
  53. luaL_error(L, "end must be larger than start");
  54. }
  55. uint32_t binsize = (end - start + bins - 1) / bins;
  56. // Round up to a power of two
  57. int shift;
  58. binsize = binsize - 1;
  59. for (shift = 0; binsize > 0; shift++) {
  60. binsize >>= 1;
  61. }
  62. bins = (end - start + (1 << shift) - 1) / (1 << shift);
  63. size_t data_size = sizeof(DATA) + bins * sizeof(uint32_t);
  64. DATA *d = (DATA *) lua_newuserdata(L, data_size);
  65. memset(d, 0, data_size);
  66. d->ref = luaL_ref(L, LUA_REGISTRYINDEX);
  67. d->start = start;
  68. d->bucket_shift = shift;
  69. d->bucket_count = bins;
  70. if (data) {
  71. luaL_unref(L, LUA_REGISTRYINDEX, data->ref);
  72. }
  73. data = d;
  74. // Start the timer
  75. if (!platform_hw_timer_init(TIMER_OWNER, FRC1_SOURCE, TRUE)) {
  76. // Failed to init the timer
  77. data = NULL;
  78. luaL_unref(L, LUA_REGISTRYINDEX, d->ref);
  79. luaL_error(L, "Unable to initialize timer");
  80. }
  81. platform_hw_timer_set_func(TIMER_OWNER, hw_timer_cb, 0);
  82. platform_hw_timer_arm_us(TIMER_OWNER, 50);
  83. return 0;
  84. }
  85. static int perf_stop(lua_State *L)
  86. {
  87. if (!data) {
  88. return 0;
  89. }
  90. // stop the timer
  91. platform_hw_timer_close(TIMER_OWNER);
  92. DATA *d = data;
  93. data = NULL;
  94. lua_pushunsigned(L, d->total_samples);
  95. lua_pushunsigned(L, d->outside_samples);
  96. lua_newtable(L);
  97. int i;
  98. uint32_t addr = d->start;
  99. for (i = 0; i < d->bucket_count; i++, addr += (1 << d->bucket_shift)) {
  100. if (d->bucket[i]) {
  101. lua_pushunsigned(L, addr);
  102. lua_pushunsigned(L, d->bucket[i]);
  103. lua_settable(L, -3);
  104. }
  105. }
  106. lua_pushunsigned(L, 1 << d->bucket_shift);
  107. luaL_unref(L, LUA_REGISTRYINDEX, d->ref);
  108. return 4;
  109. }
  110. LROT_BEGIN(perf, NULL, 0)
  111. LROT_FUNCENTRY( start, perf_start )
  112. LROT_FUNCENTRY( stop, perf_stop )
  113. LROT_END(perf, NULL, 0)
  114. NODEMCU_MODULE(PERF, "perf", perf, NULL);