Переглянути джерело

Implement adaptive strategy with checkpoint support

Youngbin Kim 1 рік тому
батько
коміт
31bb7330a7

+ 1 - 1
.gitignore

@@ -7,5 +7,5 @@
 imc_freertos_app_m33.launch
 build/
 build.sh
-imc/exprs/**/output
+imc/exprs/**/output**
 __pycache__

+ 1 - 1
CMakeLists.txt

@@ -150,7 +150,7 @@ set(FPU "-mfpu=fpv5-sp-d16")
 set(FLOAT-ABI "-mfloat-abi=hard")
 # set(FLOAT-ABI "-mfloat-abi=soft")
 set(MCU "${CPU} -mthumb ${FPU} ${FLOAT-ABI}")
-set(OPT "-O1")
+set(OPT "-O3")
 set(C_FLAGS_NO_ASM )
 set(C_FLAGS_EXTRA "-Wall -Wno-char-subscripts -Wno-unused-function -Wno-unused-variable -Wno-unused-but-set-variable -Wno-format -nostdlib -fdata-sections -ffunction-sections")
 

+ 11 - 1
Core/Inc/ImC/imc_extension.h

@@ -18,7 +18,7 @@
 #endif
 
 #ifndef imcENABLE_ADAPTIVE_LOOP_PASS_COUNT
-    #define imcENABLE_ADAPTIVE_LOOP_PASS_COUNT 0
+    #define imcENABLE_ADAPTIVE_LOOP_PASS_COUNT 1
 #endif
 
 #ifndef imcMAX_LOOP_IDS
@@ -33,6 +33,12 @@
     #define imcBENCH_REPEAT_COUNT 1
 #endif
 
+#ifndef imcPRINT_STATS
+    #define imcPRINT_STATS 0
+#endif
+
+#define IMC_KERNEL_NVM __attribute__((section(".kernel_nvm")))
+
 #define imcCAP_VOL_HIGH 4800
 #define imcCAP_VOL_LOW 3500
 #define imcENERGY_TOTAL (imcCAP_VOL_HIGH*imcCAP_VOL_HIGH - imcCAP_VOL_LOW*imcCAP_VOL_LOW)
@@ -41,7 +47,11 @@ int __imc_get_loop_pass_count(int loop_id);
 void __imc_finish_loop_skipping();
 
 void imc_init_energy_estimation();
+void imc_recover_estimations();
+void imc_backup_estimations();
 
 extern int imc_is_passing_loops;
+extern int imc_checkpoint_triggered;
+extern int imc_checkpoint_executed;
 
 #endif

+ 1 - 1
Core/Inc/ImC/imc_kernel.h

@@ -18,7 +18,7 @@
 #endif
 
 #ifndef imcCHECKPOINT_VOLTAGE
-    #define imcCHECKPOINT_VOLTAGE 3800 //in mV
+    #define imcCHECKPOINT_VOLTAGE 3600 //in mV
 #endif
 
 #define imcSTM32_CUBE_IDE 0

+ 14 - 3
Core/Src/ImC/imc_api.c

@@ -196,7 +196,7 @@ RESET_ERROR:
 
 void imc_sbc_power_off ()
 {
-	printf("[EPS] SBC OFF\r\n");
+	// printf("[EPS] SBC OFF\r\n");
 	HAL_GPIO_WritePin(SBC_POWER_GPIO, SBC_POWER_GPIO_PIN, POWER_OFF_SBC);
 }
 
@@ -262,9 +262,20 @@ int medianCalc(int* input, int arr_size){
 }
 
 // uint16_t MEAS_COEF[2] = {812, 782};	// for EPS CAP ch0 and ch1
