imc_extension.c 14 KB

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