imc_extension.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdint.h>
  4. #include <math.h>
  5. #include "ImC/imc_kernel.h"
  6. #include "ImC/imc_extension.h"
  7. #include "ImC/imc_api.h"
  8. extern ADC_HandleTypeDef ADC_HANDLER_SBC;
  9. float loop_pass_estimation[imcMAX_LOOP_IDS];
  10. int imc_is_passing_loops_backup IMC_KERNEL_NVM;
  11. int imc_is_passing_loops;
  12. int imc_energy_at_start;
  13. float estimation_backup[2][imcMAX_LOOP_IDS] IMC_KERNEL_NVM;
  14. int imc_energy_estimation_initialized IMC_KERNEL_NVM;
  15. int latest_buffer_index IMC_KERNEL_NVM;
  16. int last_loop_skip_count;
  17. int pass_due_to_low_energy;
  18. #define imcLOOP_OPT_DEBUG_VERBOSE 0
  19. #if(imcPRINT_STATS)
  20. int imc_checkpoint_triggered;
  21. int imc_checkpoint_executed;
  22. int imc_checkpoint_triggered_backup[2] IMC_KERNEL_NVM;
  23. int imc_checkpoint_executed_backup[2] IMC_KERNEL_NVM;
  24. int stat_buffer_index IMC_KERNEL_NVM;
  25. int first_checkpoint IMC_KERNEL_NVM;
  26. int no_forward_progress;
  27. int imc_no_forward_progress_backup[2] IMC_KERNEL_NVM;
  28. void imc_recover_stats() {
  29. imc_checkpoint_triggered = imc_checkpoint_triggered_backup[stat_buffer_index];
  30. imc_checkpoint_executed = imc_checkpoint_executed_backup[stat_buffer_index];
  31. no_forward_progress = imc_no_forward_progress_backup[stat_buffer_index];
  32. }
  33. void imc_backup_stats() {
  34. int nextBufferIndex = stat_buffer_index == 0 ? 1: 0;
  35. imc_checkpoint_triggered_backup[nextBufferIndex] = imc_checkpoint_triggered;
  36. imc_checkpoint_executed_backup[nextBufferIndex] = imc_checkpoint_executed;
  37. imc_no_forward_progress_backup[nextBufferIndex] = no_forward_progress;
  38. stat_buffer_index = nextBufferIndex;
  39. }
  40. #endif
  41. #if (imcPRINT_LATENCY_OVERHEAD)
  42. unsigned int imc_ticks_init;
  43. unsigned int imc_ticks_getCSC;
  44. unsigned int imc_ticks_adjust;
  45. unsigned int imc_ticks_total;
  46. int imc_latency_overhead_buffer_index IMC_KERNEL_NVM;
  47. unsigned int imc_last_tick;
  48. unsigned int imc_ticks_init_backup[2] IMC_KERNEL_NVM;
  49. unsigned int imc_ticks_getCSC_backup[2] IMC_KERNEL_NVM;
  50. unsigned int imc_ticks_adjust_backup[2] IMC_KERNEL_NVM;
  51. unsigned int imc_ticks_total_backup[2] IMC_KERNEL_NVM;
  52. void imc_recover_latency_overhead() {
  53. int index = imc_latency_overhead_buffer_index;
  54. imc_ticks_init = imc_ticks_init_backup[index];
  55. imc_ticks_getCSC = imc_ticks_getCSC_backup[index];
  56. imc_ticks_adjust = imc_ticks_adjust_backup[index];
  57. imc_ticks_total = imc_ticks_total_backup[index];
  58. }
  59. void imc_backup_latency_overhead() {
  60. unsigned int tick = DWT->CYCCNT;
  61. imc_ticks_total += tick - imc_last_tick;
  62. imc_last_tick = tick;
  63. int next_buffer_index = imc_latency_overhead_buffer_index == 0 ? 1 : 0;
  64. imc_ticks_init_backup[next_buffer_index] = imc_ticks_init;
  65. imc_ticks_getCSC_backup[next_buffer_index] = imc_ticks_getCSC;
  66. imc_ticks_adjust_backup[next_buffer_index] = imc_ticks_adjust;
  67. imc_ticks_total_backup[next_buffer_index] = imc_ticks_total;
  68. imc_latency_overhead_buffer_index = next_buffer_index;
  69. }
  70. #endif
  71. void imc_recover_estimations()
  72. {
  73. #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
  74. portDISABLE_INTERRUPTS();
  75. printf("(DEBUG) recover estimation table from buffer %d\r\n", latest_buffer_index);
  76. portENABLE_INTERRUPTS();
  77. #endif
  78. memcpy(loop_pass_estimation, estimation_backup[latest_buffer_index], sizeof(float) * imcMAX_LOOP_IDS);
  79. __DSB();
  80. }
  81. void imc_backup_estimations() {
  82. int nextBufferIndex = latest_buffer_index == 0 ? 1 : 0;
  83. #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
  84. portDISABLE_INTERRUPTS();
  85. printf("(DEBUG) backup estimation table to buffer %d\r\n", nextBufferIndex);
  86. portENABLE_INTERRUPTS();
  87. #endif
  88. memcpy(estimation_backup[nextBufferIndex], loop_pass_estimation, sizeof(float) * imcMAX_LOOP_IDS);
  89. latest_buffer_index = nextBufferIndex;
  90. __DSB();
  91. }
  92. void imc_print_estimations() {
  93. portDISABLE_INTERRUPTS();
  94. for(int i=0; i<imcMAX_LOOP_IDS; i++) {
  95. printf("(DEBUG) loop_#%d: %f\r\n", i, loop_pass_estimation[i]);
  96. }
  97. portENABLE_INTERRUPTS();
  98. }
  99. void imc_init_energy_estimation() {
  100. #if (imcPRINT_LATENCY_OVERHEAD)
  101. unsigned int start_tick = DWT->CYCCNT;
  102. #endif
  103. if(!imc_energy_estimation_initialized) {
  104. #if(imcLOOP_OPT_DEBUG)
  105. portDISABLE_INTERRUPTS();
  106. printf("(DEBUG) initialize estimation table\r\n");
  107. portENABLE_INTERRUPTS();
  108. #endif
  109. for(int i=0; i<imcMAX_LOOP_IDS; i++) {
  110. loop_pass_estimation[i] = 3;
  111. }
  112. latest_buffer_index = 0;
  113. #if(imcPRINT_STATS)
  114. stat_buffer_index = 0;
  115. #endif
  116. imc_backup_estimations();
  117. } else {
  118. imc_recover_estimations();
  119. }
  120. #if (imcPRINT_LATENCY_OVERHEAD)
  121. unsigned int end_tick = DWT->CYCCNT;
  122. imc_ticks_init += end_tick - start_tick;
  123. #endif
  124. if(imc_energy_estimation_initialized && imc_is_passing_loops_backup != -1) {
  125. int loop_id = imc_is_passing_loops_backup;
  126. float new_estimation = loop_pass_estimation[loop_id] / 3;
  127. // int new_estimation = loop_pass_estimation[loop_id];
  128. // if(new_estimation >= 20) new_estimation /= 10;
  129. // else if(new_estimation < 20 && new_estimation > 2) new_estimation = 2;
  130. // else if(new_estimation == 2) new_estimation = 1;
  131. // else new_estimation = 0;
  132. loop_pass_estimation[loop_id] = new_estimation;
  133. estimation_backup[latest_buffer_index][loop_id] = new_estimation;
  134. #if (imcLOOP_OPT_DEBUG)
  135. portDISABLE_INTERRUPTS();
  136. printf("(DEBUG) (recovery) estimation for loop %d is updated to %f\r\n", loop_id, loop_pass_estimation[loop_id]);
  137. portENABLE_INTERRUPTS();
  138. #endif
  139. }
  140. imc_energy_estimation_initialized = 1;
  141. imc_is_passing_loops_backup = -1;
  142. imc_is_passing_loops = -1;
  143. __DSB();
  144. }
  145. int get_current_energy() {
  146. int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
  147. int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
  148. return energy;
  149. }
  150. void update_estimation(int loop_id, int counter, int current_energy, int energy_at_start) {
  151. float current_estimation = (float)loop_pass_estimation[loop_id];
  152. if(current_estimation > 1e6) return;
  153. const float error_margin = imcENERGY_TOTAL * 0.03;
  154. // const float error_margin = imcENERGY_TOTAL * 0;
  155. float max_consumed = energy_at_start + error_margin - (current_energy - error_margin);
  156. float min_consumed = energy_at_start - error_margin - (current_energy + error_margin);
  157. // if(max_consumed <= 0) max_consumed = 1e-3;
  158. // if(min_consumed <= 0) {
  159. // min_consumed = 1e-3;
  160. // }
  161. if(max_consumed <= 0) max_consumed = 1e-3;
  162. if(min_consumed <= 0) {
  163. min_consumed = 1;
  164. }
  165. float measured_min = ((float)(imcENERGY_TOTAL)) / max_consumed * counter;
  166. // measured_min *= 2.5;
  167. float measured_max = ((float)(imcENERGY_TOTAL)) / min_consumed * counter;
  168. // measured_max *= 2;
  169. // float measured_iterations = ((float)(imcENERGY_TOTAL)) / energy_consumed * counter;
  170. // float variance_margin = 1;
  171. // float outlier_factor = 5;
  172. // int too_large_measured = measured_iterations > outlier_factor * current_estimation;
  173. // int too_small_measured = outlier_factor * measured_iterations < current_estimation;
  174. // printf("(DEBUG) lood_id:%d, counter:%d, consumed: %d, measured: %f, current: %f\r\n", loop_id, counter, energy_consumed, measured_iterations, current_estimation);
  175. // if(too_large_measured || too_small_measured) return;
  176. float new_estimation;
  177. if(measured_max < current_estimation) {
  178. float factor = measured_max / current_estimation;
  179. float factor_max = 0.25;
  180. factor = factor < factor_max ? factor_max : factor;
  181. new_estimation = current_estimation * factor;
  182. loop_pass_estimation[loop_id] = new_estimation;
  183. } else if (measured_min > current_estimation) {
  184. float factor = measured_min / current_estimation;
  185. float factor_max = 3;
  186. factor = factor > factor_max ? factor_max : factor;
  187. new_estimation = current_estimation * factor;
  188. loop_pass_estimation[loop_id] = new_estimation;
  189. }
  190. else {
  191. #if(imcLOOP_OPT_DEBUG)
  192. portDISABLE_INTERRUPTS();
  193. printf("(DEBUG) Estimation not updated; loop_id:%d, counter:%d, measured_min: %f, measured_max: %f, current_estimation: %f\r\n",
  194. loop_id, counter, measured_min, measured_max, current_estimation);
  195. portENABLE_INTERRUPTS();
  196. #endif
  197. return;
  198. }
  199. const int max_estimation = 1000000;
  200. if(new_estimation > max_estimation) {
  201. new_estimation = max_estimation;
  202. loop_pass_estimation[loop_id] = max_estimation;
  203. }
  204. #if(imcLOOP_OPT_DEBUG)
  205. portDISABLE_INTERRUPTS();
  206. printf("(DEBUG) estimation for loop %d is updated to %f\r\n", loop_id, new_estimation);
  207. portENABLE_INTERRUPTS();
  208. #endif
  209. imc_backup_estimations();
  210. }
  211. void __imc_unflag_loop_skipping(int loop_id, int counter)
  212. {
  213. if(loop_id != imc_is_passing_loops) return;
  214. #if (imcPRINT_LATENCY_OVERHEAD)
  215. unsigned int start_tick = DWT->CYCCNT;
  216. #endif
  217. int energy = get_current_energy();
  218. int energy_consumed = imc_energy_at_start - energy;
  219. // printf("(DEBUG) energy consumed: %d\r\n", energy_consumed);
  220. update_estimation(loop_id, counter, energy, imc_energy_at_start);
  221. // float measured_iterations = ((float)(imcENERGY_TOTAL)) / energy_consumed * counter;
  222. // float current_estimation = (float)loop_pass_estimation[loop_id];
  223. // printf("(DEBUG) loop_id:%d, counter:%d, measured: %f, estimation: %f\r\n", loop_id, counter, measured_iterations, current_estimation);
  224. imc_is_passing_loops_backup = -1;
  225. imc_is_passing_loops = -1;
  226. __DSB();
  227. #if (imcPRINT_LATENCY_OVERHEAD)
  228. unsigned int end_tick = DWT->CYCCNT;
  229. imc_ticks_adjust += end_tick - start_tick;
  230. #endif
  231. }
  232. void __imc_finish_loop_skipping() {
  233. int loop_id = imc_is_passing_loops;
  234. #if (imcPRINT_LATENCY_OVERHEAD)
  235. unsigned int start_tick = DWT->CYCCNT;
  236. #endif
  237. if(loop_id == 0) {
  238. printf("(DEBUG) imc_is_passing_loop is 0\r\n");
  239. while(1) { __ASM(" nop"); }
  240. }
  241. if(loop_id > 0) {
  242. // int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
  243. // int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
  244. #if(imcLOOP_OPT_DEBUG)
  245. portDISABLE_INTERRUPTS();
  246. // printf("(DEBUG) loop %d is not perfectly skipped\r\n", loop_id);
  247. portENABLE_INTERRUPTS();
  248. #endif
  249. int energy = get_current_energy();
  250. int energy_consumed = imc_energy_at_start - energy;
  251. int last_skip_is_zero = last_loop_skip_count == 0;
  252. if(!last_skip_is_zero) {
  253. update_estimation(loop_id, last_loop_skip_count, energy, imc_energy_at_start);
  254. }
  255. }
  256. imc_is_passing_loops_backup = -1;
  257. imc_is_passing_loops = -1;
  258. __DSB();
  259. #if (imcPRINT_LATENCY_OVERHEAD)
  260. unsigned int end_tick = DWT->CYCCNT;
  261. imc_ticks_adjust += end_tick - start_tick;
  262. #endif
  263. }
  264. int __imc_get_loop_pass_count(int loop_id) {
  265. #if(imcENABLE_STATIC_LOOP_PASS_COUNT)
  266. return imcLOOP_PASS_COUNT;
  267. #elif(imcENABLE_ADAPTIVE_LOOP_PASS_COUNT)
  268. if(imc_is_passing_loops != -1) return INT32_MAX;
  269. #if (imcPRINT_LATENCY_OVERHEAD)
  270. unsigned int start_tick = DWT->CYCCNT;
  271. #endif
  272. int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
  273. int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
  274. int ratio = energy * 100 / imcENERGY_TOTAL;
  275. imc_is_passing_loops = loop_id;
  276. imc_is_passing_loops_backup = loop_id;
  277. __DSB();
  278. imc_energy_at_start = energy;
  279. #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
  280. portDISABLE_INTERRUPTS();
  281. printf("(DEBUG) loopId: %d, ratio: %d\r\n", loop_id, ratio);
  282. portENABLE_INTERRUPTS();
  283. #endif
  284. float current_estimation = loop_pass_estimation[loop_id];
  285. if(ratio > 100) {
  286. last_loop_skip_count = current_estimation;
  287. }
  288. else if(ratio < 5) {
  289. last_loop_skip_count = 0;
  290. imc_is_passing_loops = -1;
  291. imc_is_passing_loops_backup = -1;
  292. // imc_sbc_power_off();
  293. #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
  294. portDISABLE_INTERRUPTS();
  295. printf("(DEBUG) ratio: %d\r\n", ratio);
  296. portENABLE_INTERRUPTS();
  297. #endif
  298. // while(1) { __ASM(" nop"); }
  299. // printf("__imc_get_loop_pass_count(%d) called; %d returned\r\n", loop_id, last_loop_skip_count);
  300. }
  301. else {
  302. double r = (double)(ratio) / 100.0;
  303. double target_skip_count = current_estimation * r;
  304. #if(imcLOOP_OPT_DEBUG && imcLOOP_OPT_DEBUG_VERBOSE)
  305. portDISABLE_INTERRUPTS();
  306. printf("(DEBUG) loop_id:%d, current estimation: %f, target_skip_count: %f, r: %f\r\n", loop_id, current_estimation, target_skip_count, r);
  307. portENABLE_INTERRUPTS();
  308. #endif
  309. const int max_skip_count = 10000;
  310. // if(target_skip_count > max_skip_count) {
  311. // last_loop_skip_count = max_skip_count;
  312. // } else {
  313. // last_loop_skip_count = (int)target_skip_count;
  314. // }
  315. if (isnan(target_skip_count) || target_skip_count < 1.0) {
  316. last_loop_skip_count = 0;
  317. } else if (target_skip_count > max_skip_count) {
  318. last_loop_skip_count = max_skip_count;
  319. } else {
  320. last_loop_skip_count = (int)target_skip_count;
  321. }
  322. // last_loop_skip_count = loop_pass_estimation[loop_id] * ((double)(ratio) / 100.0);
  323. }
  324. // printf("loopId: %d, volt: %d, energy: %d, total: %d, ratio: %d, est:%f, count:%d\r\n", loop_id, volt, energy, imcENERGY_TOTAL, ratio, current_estimation, last_loop_skip_count);
  325. #if (imcPRINT_LATENCY_OVERHEAD)
  326. unsigned int end_tick = DWT->CYCCNT;
  327. imc_ticks_getCSC += end_tick - start_tick;
  328. #endif
  329. return last_loop_skip_count;
  330. #else
  331. return 0;
  332. #endif
  333. }
  334. void ckptTask() {
  335. while(1) {
  336. int volt = measure_voltage(ADC_HANDLER_SBC, 0);
  337. // __asm(" svc 7");
  338. if(volt < 3660) {
  339. HAL_GPIO_WritePin(GPIOF, GPIO_PIN_11, GPIO_PIN_SET);
  340. __asm(" svc 7");
  341. imc_sbc_power_off();
  342. while(1) __asm(" nop");
  343. }
  344. // printf("volt: %d\r\n", volt);
  345. const TickType_t xDelay = 25 / portTICK_PERIOD_MS;
  346. osDelay(xDelay);
  347. }
  348. }