-uint16_t MEAS_COEF[2] = {700, 782};	// imc, 10mF
+// uint16_t MEAS_COEF[2] = {700, 782};	// imc, 10mF
+uint16_t MEAS_COEF[2] = {770, 782};	// imc, 4.7mF, voltage divider
 int measure_voltage(ADC_HandleTypeDef hadc, uint8_t ch){
-	int n_evals = 1;
+	int val;
+	// for(int i=0; i<100; i++) { __ASM(" nop"); }
+	// osDelay(1);
+	HAL_ADC_Start(&hadc);
+	// Poll ADC Peripheral & TimeOut = 1mSec
+	HAL_ADC_PollForConversion(&hadc, 1);
+	val = HAL_ADC_GetValue(&hadc);
+	HAL_ADC_Stop(&hadc);
+	return val * MEAS_COEF[ch] / 500;
+
+	int n_evals = 5;
 	int res_value[n_evals];
 
 /* UCR ref.

+ 125 - 23
Core/Src/ImC/imc_extension.c

@@ -1,4 +1,5 @@
 #include <stdio.h>
+#include <string.h>
 
 #include "ImC/imc_kernel.h"
 #include "ImC/imc_extension.h"
@@ -6,53 +7,154 @@
 
 extern ADC_HandleTypeDef ADC_HANDLER_SBC;
 
-float loop_energy_estimation[imcMAX_LOOP_IDS] IMC_GLOBAL;
-int imc_is_passing_loops IMC_GLOBAL;
-int imc_energy_estimation_initialized IMC_GLOBAL;
+// int loop_pass_estimation_backup[imcMAX_LOOP_IDS] IMC_KERNEL_NVM;
+int loop_pass_estimation[imcMAX_LOOP_IDS];
+int imc_is_passing_loops_backup IMC_KERNEL_NVM;
+int imc_is_passing_loops;
+int imc_energy_at_start;
+
+int estimation_backup[2][imcMAX_LOOP_IDS] IMC_KERNEL_NVM;
+int imc_energy_estimation_initialized IMC_KERNEL_NVM;
+int latest_buffer_index IMC_KERNEL_NVM;
+int last_loop_skip_count;
+int pass_due_to_low_energy;
+
+#if(imcPRINT_STATS)
+    int imc_checkpoint_triggered IMC_KERNEL_NVM;
+    int imc_checkpoint_executed IMC_KERNEL_NVM;
+#endif
+
+void imc_recover_estimations() {
+    memcpy(loop_pass_estimation, estimation_backup[latest_buffer_index], sizeof(int) * imcMAX_LOOP_IDS);
+    __DSB();
+}
+
+void imc_backup_estimations() {
+    int nextBufferIndex = latest_buffer_index == 0 ? 1 : 0;
+    memcpy(estimation_backup[nextBufferIndex], loop_pass_estimation, sizeof(int) * imcMAX_LOOP_IDS);
+    __DSB();
+    latest_buffer_index = nextBufferIndex;
+    __DSB();
+}
 
 void imc_init_energy_estimation() {
     if(!imc_energy_estimation_initialized) {
         for(int i=0; i<imcMAX_LOOP_IDS; i++) {
-            loop_energy_estimation[i] = 0.1;
+            loop_pass_estimation[i] = 1;
         }
-        imc_energy_estimation_initialized = 1;
+        latest_buffer_index = 0;
+        imc_backup_estimations();
+    } else {
+        imc_recover_estimations();
     }
-    if(imc_is_passing_loops != -1) {
-        float current_estimation = loop_energy_estimation[imc_is_passing_loops];
-        current_estimation *= 2;
-        if(current_estimation > 1) current_estimation = 1;
-        loop_energy_estimation[imc_is_passing_loops] = current_estimation;
-        // printf("estimation for loop%d is updated to %f\r\n", imc_is_passing_loops, current_estimation);
+
+    if(imc_energy_estimation_initialized && imc_is_passing_loops_backup != -1) {
+        int loop_id = imc_is_passing_loops_backup;
+        int new_estimation = loop_pass_estimation[loop_id] / 2;
+        loop_pass_estimation[loop_id] = new_estimation;
+        estimation_backup[latest_buffer_index][loop_id] = new_estimation;
+        // printf("(recovery) estimation for loop %d is updated to %d\r\n", loop_id, loop_pass_estimation[loop_id]);
     }
+    imc_energy_estimation_initialized = 1;
+    imc_is_passing_loops_backup = -1;
+    imc_is_passing_loops = -1;
+    __DSB();
+}
+
+void __imc_unflag_loop_skipping()
+{
+    imc_is_passing_loops_backup = -1;
     imc_is_passing_loops = -1;
+    __DSB();
 }
 
 void __imc_finish_loop_skipping() {
-    if(imc_is_passing_loops >= 0) {
+    int loop_id = imc_is_passing_loops;
+    if(loop_id == 0) {
+        printf("imc_is_passing_loop is 0\r\n");
+        while(1) { __ASM("  nop"); }
+    }
+    if(loop_id > 0) {
         int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
-        float energy_available = (float)(volt * volt - imcCAP_VOL_LOW * imcCAP_VOL_LOW) / imcENERGY_TOTAL;
-        if(energy_available > 0.2) {
-            float current_estimation = loop_energy_estimation[imc_is_passing_loops];
-            current_estimation /= 2;
-            loop_energy_estimation[imc_is_passing_loops] = current_estimation;
-            // printf("estimation for loop%d is updated to %f\r\n", imc_is_passing_loops, current_estimation);
+        // printf("imc_finish_loop_skipping() called with loopId = %d\r\n", loop_id);
+        int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
+        // int ratio = energy * 100 / imcENERGY_TOTAL;
+
+        int energy_consumed = imc_energy_at_start - energy;
+        // int consumed_ratio = energy_consumed * 100 / imcENERGY_TOTAL;
+
+        // if(ratio > 5) {
+        // printf("last loop skip count: %d\r\n", last_loop_skip_count);
+        int last_skip_is_zero = last_loop_skip_count == 0;
+        int energy_per_iteration = energy_consumed / last_loop_skip_count;
+        int underestimated = energy_per_iteration * 10 < energy;
+        // if(energy_consumed / last_loop_skip_count < 2 * energy) {
+        if(!last_skip_is_zero && underestimated) {
+            int current_estimation = loop_pass_estimation[loop_id];
+            // printf("current estimation for loop_%d: %d\r\n", loop_id, current_estimation);
+            double inc_factor = 2;
+            if (current_estimation * inc_factor > (double)INT32_MAX)
+            {
+                // printf("remaining energy: %d\r\n", remaining_energy);
+                current_estimation = INT32_MAX/2-1;
+            }
+            else
+            {
+                current_estimation = (int)(current_estimation * inc_factor);
+                // printf("remaining energy: %d\r\n", remaining_energy);
+            }
+            if (current_estimation < 1) {
+                current_estimation = 1;
+            }
+            loop_pass_estimation[loop_id] = current_estimation;
+            // loop_pass_estimation_backup[loop_id] = current_estimation;
+            portDISABLE_INTERRUPTS();
+            // printf("estimation for loop %d is updated to %d\r\n", loop_id, current_estimation);
+            portENABLE_INTERRUPTS();
         }
     }
+    imc_is_passing_loops_backup = -1;
     imc_is_passing_loops = -1;
+    __DSB();
 }
 
 int __imc_get_loop_pass_count(int loop_id) {
-    // printf("__imc_get_loop_pass_count() called\r\n");
     #if(imcENABLE_STATIC_LOOP_PASS_COUNT)
         return imcLOOP_PASS_COUNT;
     #elif(imcENABLE_ADAPTIVE_LOOP_PASS_COUNT)
         int volt = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
-        float energy_available = (float)(volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW) / imcENERGY_TOTAL;
+        // if(volt < imcCHECKPOINT_VOLTAGE) {
+        //     imcREQUEST_CHECKPOINT();
+        // }
+        int energy = volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW;
+        int ratio = energy * 100 / imcENERGY_TOTAL;
+        // float energy_available = (float)(volt*volt - imcCAP_VOL_LOW*imcCAP_VOL_LOW) / imcENERGY_TOTAL;
         imc_is_passing_loops = loop_id;
+        imc_is_passing_loops_backup = loop_id;
+        __DSB();
+        imc_energy_at_start = energy;
+        // printf("write %d to imc_is_passing_loops\r\n", imc_is_passing_loops);
         // printf("energy available: %f\r\n", energy_available);
-        if(energy_available > 1) return (int)(energy_available / loop_energy_estimation[loop_id]);
-        else if(energy_available < 0) return 0;
-        else return (int)(energy_available / loop_energy_estimation[loop_id]);
+        // if(energy_available > 1) return (int)(energy_available / loop_energy_estimation[loop_id]);
+        // else if(energy_available < 0) return 0;
+        // else return (int)(energy_available / loop_energy_estimation[loop_id]);
+        int current_estimation = loop_pass_estimation[loop_id];
+        if(ratio > 100) {
+            last_loop_skip_count = current_estimation;
+        }
+        else if(ratio < 0) {
+            last_loop_skip_count = 0;
+            // imc_sbc_power_off();
+            // while(1) { __ASM(" nop"); }
+            // printf("__imc_get_loop_pass_count(%d) called; %d returned\r\n", loop_id, last_loop_skip_count);
+        }
+        else {
+            double r = (double)(ratio) / 100.0;
+            last_loop_skip_count = (int)((double)current_estimation * r);
+            // last_loop_skip_count = loop_pass_estimation[loop_id] * ((double)(ratio) / 100.0);
+        }
+        // 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);
+        return last_loop_skip_count;
     #else
         return 0;
     #endif

+ 5 - 0
Core/Src/ImC/imc_kernel.c

@@ -27,6 +27,10 @@ void imcInit()
 }
 
 int needCheckpointExecution() {
+    #if(imcPRINT_STATS)
+        imc_checkpoint_triggered++;
+    #endif
+
     #if(imcUSE_CHECKPOINT_VOLTAGE_CHECK)
         int capacitor_voltage0 = measure_voltage(ADC_HANDLER_SBC, EPS_CAP_ID_SBC);
         return capacitor_voltage0 < imcCHECKPOINT_VOLTAGE;
@@ -43,6 +47,7 @@ int needCheckpointExecution() {
         }
     #endif
 
+
     #if(!imcUSE_CHECKPOINT_VOLTAGE_CHECK && !imcUSE_CHECKPOINT_PASS_COUNTER)
         return 1;
     #endif

+ 11 - 1
Core/Src/benchmarks/benchmark_driver.c

@@ -16,12 +16,22 @@ void vBenchmarkDriver(void *_benchmark)
 
     benchmark();
 
+    #if(imcPRINT_STATS)
+        portDISABLE_INTERRUPTS();
+        printf("(STAT) checkpoint triggered: %d\r\n", imc_checkpoint_triggered);
+        printf("(STAT) checkpoint executed: %d\r\n", imc_checkpoint_executed);
+        portENABLE_INTERRUPTS();
+        imc_checkpoint_triggered = 0;
+        imc_checkpoint_executed = 0;
+    #endif
+
     portDISABLE_INTERRUPTS();
     printf("End benchmark\r\n");
     portENABLE_INTERRUPTS();
+
     imcREQUEST_CHECKPOINT();
     #if (imcBENCH_INFINITE_LOOP)
-    osDelay(10);
+    // osDelay(10);
     }
     #endif
 

+ 97 - 34
Core/Src/main.c

@@ -150,6 +150,8 @@ void taskSnapRunner(void *argument);
 void taskAIRunner(void *argument);
 void taskImcTest(void *argument);
 
+static void MPU_RegionConfig(void);
+
 /* USER CODE BEGIN PFP */
 /* USER CODE END PFP */
 
@@ -241,6 +243,7 @@ int main(void)
   #if (imcUSE_IMC_KERNEL == 1)
     HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
     imcInit();
+    MPU_RegionConfig();
 #endif
 
   // printf("\r\n\r\n\r\n");
@@ -432,8 +435,9 @@ static void MX_ADC1_Init(void)
   */
   sConfig.Channel = ADC_CHANNEL_1;
   sConfig.Rank = ADC_REGULAR_RANK_1;
-  // sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
-  sConfig.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;
+  sConfig.SamplingTime = ADC_SAMPLETIME_2CYCLES_5;
+  // sConfig.SamplingTime = ADC_SAMPLETIME_6CYCLES_5;
+  // sConfig.SamplingTime = ADC_SAMPLETIME_24CYCLES_5;
   sConfig.SingleDiff = ADC_SINGLE_ENDED;
   sConfig.OffsetNumber = ADC_OFFSET_NONE;
   sConfig.Offset = 0;
@@ -1023,6 +1027,7 @@ static void MX_FMC_Init(void)
   /* USER CODE END FMC_Init 0 */
 
   FMC_NORSRAM_TimingTypeDef Timing = {0};
+  FMC_NORSRAM_TimingTypeDef ExtTiming = {0};
 
   /* USER CODE BEGIN FMC_Init 1 */
 
@@ -1050,21 +1055,21 @@ static void MX_FMC_Init(void)
   hsram1.Init.NBLSetupTime = 0;
   hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;
   hsram1.Init.MaxChipSelectPulse = DISABLE;
-  /* Timing */
-  Timing.AddressSetupTime = 15;
-  Timing.AddressHoldTime = 15;
-  Timing.DataSetupTime = 30;
-  Timing.DataHoldTime = 0;
-  Timing.BusTurnAroundDuration = 2;
-  Timing.CLKDivision = 16;
-  Timing.DataLatency = 17;
-  Timing.AccessMode = FMC_ACCESS_MODE_A;
+  // /* Timing */
+  // Timing.AddressSetupTime = 15;
+  // Timing.AddressHoldTime = 15;
+  // Timing.DataSetupTime = 30;
+  // Timing.DataHoldTime = 0;
+  // Timing.BusTurnAroundDuration = 2;
+  // Timing.CLKDivision = 16;
+  // Timing.DataLatency = 17;
+  // Timing.AccessMode = FMC_ACCESS_MODE_A;
   /* ExtTiming */
 
-  if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
-  {
-    Error_Handler( );
-  }
+  // if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK)
+  // {
+  //   Error_Handler( );
+  // }
 
   /** Perform the SRAM2 memory initialization sequence
   */
@@ -1080,26 +1085,48 @@ static void MX_FMC_Init(void)
   hsram2.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS;
   hsram2.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
   hsram2.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
-  hsram2.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
+  // hsram2.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
+  hsram2.Init.ExtendedMode = FMC_EXTENDED_MODE_ENABLE;
   hsram2.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
   hsram2.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
   hsram2.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
-  hsram2.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;
+  // hsram2.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;
+  hsram2.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
   hsram2.Init.NBLSetupTime = 0;
   hsram2.Init.PageSize = FMC_PAGE_SIZE_NONE;
   hsram2.Init.MaxChipSelectPulse = DISABLE;
   /* Timing */
-  Timing.AddressSetupTime = 15;
-  Timing.AddressHoldTime = 15;
-  Timing.DataSetupTime = 30;
-  Timing.DataHoldTime = 0;
-  Timing.BusTurnAroundDuration = 2;
+  // Timing.AddressSetupTime = 15;
+  // Timing.AddressHoldTime = 15;
+  // Timing.DataSetupTime = 30;
+  // Timing.DataHoldTime = 0;
+  // Timing.BusTurnAroundDuration = 2;
+  // Timing.CLKDivision = 16;
+  // Timing.DataLatency = 17;
+  // Timing.AccessMode = FMC_ACCESS_MODE_A;
+  Timing.AddressSetupTime = 6;
+  Timing.AddressHoldTime = 11;
+  Timing.DataSetupTime = 3;
+  Timing.DataHoldTime = 3;
+  Timing.BusTurnAroundDuration = 1;
   Timing.CLKDivision = 16;
   Timing.DataLatency = 17;
   Timing.AccessMode = FMC_ACCESS_MODE_A;
   /* ExtTiming */
-
-  if (HAL_SRAM_Init(&hsram2, &Timing, NULL) != HAL_OK)
+  ExtTiming.AddressSetupTime = 3;
+  ExtTiming.AddressHoldTime = 11;
+  ExtTiming.DataSetupTime = 3;
+  ExtTiming.BusTurnAroundDuration = 2;
+  ExtTiming.CLKDivision = 16;
+  ExtTiming.DataLatency = 17;
+  ExtTiming.AccessMode = FMC_ACCESS_MODE_A;
+
+  // if (HAL_SRAM_Init(&hsram2, &Timing, NULL) != HAL_OK)
+  // if (HAL_SRAM_Init(&hsram1, &Timing, &ExtTiming) != HAL_OK)
+  // {
+  //   Error_Handler( );
+  // }
+  if (HAL_SRAM_Init(&hsram2, &Timing, &ExtTiming) != HAL_OK)
   {
     Error_Handler( );
   }
@@ -1119,25 +1146,35 @@ static void MX_FMC_Init(void)
   hsram3.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE;
   hsram3.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE;
   hsram3.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE;
+  // hsram3.Init.ExtendedMode = FMC_EXTENDED_MODE_ENABLE;
   hsram3.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE;
   hsram3.Init.WriteBurst = FMC_WRITE_BURST_DISABLE;
   hsram3.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY;
-  hsram3.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;
+  // hsram3.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE;
+  hsram3.Init.WriteFifo = FMC_WRITE_FIFO_DISABLE;
   hsram3.Init.NBLSetupTime = 0;
   hsram3.Init.PageSize = FMC_PAGE_SIZE_NONE;
   hsram3.Init.MaxChipSelectPulse = DISABLE;
   /* Timing */
   Timing.AddressSetupTime = 15;
   Timing.AddressHoldTime = 15;
-  Timing.DataSetupTime = 30;
-  Timing.DataHoldTime = 0;
-  Timing.BusTurnAroundDuration = 2;
+  Timing.DataSetupTime = 10;
+  Timing.DataHoldTime = 3;
+  Timing.BusTurnAroundDuration = 15;
   Timing.CLKDivision = 16;
   Timing.DataLatency = 17;
   Timing.AccessMode = FMC_ACCESS_MODE_A;
   /* ExtTiming */
-
-  if (HAL_SRAM_Init(&hsram3, &Timing, NULL) != HAL_OK)
+  ExtTiming.AddressSetupTime = 15;
+  ExtTiming.AddressHoldTime = 15;
+  ExtTiming.DataSetupTime = 30;
+  ExtTiming.DataHoldTime = 0;
+  ExtTiming.BusTurnAroundDuration = 2;
+  ExtTiming.CLKDivision = 16;
+  ExtTiming.DataLatency = 17;
+  ExtTiming.AccessMode = FMC_ACCESS_MODE_A;
+
+  if (HAL_SRAM_Init(&hsram3, &Timing, &ExtTiming) != HAL_OK)
   {
     Error_Handler( );
   }
@@ -1175,10 +1212,10 @@ static void MX_FMC_Init(void)
   Timing.AccessMode = FMC_ACCESS_MODE_A;
   /* ExtTiming */
 
-  if (HAL_SRAM_Init(&hsram4, &Timing, NULL) != HAL_OK)
-  {
-    Error_Handler( );
-  }
+  // if (HAL_SRAM_Init(&hsram4, &Timing, NULL) != HAL_OK)
+  // {
+  //   Error_Handler( );
+  // }
 
   /* USER CODE BEGIN FMC_Init 2 */
 
@@ -1299,6 +1336,32 @@ static void MX_GPIO_Init(void)
 /* USER CODE END MX_GPIO_Init_2 */
 }
 
+void MPU_RegionConfig(void)
+{
+  MPU_Region_InitTypeDef MPU_InitStruct;
+  /* Disable MPU */
+  HAL_MPU_Disable();
+  /* Configure RAM region as Region N°0, 8kB of size and R/W region */
+  MPU_InitStruct.Enable = MPU_REGION_ENABLE;
+  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
+  MPU_InitStruct.BaseAddress = 0x68000000;
+  MPU_InitStruct.LimitAddress = 0x68100000;
+  MPU_InitStruct.AccessPermission = MPU_REGION_ALL_RW;
+
+  // MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
+  // MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
+  MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
+  // MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
+  MPU_InitStruct.AttributesIndex = MPU_ATTRIBUTES_NUMBER5;
+
+  MPU_InitStruct.Number = MPU_REGION_NUMBER0;
+  // MPU_InitStruct.SubRegionDisable = 0x00;
+  MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
+  HAL_MPU_ConfigRegion(&MPU_InitStruct);
+  /* Enable MPU */
+  HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
+}
+
 /* USER CODE BEGIN 4 */
 
 /* USER CODE END 4 */

+ 5 - 0
Middlewares/Third_Party/FreeRTOS/Source/tasks.c

@@ -5308,6 +5308,7 @@ when performing module tests). */
 #endif
 
 #include "ImC/imc_kernel.h"
+#include "ImC/imc_extension.h"
 #include <stdio.h>
 #if (imcUSE_IMC_KERNEL == 1)
 
@@ -5324,6 +5325,9 @@ uint8_t ucLatestBufferIndex[imcMAX_NUM_TASKS] __attribute__((section(".kernel_nv
 
 void xTaskCheckpointCurrentTask(uint32_t lr_register)
 {
+	#if(imcPRINT_STATS)
+		imc_checkpoint_executed++;
+	#endif
 	// portDISABLE_INTERRUPTS();
 	TCB_t *tcb = pxCurrentTCB;
 	UBaseType_t taskNumber = pxCurrentTCB->uxTCBNumber;
@@ -5353,6 +5357,7 @@ void xTaskCheckpointCurrentTask(uint32_t lr_register)
 	ucTaskSnapshotValid[taskNumber] = pdTRUE;
 
 	__DMB();
+	imc_backup_estimations();
 	// portENABLE_INTERRUPTS();
 	
 }

Різницю між файлами не показано, бо вона завелика
+ 237 - 0
imc/exprs/date2025/3_adaptive/draw_graph_expr_3.ipynb


+ 166 - 0
imc/exprs/date2025/3_adaptive/draw_graph_expr_3.py

@@ -0,0 +1,166 @@
+import pickle
+import os
+import pandas as pd
+import seaborn as sns
+import matplotlib.pyplot as plt
+
+import plot_utils
+
+def validate_and_cleanup_df(df):
+    # rename_dict = {
+    #     "checkpoint_enabled": "ckpt",
+    #     "voltage_check_enabled": "VC",
+    #     "pass_counter_enabled": "PC"
+    # }
+    # df = df.rename(columns=rename_dict)
+
+    mask = df["is_correct"] == False
+    if mask.any():
+        print("drop rows with incorrect output")
+        print(df[mask])
+
+    df = df[~mask]
+    assert(df["is_correct"].all())
+
+    # def category_mapper(row):
+    #     if row["ckpt"] == False:
+    #         return "Baseline"
+    #     else:
+    #         if row["VC"] == False:
+    #             assert(row["PC"] == True)
+    #             return "PC"
+    #         else:
+    #             assert(row["PC"] == False)
+    #             return "VC"
+
+    # category_column_name = "config"
+    # df[category_column_name] = df.apply(category_mapper, axis=1)
+
+    def process_stats(row):
+        lines = row["stats"]
+        result = {}
+        for line in lines:
+            key, val = line.split(":")
+            val = int(val.strip())
+            if key.startswith("checkpoint triggered"):
+                result["ckpt_trig"] = val
+            if key.startswith("checkpoint executed"):
+                result["ckpt_exec"] = val
+        return result
+    
+    df_stats = df.apply(process_stats, axis=1, result_type="expand")
+    df = pd.concat([df, df_stats], axis=1)
+
+    drop_columns = [
+        "start",
+        "end",
+        "recovery",
+        "outputs",
+        "stats",
+        # "ckpt",
+        # "VC",
+        # "PC",
+        "is_correct"
+    ]
+    df = df.drop(columns = drop_columns) 
+    return df
+
+
+def get_base_df():
+    benchmarks = [ 
+        "vBasicMath", 
+        "vCrc", 
+        "vFFT", 
+        "vSha", 
+        "vStringSearch", 
+        "vMatMul", 
+        "vConv2d", 
+        "vAes"
+    ]
+    output_dir = "/home/ybkim/workspace/imc/imc_freertos_app_m33/imc/exprs/date2025/3_adaptive/output"
+
+    all_dfs = []
+    configs = ["pass_count", "adaptive"]
+    drop_index = list(range(0, 3))
+    drop_index = None
+
+    for benchmark in benchmarks:
+        for config_name in configs:
+            pickle_filename = f"{output_dir}/{config_name}/{benchmark}.pickle"
+            if not os.path.exists(pickle_filename):
+                print(f"pass loading {config_name}/{benchmark}")
+                continue
+            with open(pickle_filename, "rb") as f:
+                orig_df = pickle.load(f)
+                if drop_index and config_name == "adaptive":
+                    orig_df = orig_df.drop(drop_index)
+                df = validate_and_cleanup_df(orig_df)
+                df["config"] = config_name
+                all_dfs.append(df)
+
+    orig_df = pd.concat(all_dfs)
+    return orig_df
+
+
+def draw_checkpoint_count():
+    plot_utils.set_theme_seaborn(kind="line")
+    orig_df = get_base_df()
+    mask = orig_df["ckpt_trig"].abs() > 1e7 
+    df = orig_df[~mask]
+    mask = orig_df["ckpt_exec"].abs() > 1e6
+    df = orig_df[~mask]
+    benchmarks = list(df["bench_name"].unique())
+    print(benchmarks)
+    fig_size = (12, 3.5 * len(benchmarks))
+    n_rows = len(benchmarks)
+    n_cols = 1
+    hspace = 0.08
+    fig = plt.figure(figsize=fig_size)
+    axes = fig.subplots(n_rows, n_cols, sharex=False, gridspec_kw={"hspace": hspace})
+    for (i, (key, d_orig)) in enumerate(df.groupby(["bench_name"])):
+        d = d_orig.reset_index()
+        # mask = d["config"] == "adaptive"
+        # d = d[mask]
+        y = "ckpt_exec"
+        # y = "ckpt_trig"
+        print(d)
+
+        ax = axes.reshape(-1)[i]
+        sns.lineplot(
+            data=d,
+            x="index",
+            y=y,
+            hue="config",
+            ax=ax
+        )
+        ax.set_title(key[0])
+
+
+def draw_graph():
+    orig_df = get_base_df()
+    df = orig_df.groupby(["bench_name", "config"]).mean()
+    df = df.reset_index()
+
+    # df = df.pivot(index="bench_name", columns="config", values="time_taken")
+
+    # df2 = pd.DataFrame()
+    # df2["PC"] = df["PC"] / df["Baseline"]
+    # df2["VC"] = df["VC"] / df["Baseline"]
+
+    # df2 = df2.reset_index().melt(id_vars=["bench_name"], var_name="config", value_name="normalized")
+    # df2 = df2.sort_values(by="bench_name")
+    # df2 = df2[df2["config"] == "PC"]
+    # df2 = df2[df2["config"] == "VC"]
+    # df2 = df2[df2["bench_name"] == "vFFT"]
+
+    plot_utils.set_theme_seaborn()
+    g = sns.catplot(
+        data=df,
+        kind="bar",
+        x="bench_name",
+        y = "time_taken",
+        hue="config",
+        aspect=2.3
+    )
+
+    return g

+ 67 - 42
imc/exprs/date2025/3_adaptive/run_expr_3.py

@@ -12,6 +12,26 @@ WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
 NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
 OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
 
+def get_build_config(benchmark, config_name):
+    config = get_default_build_config()
+    config.bench_name = benchmark
+    bench_repeat_count = config.bench_repeat_count_small[benchmark]
+    config.bench_repeat_count = bench_repeat_count
+
+    if config_name == "pass_count":
+        config.use_checkpoint_pass_counter = True
+        config.checkpoint_pass_count = config.pass_count_10ms[benchmark]
+    
+    if config_name == "adaptive":
+        config.use_checkpoint_voltage_check = True
+        config.split_loop = True
+        config.enable_adaptive_loop_pass_count = True
+        # config.enable_static_loop_pass_count = True
+        # config.loop_pass_count = 50
+        config.max_loop_ids = 30
+
+    return config
+
 def main():
     pps = PPS_E36311A()
     config = get_default_build_config()
@@ -26,65 +46,70 @@ def main():
         "vConv2d",
         "vAes",
     ]
-    benchmarks = ["vSha"]
+    # benchmarks = [
+    #     "vBasicMath"
+    # ]
+
+    configs = ["pass_count", "adaptive"]
+    # configs = ["adaptive"]
+
+    total_iterations = 20
 
     for benchmark in benchmarks:
-        all_records = []
-        bench_repeat_count = config.bench_repeat_count_small[benchmark]
-
-        config.bench_name = benchmark
-        config.bench_repeat_count = bench_repeat_count
-
-        pps.set_voltage(3.3, 1)
-        pps.set_current(0.1, 1)
-        pps.output_on(1)
-
-        env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
-
-        with tempfile.TemporaryDirectory() as build_dir:
-            binary = env.build_binary(config, build_dir)
-            env.clear_nvm_and_load_binary(binary, resume=False)
-
-        pps.set_current(0.015, 1)
-        time.sleep(1)
-
-        env.resume_board(terminate=True)
-        total_iterations = 10
-        watcher = SerialWatcher(benchmark, total_iterations)
-        records = watcher.run()
-        for record in records:
-            record.update(
-                {
-                    # "loop_pass_count": loop_pass_count,
-                }
-            )
-            all_records.append(record)
-        df = pd.DataFrame(all_records)
-        print(df)
-        save_records(benchmark, df)
+        for config_name in  configs:
+            all_records = []
+            config = get_build_config(benchmark, config_name)
+
+            pps.set_voltage(3.3, 1)
+            pps.set_current(0.1, 1)
+            pps.output_on(1)
+
+            env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+            with tempfile.TemporaryDirectory() as build_dir:
+                binary = env.build_binary(config, build_dir)
+                env.clear_nvm_and_load_binary(binary, resume=False)
+
+            pps.set_current(0.015, 1)
+            time.sleep(1)
+
+            env.resume_board(terminate=True)
+            watcher = SerialWatcher(benchmark, total_iterations)
+            records = watcher.run()
+
+            for record in records:
+                record.update(
+                    {
+                        # "loop_pass_count": loop_pass_count,
+                    }
+                )
+                all_records.append(record)
+
+            df = pd.DataFrame(all_records)
+            columns = ["bench_name", "time_taken", "recovery", "stats", "is_correct"]
+            print(df[columns])
+            save_records(benchmark, config_name, df)
+
     pps.output_off(1)
 
 
 def get_default_build_config():
     config = BuildConfigM33()
-    config.bench_name = "vBasicMath"
     config.insert_compiler_checkpoints = True
     config.enable_extension = True
     config.use_checkpoint_pass_counter = False
-    config.checkpoint_pass_count = 100
-    config.use_checkpoint_voltage_check = True
+    config.use_checkpoint_voltage_check = False
     config.bench_infinite_loop = True
+    config.print_recovery_message = True
     config.split_loop = False
     config.enable_static_loop_pass_count = False
-    config.loop_pass_count = 0
     config.enable_adaptive_loop_pass_count = False
-    config.max_loop_ids = 30
-    config.print_recovery_message = True
+    config.print_stats = True
     return config
 
 
-def save_records(bench_name, df):
-    with open(f"output/{bench_name}.pickle", "wb") as f:
+def save_records(bench_name, config_name, df):
+    with open(f"output/{config_name}/{bench_name}.pickle", "wb") as f:
         pickle.dump(df, f)
 
 

+ 106 - 0
imc/exprs/date2025/4_decide_pass_count/run_expr_4.py

@@ -0,0 +1,106 @@
+import tempfile
+import time
+import pickle
+import pandas as pd
+import pprint
+
+from imc_utils.pps_e36311a import PPS_E36311A
+from imc_utils.build_config.cortex_m33 import BuildConfigM33
+from imc_utils.build_config.test_env import TestEnv
+from imc_utils.serial_watch import SerialWatcher
+
+WORKSPACE_ROOT = "/home/ybkim/workspace/imc/imc_freertos_app_m33"
+NVM_RESET_BIN = f"{WORKSPACE_ROOT}/imc/utils/nvm_reset.elf"
+OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
+
+def main():
+    pps = PPS_E36311A()
+    config = get_default_build_config()
+
+    benchmarks = [
+        "vBasicMath",
+        "vCrc",
+        "vFFT",
+        "vSha",
+        "vStringSearch",
+        "vMatMul",
+        "vConv2d",
+        "vAes",
+    ]
+    # benchmarks = ["vSha"]
+
+    target_period_ms = 10
+
+    output_dict = {}
+
+    for benchmark in benchmarks:
+        bench_repeat_count = config.bench_repeat_count_small[benchmark]
+
+        config.bench_name = benchmark
+        config.bench_repeat_count = bench_repeat_count
+
+        pps.set_voltage(3.3, 1)
+        pps.set_current(0.1, 1)
+        pps.output_on(1)
+
+        env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
+
+        with tempfile.TemporaryDirectory() as build_dir:
+            binary = env.build_binary(config, build_dir)
+            env.clear_nvm_and_load_binary(binary, resume=False)
+
+        total_iterations = 1
+        watcher = SerialWatcher(benchmark, total_iterations)
+        env.resume_board(terminate=True)
+        records = watcher.run()
+
+        record = records[0]
+        time_taken = record["time_taken"]
+        stats = record["stats"]
+
+        for stat in stats:
+            if stat.startswith("checkpoint triggered"):
+                checkpoint_triggered = int(stat.split(":")[1].strip())
+                break
+        
+        trigger_period = time_taken / checkpoint_triggered * 1000
+        pass_count = target_period_ms / trigger_period
+
+        print(f"checkpoint triggered: {checkpoint_triggered}")
+        print(f"checkpoint trigger frequency: {checkpoint_triggered/time_taken}/s")
+        print(f"trigger period: {trigger_period}ms")
+        print(f"pass count: {pass_count}")
+
+        output_dict[benchmark] = int(pass_count)
+
+    pps.output_off(1)
+
+    pprint.pprint(output_dict)
+
+
+def get_default_build_config():
+    config = BuildConfigM33()
+    config.bench_name = "vBasicMath"
+    config.insert_compiler_checkpoints = True
+    config.enable_extension = True
+    config.use_checkpoint_pass_counter = True
+    config.checkpoint_pass_count = 10000000
+    config.use_checkpoint_voltage_check = False
+    config.bench_infinite_loop = True
+    config.split_loop = False
+    config.enable_static_loop_pass_count = False
+    config.loop_pass_count = 0
+    config.enable_adaptive_loop_pass_count = False
+    config.max_loop_ids = 30
+    config.print_recovery_message = False
+    config.print_stats = True
+    return config
+
+
+def save_records(bench_name, df):
+    with open(f"output/{bench_name}.pickle", "wb") as f:
+        pickle.dump(df, f)
+
+
+if __name__ == "__main__":
+    main()

+ 4 - 0
imc_extension.cmake

@@ -6,6 +6,7 @@ set(IMC_ENABLE_ADAPTIVE_LOOP_PASS_COUNT 0 CACHE BOOL "")
 set(IMC_MAX_LOOP_IDS 1 CACHE STRING "")
 set(IMC_LOOP_PASS_COUNT 10 CACHE BOOL "")
 set(IMC_BENCH_REPEAT_COUNT 1 CACHE BOOL "")
+set(IMC_PRINT_STATS 0 CACHE BOOL "")
 
 set(AVAILABLE_BENCHES "vBasicMath" "vStringSearch" "vFFT" "vSha" "vCrc" "vMatMul" "vConv2d" "adc_demo" "vAes")
 if(NOT IMC_BENCH_NAME IN_LIST AVAILABLE_BENCHES)
@@ -18,6 +19,7 @@ endif()
 
 add_compile_definitions(imcBENCH_NAME=${IMC_BENCH_NAME})
 add_compile_definitions(imcBENCH_REPEAT_COUNT=${IMC_BENCH_REPEAT_COUNT})
+
 if(IMC_BENCH_INFINITE_LOOP)
     add_compile_definitions(imcBENCH_INFINITE_LOOP=1)
 endif()
@@ -25,6 +27,8 @@ if(IMC_PRINT_RECOVERY_MESSAGE)
     add_compile_definitions(imcPRINT_RECOVERY_MESSAGE=1)
 endif()
 
+add_compile_definitions(imcPRINT_STATS=${IMC_PRINT_STATS})
+
 list(APPEND SRC_FILES
     Core/Src/ImC/imc_extension.c
 )

+ 2 - 1
setup_build_dir.py

@@ -10,7 +10,7 @@ OPENOCD_SCRIPT = f"{WORKSPACE_ROOT}/imc_freertos_app_m33.cfg"
 BUILD_DIR = f"{WORKSPACE_ROOT}/build"
 
 config = BuildConfigM33()
-config.bench_name = "vFFT"
+config.bench_name = "vSha"
 config.insert_compiler_checkpoints = True
 config.enable_extension = True
 config.use_checkpoint_pass_counter = False
@@ -22,6 +22,7 @@ config.enable_static_loop_pass_count = False
 config.enable_adaptive_loop_pass_count = True
 config.max_loop_ids = 30
 config.bench_repeat_count = config.bench_repeat_count_small[config.bench_name]
+config.print_stats = True
 
 env = TestEnv(WORKSPACE_ROOT, NVM_RESET_BIN, OPENOCD_SCRIPT)
 

Деякі файли не було показано, через те що забагато файлів було змінено