diff --git a/data/custom/11-unschedulable-test-case/architecture.csv b/data/custom/11-unschedulable-test-case/architecture.csv new file mode 100644 index 0000000..91352c3 --- /dev/null +++ b/data/custom/11-unschedulable-test-case/architecture.csv @@ -0,0 +1,2 @@ +core_id,speed_factor,scheduler +Core_1,1.49,EDF diff --git a/data/custom/11-unschedulable-test-case/budgets.csv b/data/custom/11-unschedulable-test-case/budgets.csv new file mode 100644 index 0000000..ff0d7de --- /dev/null +++ b/data/custom/11-unschedulable-test-case/budgets.csv @@ -0,0 +1,3 @@ +component_id,scheduler,budget,period,core_id,priority +Camera_Sensor,RM,5,9,Core_1, +Image_Processor,EDF,2,6,Core_1, diff --git a/data/custom/11-unschedulable-test-case/tasks.csv b/data/custom/11-unschedulable-test-case/tasks.csv new file mode 100644 index 0000000..2b1d5c2 --- /dev/null +++ b/data/custom/11-unschedulable-test-case/tasks.csv @@ -0,0 +1,9 @@ +task_name,wcet,period,component_id,priority +Task_0,16,100,Camera_Sensor,1 +Task_1,10,50,Camera_Sensor,0 +Task_2,58,70,Camera_Sensor,3 +Task_3,8,200,Camera_Sensor,2 +Task_4,120,900,Camera_Sensor,4 +Task_5,4,25,Image_Processor, +Task_6,4,50,Image_Processor, +Task_7,13,75,Image_Processor diff --git a/data/custom/13-validation-test-case/architecture.csv b/data/custom/13-validation-test-case/architecture.csv new file mode 100644 index 0000000..d63dbcc --- /dev/null +++ b/data/custom/13-validation-test-case/architecture.csv @@ -0,0 +1,3 @@ +core_id,speed_factor,scheduler +C1,1.0,EDF +C2,1.0,RM \ No newline at end of file diff --git a/data/custom/13-validation-test-case/budgets.csv b/data/custom/13-validation-test-case/budgets.csv new file mode 100644 index 0000000..8924fb4 --- /dev/null +++ b/data/custom/13-validation-test-case/budgets.csv @@ -0,0 +1,3 @@ +component_id,scheduler,budget,period,core_id,priority +CompA,EDF,3,6,C1, +CompB,EDF,2,6,C1, \ No newline at end of file diff --git a/data/custom/13-validation-test-case/tasks.csv b/data/custom/13-validation-test-case/tasks.csv new file mode 100644 index 0000000..3530490 --- /dev/null +++ b/data/custom/13-validation-test-case/tasks.csv @@ -0,0 +1,4 @@ +task_name,wcet,period,component_id,priority +T1,1,3,CompA, +T2,1,3,CompA, +T3,2,6,CompA, \ No newline at end of file diff --git a/data/custom/14-validation-test-case/architecture.csv b/data/custom/14-validation-test-case/architecture.csv new file mode 100644 index 0000000..8e8c71e --- /dev/null +++ b/data/custom/14-validation-test-case/architecture.csv @@ -0,0 +1,2 @@ +core_id,speed_factor,scheduler +C1,1.0,EDF \ No newline at end of file diff --git a/data/custom/14-validation-test-case/budgets.csv b/data/custom/14-validation-test-case/budgets.csv new file mode 100644 index 0000000..8ea834e --- /dev/null +++ b/data/custom/14-validation-test-case/budgets.csv @@ -0,0 +1,3 @@ +component_id,scheduler,budget,period,core_id,priority +CompA,EDF,3,6,C1,1 +CompB,EDF,2,6,C1,1 \ No newline at end of file diff --git a/data/custom/14-validation-test-case/tasks.csv b/data/custom/14-validation-test-case/tasks.csv new file mode 100644 index 0000000..12aa416 --- /dev/null +++ b/data/custom/14-validation-test-case/tasks.csv @@ -0,0 +1,6 @@ +task_name,wcet,period,component_id,priority +T1,1,6,CompA, +T2,1,6,CompA, +T3,2,12,CompA, +T4,1,12,CompB, +T5,1,6,CompB, \ No newline at end of file diff --git a/data/custom/15-med-onecore/architecture.csv b/data/custom/15-med-onecore/architecture.csv new file mode 100644 index 0000000..bdd94cb --- /dev/null +++ b/data/custom/15-med-onecore/architecture.csv @@ -0,0 +1,3 @@ +core_id,speed_factor,scheduler +Core_1,1.49,EDF +Core_2,0.62,EDF diff --git a/data/custom/15-med-onecore/budgets.csv b/data/custom/15-med-onecore/budgets.csv new file mode 100644 index 0000000..68ae82c --- /dev/null +++ b/data/custom/15-med-onecore/budgets.csv @@ -0,0 +1,3 @@ +component_id,scheduler,budget,period,core_id,priority +Lidar_Sensor,RM,1,3,Core_2, +Control_Unit,EDF,6,9,Core_2, diff --git a/data/custom/15-med-onecore/tasks.csv b/data/custom/15-med-onecore/tasks.csv new file mode 100644 index 0000000..306e9b2 --- /dev/null +++ b/data/custom/15-med-onecore/tasks.csv @@ -0,0 +1,11 @@ +task_name,wcet,period,component_id,priority +Task_8,1,25,Lidar_Sensor,0 +Task_9,4,100,Lidar_Sensor,2 +Task_10,2,50,Lidar_Sensor,1 +Task_11,3,200,Lidar_Sensor,3 +Task_12,3,75,Control_Unit, +Task_13,4,40,Control_Unit, +Task_14,6,100,Control_Unit, +Task_15,4,50,Control_Unit, +Task_16,5,75,Control_Unit, +Task_17,4,120,Control_Unit, diff --git a/data/custom/16-large-onecore/architecture.csv b/data/custom/16-large-onecore/architecture.csv new file mode 100644 index 0000000..f664efd --- /dev/null +++ b/data/custom/16-large-onecore/architecture.csv @@ -0,0 +1,4 @@ +core_id,speed_factor,scheduler +Core_1,0.54,EDF +Core_2,0.7,EDF +Core_3,0.74,RM diff --git a/data/custom/16-large-onecore/budgets.csv b/data/custom/16-large-onecore/budgets.csv new file mode 100644 index 0000000..f812d93 --- /dev/null +++ b/data/custom/16-large-onecore/budgets.csv @@ -0,0 +1,3 @@ +component_id,scheduler,budget,period,core_id,priority +Lidar_Sensor,RM,1,3,Core_2, +Control_Unit,EDF,4,6,Core_2 diff --git a/data/custom/16-large-onecore/tasks.csv b/data/custom/16-large-onecore/tasks.csv new file mode 100644 index 0000000..a12622c --- /dev/null +++ b/data/custom/16-large-onecore/tasks.csv @@ -0,0 +1,11 @@ +task_name,wcet,period,component_id,priority +Task_12,8,100,Lidar_Sensor,1 +Task_13,9,90,Lidar_Sensor,0 +Task_14,6,300,Lidar_Sensor,2 +Task_15,23,900,Lidar_Sensor,3 +Task_16,2,200,Control_Unit, +Task_17,7,80,Control_Unit, +Task_18,4,800,Control_Unit, +Task_19,12,100,Control_Unit, +Task_20,37,300,Control_Unit, +Task_21,4,50,Control_Unit, diff --git a/data/simulator_outputs/1-tiny-test-case.csv b/data/simulator_outputs/1-tiny-test-case.csv new file mode 100644 index 0000000..f4aa528 --- /dev/null +++ b/data/simulator_outputs/1-tiny-test-case.csv @@ -0,0 +1,3 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,23.00,23.00,True +Task_1,Camera_Sensor,True,77.00,77.00,True diff --git a/data/simulator_outputs/10-unschedulable-test-case.csv b/data/simulator_outputs/10-unschedulable-test-case.csv new file mode 100644 index 0000000..3fa3899 --- /dev/null +++ b/data/simulator_outputs/10-unschedulable-test-case.csv @@ -0,0 +1,116 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,10.33,11.00,True +Task_1,Camera_Sensor,True,5.00,6.00,True +Task_2,Image_Processor,True,7.21,12.00,True +Task_3,Image_Processor,True,1.00,1.00,True +Task_4,Bitmap_Processor,True,4.00,5.00,True +Task_5,Bitmap_Processor,True,10.71,11.00,True +Task_6,Lidar_Sensor,True,3.91,10.00,True +Task_7,Lidar_Sensor,True,34.79,49.00,True +Task_8,Lidar_Sensor,True,116.08,141.00,True +Task_9,Lidar_Sensor,True,2.33,6.00,True +Task_10,Control_Unit,True,2.27,9.00,True +Task_11,Control_Unit,True,4.56,10.00,True +Task_12,Control_Unit,True,5.60,10.00,True +Task_13,Control_Unit,True,4.46,10.00,True +Task_14,Control_Unit,True,2.58,9.00,True +Task_15,Control_Unit,True,6.69,12.00,True +Task_16,GPS_Sensor,True,9.29,15.00,True +Task_17,GPS_Sensor,True,1.00,1.00,True +Task_18,Communication_Unit,True,1.00,1.00,True +Task_19,Communication_Unit,True,1.00,1.00,True +Task_20,Communication_Unit,True,7.21,12.00,True +Task_21,Communication_Unit,True,10.38,13.00,True +Task_22,Proximity_Sensor,True,16.00,16.00,True +Task_23,Proximity_Sensor,True,1.00,1.00,True +Task_24,Proximity_Sensor,True,1.00,1.00,True +Task_25,Radar_Sensor,True,1.00,1.00,True +Task_26,Radar_Sensor,True,34.67,37.00,True +Task_27,Radar_Sensor,True,136.58,141.00,True +Task_28,Sonar_Sensor,True,14.38,22.00,True +Task_29,Sonar_Sensor,True,20.00,21.00,True +Task_30,Laser_Sensor,True,62.29,65.00,True +Task_31,Laser_Sensor,True,2.54,7.00,True +Task_32,Laser_Sensor,True,18.17,21.00,True +Task_33,Laser_Sensor,True,6.75,8.00,True +Task_34,Infrared_Sensor,False,0.00,0.00,False +Task_35,Infrared_Sensor,True,25.23,31.00,False +Task_36,Infrared_Sensor,True,2.00,2.00,False +Task_37,Ultraviolet_Sensor,True,3.83,23.00,False +Task_38,Ultraviolet_Sensor,True,51.67,99.00,False +Task_39,Ultraviolet_Sensor,True,15.00,39.00,False +Task_40,Ultraviolet_Sensor,True,7.00,9.00,False +Task_41,Ultraviolet_Sensor,False,135.00,191.00,False +Task_42,Ultraviolet_Sensor,False,0.00,0.00,False +Task_43,Ultraviolet_Sensor,True,4.00,9.00,False +Task_44,Ultraviolet_Sensor,True,35.75,51.00,False +Task_45,Thermal_Sensor,False,0.00,0.00,False +Task_46,Thermal_Sensor,True,3.00,3.00,False +Task_47,Thermal_Sensor,False,11.00,11.00,False +Task_48,Thermal_Sensor,False,0.00,0.00,False +Task_49,Pressure_Sensor,True,8.88,10.00,False +Task_50,Pressure_Sensor,True,22.17,25.00,False +Task_51,Pressure_Sensor,False,0.00,0.00,False +Task_52,Humidity_Sensor,True,2.32,3.00,False +Task_53,Humidity_Sensor,False,5.00,5.00,False +Task_54,Temperature_Sensor,True,30.71,47.00,True +Task_55,Temperature_Sensor,True,1.00,1.00,True +Task_56,Temperature_Sensor,True,240.25,247.00,True +Task_57,Temperature_Sensor,True,7.47,18.00,True +Task_58,Light_Sensor,True,1.00,1.00,True +Task_59,Light_Sensor,True,22.42,32.00,True +Task_60,Light_Sensor,True,221.75,231.00,True +Task_61,Sound_Sensor,True,42.88,54.00,True +Task_62,Sound_Sensor,True,25.88,32.00,True +Task_63,Vibration_Sensor,True,7.50,9.00,True +Task_64,Vibration_Sensor,True,9.00,9.00,True +Task_65,Motion_Sensor,True,10.58,48.00,True +Task_66,Motion_Sensor,True,147.00,173.00,True +Task_67,Acceleration_Sensor,True,1.00,1.00,True +Task_68,Acceleration_Sensor,True,3.69,14.00,True +Task_69,Acceleration_Sensor,True,21.25,35.00,True +Task_70,Acceleration_Sensor,True,241.25,253.00,True +Task_71,Gyroscope_Sensor,True,4.62,10.00,True +Task_72,Gyroscope_Sensor,True,1.00,1.00,True +Task_73,Gyroscope_Sensor,True,1.00,1.00,True +Task_74,Gyroscope_Sensor,True,34.12,38.00,True +Task_75,Gyroscope_Sensor,True,21.25,27.00,True +Task_76,Gyroscope_Sensor,True,1.00,1.00,True +Task_77,Magnetometer_Sensor,True,1.00,1.00,True +Task_78,Magnetometer_Sensor,True,17.88,23.00,True +Task_79,Compass_Sensor,True,2.21,12.00,True +Task_80,Compass_Sensor,True,6.12,15.00,True +Task_81,Compass_Sensor,True,2.93,12.00,True +Task_82,Compass_Sensor,True,50.00,51.00,True +Task_83,Altimeter_Sensor,True,9.48,12.00,False +Task_84,Altimeter_Sensor,True,30.17,48.00,False +Task_85,Altimeter_Sensor,False,0.00,0.00,False +Task_86,Barometer_Sensor,True,10.33,15.00,True +Task_87,Barometer_Sensor,True,1.00,1.00,True +Task_88,Barometer_Sensor,True,56.50,63.00,True +Task_89,Hygrometer_Sensor,True,1.00,1.00,True +Task_90,Hygrometer_Sensor,True,92.81,107.00,True +Task_91,Anemometer_Sensor,False,0.00,0.00,False +Task_92,Anemometer_Sensor,False,21.00,21.00,False +Task_93,Anemometer_Sensor,True,3.00,3.00,False +Task_94,Anemometer_Sensor,False,0.00,0.00,False +Task_95,Rain_Gauge_Sensor,True,5.00,5.00,True +Task_96,Rain_Gauge_Sensor,True,17.00,17.00,True +Task_97,Rain_Gauge_Sensor,True,65.00,65.00,True +Task_98,Snow_Gauge_Sensor,True,7.69,12.00,False +Task_99,Snow_Gauge_Sensor,True,4.62,20.00,False +Task_100,Snow_Gauge_Sensor,True,98.88,140.00,False +Task_101,Snow_Gauge_Sensor,False,329.33,404.00,False +Task_102,Snow_Gauge_Sensor,True,40.50,56.00,False +Task_103,Snow_Gauge_Sensor,True,2.48,11.00,False +Task_104,Snow_Gauge_Sensor,False,0.00,0.00,False +Task_105,Snow_Gauge_Sensor,True,106.17,144.00,False +Task_106,Thermometer_Sensor,True,6.00,8.00,True +Task_107,Thermometer_Sensor,True,2.00,2.00,True +Task_108,Thermometer_Sensor,True,81.00,81.00,True +Task_109,Thermometer_Sensor,True,10.67,13.00,True +Task_110,Pyrometer_Sensor,True,10.00,10.00,False +Task_111,Pyrometer_Sensor,False,28.00,28.00,False +Task_112,Pyrometer_Sensor,False,0.00,0.00,False +Task_113,Photometer_Sensor,True,13.08,16.00,True +Task_114,Photometer_Sensor,True,10.10,13.00,True diff --git a/data/simulator_outputs/2-small-test-case.csv b/data/simulator_outputs/2-small-test-case.csv new file mode 100644 index 0000000..c6873db --- /dev/null +++ b/data/simulator_outputs/2-small-test-case.csv @@ -0,0 +1,10 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,7.75,8.00,False +Task_1,Camera_Sensor,True,104.33,120.00,False +Task_2,Camera_Sensor,True,4.92,7.00,False +Task_3,Camera_Sensor,False,199.00,205.00,False +Task_4,Image_Processor,True,6.83,12.00,True +Task_5,Image_Processor,True,62.33,78.00,True +Task_6,Image_Processor,True,163.67,256.00,True +Task_7,Image_Processor,True,91.00,158.00,True +Task_8,Image_Processor,True,10.88,16.00,True diff --git a/data/simulator_outputs/3-medium-test-case.csv b/data/simulator_outputs/3-medium-test-case.csv new file mode 100644 index 0000000..c71f134 --- /dev/null +++ b/data/simulator_outputs/3-medium-test-case.csv @@ -0,0 +1,19 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,19.44,23.00,True +Task_1,Camera_Sensor,True,11.44,13.00,True +Task_2,Camera_Sensor,True,132.67,139.00,True +Task_3,Camera_Sensor,True,9.22,12.00,True +Task_4,Camera_Sensor,True,416.00,416.00,True +Task_5,Image_Processor,True,6.50,7.00,True +Task_6,Image_Processor,True,7.00,7.00,True +Task_7,Image_Processor,True,37.50,43.00,True +Task_8,Lidar_Sensor,True,3.47,4.00,True +Task_9,Lidar_Sensor,True,45.17,62.00,True +Task_10,Lidar_Sensor,True,10.08,15.00,True +Task_11,Lidar_Sensor,True,94.00,103.00,True +Task_12,Control_Unit,True,9.25,18.00,True +Task_13,Control_Unit,True,9.40,12.00,True +Task_14,Control_Unit,True,23.44,37.00,True +Task_15,Control_Unit,True,11.58,22.00,True +Task_16,Control_Unit,True,20.58,36.00,True +Task_17,Control_Unit,True,19.27,28.00,True diff --git a/data/simulator_outputs/4-large-test-case.csv b/data/simulator_outputs/4-large-test-case.csv new file mode 100644 index 0000000..c7f07e0 --- /dev/null +++ b/data/simulator_outputs/4-large-test-case.csv @@ -0,0 +1,29 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,24.61,42.00,True +Task_1,Camera_Sensor,True,57.58,68.00,True +Task_2,Camera_Sensor,True,10.43,20.00,True +Task_3,Camera_Sensor,True,6.75,14.00,True +Task_4,Camera_Sensor,True,9.33,14.00,True +Task_5,Image_Processor,True,7.99,14.00,True +Task_6,Image_Processor,True,26.33,38.00,True +Task_7,Image_Processor,True,11.83,29.00,True +Task_8,Bitmap_Processor,True,165.67,178.00,True +Task_9,Bitmap_Processor,True,108.42,287.00,True +Task_10,Bitmap_Processor,True,32.91,38.00,True +Task_11,Bitmap_Processor,True,163.00,330.00,True +Task_12,Lidar_Sensor,False,54.60,96.00,False +Task_13,Lidar_Sensor,True,41.65,51.00,False +Task_14,Lidar_Sensor,False,153.25,208.00,False +Task_15,Lidar_Sensor,False,0.00,0.00,False +Task_16,Control_Unit,True,8.00,28.00,True +Task_17,Control_Unit,True,14.96,24.00,True +Task_18,Control_Unit,True,8.67,9.00,True +Task_19,Control_Unit,True,31.75,52.00,True +Task_20,Control_Unit,True,206.33,227.00,True +Task_21,Control_Unit,True,7.15,8.00,True +Task_22,GPS_Sensor,True,28.82,34.00,True +Task_23,GPS_Sensor,True,16.33,22.00,True +Task_24,Communication_Unit,True,9.00,9.00,True +Task_25,Communication_Unit,True,37.33,50.00,True +Task_26,Communication_Unit,True,209.00,209.00,True +Task_27,Communication_Unit,True,8.80,9.00,True diff --git a/data/simulator_outputs/5-huge-test-case.csv b/data/simulator_outputs/5-huge-test-case.csv new file mode 100644 index 0000000..8399ea5 --- /dev/null +++ b/data/simulator_outputs/5-huge-test-case.csv @@ -0,0 +1,62 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,6.24,7.00,True +Task_1,Camera_Sensor,True,83.53,85.00,True +Task_2,Image_Processor,True,27.61,30.00,True +Task_3,Image_Processor,True,50.00,52.00,True +Task_4,Bitmap_Processor,True,33.33,39.00,True +Task_5,Bitmap_Processor,True,219.00,221.00,True +Task_6,Lidar_Sensor,True,106.00,106.00,True +Task_7,Lidar_Sensor,True,4.00,4.00,True +Task_8,Lidar_Sensor,True,3.81,4.00,True +Task_9,Lidar_Sensor,True,223.00,223.00,True +Task_10,Control_Unit,True,3.56,12.00,True +Task_11,Control_Unit,True,28.79,70.00,True +Task_12,Control_Unit,True,19.88,40.00,True +Task_13,Control_Unit,True,5.22,14.00,True +Task_14,Control_Unit,True,61.01,128.00,True +Task_15,Control_Unit,True,23.79,28.00,True +Task_16,GPS_Sensor,True,21.00,21.00,True +Task_17,GPS_Sensor,True,61.00,61.00,True +Task_18,Communication_Unit,True,11.00,13.00,True +Task_19,Communication_Unit,True,6.16,8.00,True +Task_20,Communication_Unit,True,107.60,120.00,True +Task_21,Communication_Unit,True,2.21,5.00,True +Task_22,Proximity_Sensor,True,8.30,11.00,True +Task_23,Proximity_Sensor,True,24.22,28.00,True +Task_24,Proximity_Sensor,True,5.98,10.00,True +Task_25,Radar_Sensor,True,4.07,10.00,True +Task_26,Radar_Sensor,True,56.33,60.00,True +Task_27,Radar_Sensor,True,215.80,224.00,True +Task_28,Sonar_Sensor,True,6.75,9.00,True +Task_29,Sonar_Sensor,True,32.48,33.00,True +Task_30,Laser_Sensor,True,2.33,3.00,True +Task_31,Laser_Sensor,True,34.67,37.00,True +Task_32,Laser_Sensor,True,245.00,245.00,True +Task_33,Laser_Sensor,True,5.67,9.00,True +Task_34,Infrared_Sensor,True,6.00,7.00,True +Task_35,Infrared_Sensor,True,24.83,26.00,True +Task_36,Infrared_Sensor,True,46.00,52.00,True +Task_37,Ultraviolet_Sensor,True,10.37,21.00,True +Task_38,Ultraviolet_Sensor,True,2.01,3.00,True +Task_39,Ultraviolet_Sensor,True,30.97,53.00,True +Task_40,Ultraviolet_Sensor,True,56.13,73.00,True +Task_41,Ultraviolet_Sensor,True,15.67,16.00,True +Task_42,Ultraviolet_Sensor,True,614.40,763.00,True +Task_43,Ultraviolet_Sensor,True,193.90,241.00,True +Task_44,Ultraviolet_Sensor,True,32.51,54.00,True +Task_45,Thermal_Sensor,True,9.42,24.00,True +Task_46,Thermal_Sensor,True,5.56,8.00,True +Task_47,Thermal_Sensor,True,76.47,99.00,True +Task_48,Thermal_Sensor,True,25.78,36.00,True +Task_49,Pressure_Sensor,True,5.92,8.00,True +Task_50,Pressure_Sensor,True,1.00,1.00,True +Task_51,Pressure_Sensor,True,17.02,29.00,True +Task_52,Humidity_Sensor,True,73.36,76.00,True +Task_53,Humidity_Sensor,True,219.16,223.00,True +Task_54,Temperature_Sensor,True,4.97,8.00,True +Task_55,Temperature_Sensor,True,48.40,59.00,True +Task_56,Temperature_Sensor,True,158.06,199.00,True +Task_57,Temperature_Sensor,True,5.97,12.00,True +Task_58,Light_Sensor,True,24.42,32.00,True +Task_59,Light_Sensor,True,2.45,12.00,True +Task_60,Light_Sensor,True,56.98,98.00,True diff --git a/data/simulator_outputs/6-gigantic-test-case.csv b/data/simulator_outputs/6-gigantic-test-case.csv new file mode 100644 index 0000000..afd493c --- /dev/null +++ b/data/simulator_outputs/6-gigantic-test-case.csv @@ -0,0 +1,116 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,10.36,11.00,True +Task_1,Camera_Sensor,True,5.00,6.00,True +Task_2,Image_Processor,True,7.26,12.00,True +Task_3,Image_Processor,True,1.00,1.00,True +Task_4,Bitmap_Processor,True,4.00,5.00,True +Task_5,Bitmap_Processor,True,10.72,11.00,True +Task_6,Lidar_Sensor,True,3.69,10.00,True +Task_7,Lidar_Sensor,True,21.26,28.00,True +Task_8,Lidar_Sensor,True,56.26,59.00,True +Task_9,Lidar_Sensor,True,2.37,9.00,True +Task_10,Control_Unit,True,2.27,9.00,True +Task_11,Control_Unit,True,4.80,10.00,True +Task_12,Control_Unit,True,5.55,10.00,True +Task_13,Control_Unit,True,4.26,10.00,True +Task_14,Control_Unit,True,2.62,9.00,True +Task_15,Control_Unit,True,7.14,12.00,True +Task_16,GPS_Sensor,True,48.07,53.00,True +Task_17,GPS_Sensor,True,1.00,1.00,True +Task_18,Communication_Unit,True,1.00,1.00,True +Task_19,Communication_Unit,True,1.00,1.00,True +Task_20,Communication_Unit,True,6.66,12.00,True +Task_21,Communication_Unit,True,11.10,15.00,True +Task_22,Proximity_Sensor,True,16.00,16.00,True +Task_23,Proximity_Sensor,True,1.00,1.00,True +Task_24,Proximity_Sensor,True,1.00,1.00,True +Task_25,Radar_Sensor,True,2.00,2.00,True +Task_26,Radar_Sensor,True,32.02,41.00,True +Task_27,Radar_Sensor,True,128.71,137.00,True +Task_28,Sonar_Sensor,True,18.25,34.00,True +Task_29,Sonar_Sensor,True,54.19,76.00,True +Task_30,Laser_Sensor,True,61.67,65.00,True +Task_31,Laser_Sensor,True,2.50,7.00,True +Task_32,Laser_Sensor,True,19.03,28.00,True +Task_33,Laser_Sensor,True,6.33,8.00,True +Task_34,Infrared_Sensor,True,153.67,159.00,True +Task_35,Infrared_Sensor,True,24.69,31.00,True +Task_36,Infrared_Sensor,True,2.16,5.00,True +Task_37,Ultraviolet_Sensor,True,7.80,12.00,True +Task_38,Ultraviolet_Sensor,True,25.33,45.00,True +Task_39,Ultraviolet_Sensor,True,21.25,37.00,True +Task_40,Ultraviolet_Sensor,True,3.81,9.00,True +Task_41,Ultraviolet_Sensor,True,115.20,145.00,True +Task_42,Ultraviolet_Sensor,True,525.00,575.00,True +Task_43,Ultraviolet_Sensor,True,9.80,12.00,True +Task_44,Ultraviolet_Sensor,True,26.00,49.00,True +Task_45,Thermal_Sensor,False,297.50,371.00,False +Task_46,Thermal_Sensor,True,5.00,5.00,False +Task_47,Thermal_Sensor,False,77.47,118.00,False +Task_48,Thermal_Sensor,False,23.67,31.00,False +Task_49,Pressure_Sensor,True,16.17,19.00,True +Task_50,Pressure_Sensor,True,17.00,19.00,True +Task_51,Pressure_Sensor,True,311.50,331.00,True +Task_52,Humidity_Sensor,True,3.67,4.00,True +Task_53,Humidity_Sensor,True,10.00,10.00,True +Task_54,Temperature_Sensor,True,29.73,49.00,True +Task_55,Temperature_Sensor,True,2.29,11.00,True +Task_56,Temperature_Sensor,True,526.95,532.00,True +Task_57,Temperature_Sensor,True,7.64,18.00,True +Task_58,Light_Sensor,True,2.56,19.00,True +Task_59,Light_Sensor,True,54.43,70.00,True +Task_60,Light_Sensor,True,475.68,485.00,True +Task_61,Sound_Sensor,True,134.39,149.00,True +Task_62,Sound_Sensor,True,41.03,61.00,True +Task_63,Vibration_Sensor,True,30.25,33.00,True +Task_64,Vibration_Sensor,True,24.33,25.00,True +Task_65,Motion_Sensor,True,19.00,19.00,True +Task_66,Motion_Sensor,True,141.24,166.00,True +Task_67,Acceleration_Sensor,True,3.15,13.00,True +Task_68,Acceleration_Sensor,True,4.42,14.00,True +Task_69,Acceleration_Sensor,True,28.26,34.00,True +Task_70,Acceleration_Sensor,True,529.28,543.00,True +Task_71,Gyroscope_Sensor,True,5.03,10.00,True +Task_72,Gyroscope_Sensor,True,1.00,1.00,True +Task_73,Gyroscope_Sensor,True,1.00,1.00,True +Task_74,Gyroscope_Sensor,True,35.33,46.00,True +Task_75,Gyroscope_Sensor,True,21.35,27.00,True +Task_76,Gyroscope_Sensor,True,1.00,1.00,True +Task_77,Magnetometer_Sensor,True,1.00,1.00,True +Task_78,Magnetometer_Sensor,True,17.76,23.00,True +Task_79,Compass_Sensor,True,61.89,74.00,True +Task_80,Compass_Sensor,True,26.00,27.00,True +Task_81,Compass_Sensor,True,26.00,26.00,True +Task_82,Compass_Sensor,True,373.67,374.00,True +Task_83,Altimeter_Sensor,True,78.75,82.00,True +Task_84,Altimeter_Sensor,True,105.33,136.00,True +Task_85,Altimeter_Sensor,True,27.33,28.00,True +Task_86,Barometer_Sensor,True,20.16,25.00,True +Task_87,Barometer_Sensor,True,5.08,7.00,True +Task_88,Barometer_Sensor,True,45.50,46.00,True +Task_89,Hygrometer_Sensor,True,1.00,1.00,True +Task_90,Hygrometer_Sensor,True,95.50,109.00,True +Task_91,Anemometer_Sensor,True,11.00,11.00,False +Task_92,Anemometer_Sensor,True,30.08,31.00,False +Task_93,Anemometer_Sensor,True,5.00,5.00,False +Task_94,Anemometer_Sensor,False,0.00,0.00,False +Task_95,Rain_Gauge_Sensor,True,4.04,5.00,True +Task_96,Rain_Gauge_Sensor,True,17.00,17.00,True +Task_97,Rain_Gauge_Sensor,True,65.00,65.00,True +Task_98,Snow_Gauge_Sensor,True,15.98,25.00,True +Task_99,Snow_Gauge_Sensor,True,79.86,111.00,True +Task_100,Snow_Gauge_Sensor,True,63.69,117.00,True +Task_101,Snow_Gauge_Sensor,True,265.73,379.00,True +Task_102,Snow_Gauge_Sensor,True,20.62,45.00,True +Task_103,Snow_Gauge_Sensor,True,11.08,15.00,True +Task_104,Snow_Gauge_Sensor,True,58.20,92.00,True +Task_105,Snow_Gauge_Sensor,True,54.04,105.00,True +Task_106,Thermometer_Sensor,True,6.00,8.00,True +Task_107,Thermometer_Sensor,True,2.00,2.00,True +Task_108,Thermometer_Sensor,True,81.00,81.00,True +Task_109,Thermometer_Sensor,True,10.67,13.00,True +Task_110,Pyrometer_Sensor,True,17.36,19.00,True +Task_111,Pyrometer_Sensor,True,145.07,204.00,True +Task_112,Pyrometer_Sensor,True,30.40,61.00,True +Task_113,Photometer_Sensor,True,54.53,60.00,True +Task_114,Photometer_Sensor,True,20.94,27.00,True diff --git a/data/simulator_outputs/7-unschedulable-test-case.csv b/data/simulator_outputs/7-unschedulable-test-case.csv new file mode 100644 index 0000000..5b6ce99 --- /dev/null +++ b/data/simulator_outputs/7-unschedulable-test-case.csv @@ -0,0 +1,22 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,44.00,49.00,True +Task_1,Camera_Sensor,True,1.00,1.00,True +Task_2,Camera_Sensor,True,5.00,5.00,True +Task_3,Camera_Sensor,True,211.00,211.00,True +Task_4,Image_Processor,True,1.00,1.00,True +Task_5,Image_Processor,True,2.00,2.00,True +Task_6,Lidar_Sensor,False,24.10,26.00,False +Task_7,Lidar_Sensor,False,2.00,2.00,False +Task_8,Lidar_Sensor,False,140.00,140.00,False +Task_9,Lidar_Sensor,False,0.00,0.00,False +Task_10,Lidar_Sensor,False,0.00,0.00,False +Task_11,Lidar_Sensor,False,2.00,2.00,False +Task_12,GPS_Sensor,True,4.42,5.00,True +Task_13,GPS_Sensor,True,41.00,41.00,True +Task_14,Communication_Unit,True,3.92,8.00,True +Task_15,Communication_Unit,True,76.21,77.00,True +Task_16,Communication_Unit,True,5.42,15.00,True +Task_17,Communication_Unit,True,3.69,13.00,True +Task_18,Proximity_Sensor,True,34.00,36.00,True +Task_19,Proximity_Sensor,True,228.25,229.00,True +Task_20,Proximity_Sensor,True,1.00,1.00,True diff --git a/data/simulator_outputs/8-unschedulable-test-case.csv b/data/simulator_outputs/8-unschedulable-test-case.csv new file mode 100644 index 0000000..0c11a28 --- /dev/null +++ b/data/simulator_outputs/8-unschedulable-test-case.csv @@ -0,0 +1,29 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,2.33,3.00,True +Task_1,Camera_Sensor,True,24.00,26.00,True +Task_2,Camera_Sensor,True,2.17,6.00,True +Task_3,Camera_Sensor,True,2.42,5.00,True +Task_4,Camera_Sensor,True,2.62,7.00,True +Task_5,Image_Processor,True,2.21,5.00,True +Task_6,Image_Processor,True,2.23,6.00,True +Task_7,Image_Processor,True,2.17,3.00,True +Task_8,Bitmap_Processor,True,15.08,22.00,False +Task_9,Bitmap_Processor,True,43.00,50.00,False +Task_10,Bitmap_Processor,True,6.29,8.00,False +Task_11,Bitmap_Processor,False,0.00,0.00,False +Task_12,Lidar_Sensor,False,14.20,19.00,False +Task_13,Lidar_Sensor,True,4.00,4.00,False +Task_14,Lidar_Sensor,False,0.00,0.00,False +Task_15,Lidar_Sensor,False,0.00,0.00,False +Task_16,Control_Unit,True,2.67,3.00,False +Task_17,Control_Unit,True,2.33,3.00,False +Task_18,Control_Unit,True,5.00,6.00,False +Task_19,Control_Unit,True,26.67,27.00,False +Task_20,Control_Unit,False,0.00,0.00,False +Task_21,Control_Unit,True,4.00,4.00,False +Task_22,GPS_Sensor,True,28.58,33.00,True +Task_23,GPS_Sensor,True,3.83,9.00,True +Task_24,Communication_Unit,True,2.50,4.00,True +Task_25,Communication_Unit,True,41.00,41.00,True +Task_26,Communication_Unit,True,249.00,249.00,True +Task_27,Communication_Unit,True,2.00,2.00,True diff --git a/data/simulator_outputs/9-unschedulable-test-case.csv b/data/simulator_outputs/9-unschedulable-test-case.csv new file mode 100644 index 0000000..254a83d --- /dev/null +++ b/data/simulator_outputs/9-unschedulable-test-case.csv @@ -0,0 +1,62 @@ +Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable +Task_0,Camera_Sensor,True,7.00,7.00,True +Task_1,Camera_Sensor,True,43.00,43.00,True +Task_2,Image_Processor,True,28.33,30.00,True +Task_3,Image_Processor,True,50.00,52.00,True +Task_4,Bitmap_Processor,True,33.22,37.00,True +Task_5,Bitmap_Processor,True,219.00,219.00,True +Task_6,Lidar_Sensor,True,50.50,52.00,True +Task_7,Lidar_Sensor,True,1.00,1.00,True +Task_8,Lidar_Sensor,True,3.75,4.00,True +Task_9,Lidar_Sensor,True,109.00,109.00,True +Task_10,Control_Unit,True,1.00,1.00,True +Task_11,Control_Unit,True,12.81,16.00,True +Task_12,Control_Unit,True,16.83,45.00,True +Task_13,Control_Unit,True,11.44,17.00,True +Task_14,Control_Unit,True,86.00,155.00,True +Task_15,Control_Unit,True,34.38,71.00,True +Task_16,GPS_Sensor,True,1.00,1.00,True +Task_17,GPS_Sensor,True,11.00,11.00,True +Task_18,Communication_Unit,True,1.00,1.00,True +Task_19,Communication_Unit,True,1.00,1.00,True +Task_20,Communication_Unit,True,29.67,30.00,True +Task_21,Communication_Unit,True,1.00,1.00,True +Task_22,Proximity_Sensor,True,1.00,1.00,True +Task_23,Proximity_Sensor,True,25.11,28.00,True +Task_24,Proximity_Sensor,True,2.78,9.00,True +Task_25,Radar_Sensor,True,1.00,1.00,True +Task_26,Radar_Sensor,True,58.25,66.00,True +Task_27,Radar_Sensor,True,219.92,225.00,True +Task_28,Sonar_Sensor,True,6.75,9.00,True +Task_29,Sonar_Sensor,True,32.42,33.00,True +Task_30,Laser_Sensor,True,2.33,3.00,True +Task_31,Laser_Sensor,True,34.67,37.00,True +Task_32,Laser_Sensor,True,248.00,248.00,True +Task_33,Laser_Sensor,True,5.50,8.00,True +Task_34,Infrared_Sensor,True,6.00,7.00,True +Task_35,Infrared_Sensor,True,8.17,16.00,True +Task_36,Infrared_Sensor,True,46.00,52.00,True +Task_37,Ultraviolet_Sensor,True,2.31,11.00,True +Task_38,Ultraviolet_Sensor,True,2.22,10.00,True +Task_39,Ultraviolet_Sensor,True,27.67,54.00,True +Task_40,Ultraviolet_Sensor,True,51.83,60.00,True +Task_41,Ultraviolet_Sensor,True,14.94,16.00,True +Task_42,Ultraviolet_Sensor,True,593.50,737.00,True +Task_43,Ultraviolet_Sensor,True,185.50,225.00,True +Task_44,Ultraviolet_Sensor,True,32.33,57.00,True +Task_45,Thermal_Sensor,True,9.67,22.00,True +Task_46,Thermal_Sensor,True,2.08,5.00,True +Task_47,Thermal_Sensor,True,77.72,99.00,True +Task_48,Thermal_Sensor,True,21.33,38.00,True +Task_49,Pressure_Sensor,True,1.00,1.00,True +Task_50,Pressure_Sensor,True,1.00,1.00,True +Task_51,Pressure_Sensor,True,22.00,22.00,True +Task_52,Humidity_Sensor,True,73.47,77.00,True +Task_53,Humidity_Sensor,True,109.50,115.00,True +Task_54,Temperature_Sensor,True,2.33,6.00,False +Task_55,Temperature_Sensor,True,50.72,55.00,False +Task_56,Temperature_Sensor,False,0.00,0.00,False +Task_57,Temperature_Sensor,True,2.30,6.00,False +Task_58,Light_Sensor,True,24.56,28.00,True +Task_59,Light_Sensor,True,2.68,13.00,True +Task_60,Light_Sensor,True,54.67,62.00,True diff --git a/docs/simulator-example.md b/docs/simulator-example.md new file mode 100644 index 0000000..bb950f6 --- /dev/null +++ b/docs/simulator-example.md @@ -0,0 +1,28 @@ +# Example Walkthrough + +## Initial Setup + +**Core_1 (EDF)** contains two components: + +1. **Image_Processor** + - Budget: 2/6 + - Running: Task_5 (WCET=3) + +2. **Camera_Sensor** + - Budget: 5/9 + - Running: Task_1 (WCET=7) + +## Timeline Events + +| Time | Event | Image_Processor | Camera_Sensor | Core Action | +|------|-------|-----------------|---------------|-------------| +| 0 | Image_Processor starts | budget: 2 → 1 | - | Runs Task_5 (1 unit) | +| 1 | Image_Processor continues | budget: 1 → 0 | - | Runs Task_5 (1 unit) | +| 2 | Image_Processor budget exhausted | Blocked | budget: 5 → 4 | Switches to Camera_Sensor | +| 3-6 | Camera_Sensor execution | - | budget: 4 → 0 | Task_1 paused (4/7 complete) | +| 6 | Image_Processor period reset | New budget: 2 | Blocked | Image_Processor resumes | + +## Key Events + +- **Time 2**: Image_Processor depletes its 2-unit budget and becomes blocked. Camera_Sensor takes control. +- **Time 6**: Image_Processor's period resets (6/6), receiving fresh budget and preempting current execution. \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/analysis.py b/src/analysis.py index 564c68e..7a1a36a 100644 --- a/src/analysis.py +++ b/src/analysis.py @@ -16,8 +16,8 @@ def lcm(a: int, b: int) -> int: def adjust_wcet(tasks, budgets, architectures): # Adjust WCET by core speed factor (scaling per architecture) - core_speed_map = {arch.core_id: arch.speed_factor for arch in architectures} - component_core_map = {budget.component_id: budget.core_id for budget in budgets} + core_speed_map = {arch.id: arch.speed_factor for arch in architectures} + component_core_map = {budget.id: budget.core_id for budget in budgets} for task in tasks: core_id = component_core_map[task.component_id] task.wcet = task.wcet / core_speed_map[core_id] @@ -28,7 +28,7 @@ def group_tasks_by_component(tasks, budgets): # Group tasks into their components based on budgets.csv components = {} for budget in budgets: - comp_id = budget.component_id + comp_id = budget.id comp_tasks = [t for t in tasks if t.component_id == comp_id] # Sort for RM priority order if budget.scheduler == Scheduler.RM: @@ -118,7 +118,7 @@ def summarize_by_core(components, architectures): - Also ensure each component passed its local schedulability check """ # Group components per core - core_map = {arch.core_id: [] for arch in architectures} + core_map = {arch.id: [] for arch in architectures} for comp in components.values(): core_map[comp['core_id']].append(comp) @@ -173,7 +173,7 @@ def write_solution_csv(tasks, components, filename='solution.csv'): # noqa: E30 else: demand = DBF.dbf_edf(comp['tasks'], task.period) # Eq.2 rows.append({ - 'task_name': task.task_name, + 'task_name': task.id, 'component_id': cid, 'task_schedulable': int(demand <= supply.sbf(task.period)), 'component_schedulable': int(comp['schedulable']) diff --git a/src/common/architecture.py b/src/common/architecture.py deleted file mode 100644 index 28c3a4a..0000000 --- a/src/common/architecture.py +++ /dev/null @@ -1,9 +0,0 @@ -from dataclasses import dataclass - -from common.scheduler import Scheduler - -@dataclass -class Architecture: - core_id:int - speed_factor:float - scheduler: Scheduler diff --git a/src/common/budget.py b/src/common/budget.py deleted file mode 100644 index 8cd2596..0000000 --- a/src/common/budget.py +++ /dev/null @@ -1,12 +0,0 @@ -from dataclasses import dataclass - -from common.scheduler import Scheduler - -@dataclass -class Budget: - component_id: str - scheduler:Scheduler - budget:float - period:float - core_id:int - priority:int|None diff --git a/src/common/component.py b/src/common/component.py new file mode 100644 index 0000000..082fd66 --- /dev/null +++ b/src/common/component.py @@ -0,0 +1,27 @@ +from common.scheduler import Scheduler + +class Component: + """ + Stores the budget and timing settings for a component in the system. The budget + controls how long a component can run, similar to a time allowance. + + Attributes: + component_id (str): Name/ID of the component (example: "Camera1") + scheduler (Scheduler): How tasks are ordered - either EDF or RM scheduling + budget (int): How long the component can run (in time units) before it must pause + period (int): How often the runtime budget refreshes (in time units) + core_id (int): Which CPU core this component runs on + priority (int | None): How important this component is compared to others + (used for RM scheduling, None for EDF) + Lower number means higher priority + """ + def __init__(self, component_id: str, scheduler: Scheduler, budget: int, + period: int, core_id: int, priority: int | None): + self.id = component_id + self.scheduler = scheduler + self.budget = budget + self.period = period + self.core_id = core_id + self.priority = priority + self.remaining_budget = budget + self.jobs_queue = [] diff --git a/src/common/core.py b/src/common/core.py new file mode 100644 index 0000000..7ba0a37 --- /dev/null +++ b/src/common/core.py @@ -0,0 +1,19 @@ +from dataclasses import dataclass + +from common.scheduler import Scheduler + +@dataclass +class Core: + """ + A class representing a processing core architecture with its properties and scheduling capabilities. + Attributes: + core_id (int): The unique identifier for the core. + speed_factor (float): A numerical value representing the core's speed relative to a nominal speed. + 1.0 represents the nominal speed. A value of 0.5 indicates a core that is 50% slower, + and a value of 1.2 indicates a core that is 20% faster. The WCET of tasks assigned to + a core must be adjusted by dividing the nominal WCET by the speed_factor. + scheduler (Scheduler): The scheduler instance responsible for managing task execution on this core. + """ + id:int + speed_factor:float + scheduler: Scheduler diff --git a/src/common/csvoutput.py b/src/common/csvoutput.py new file mode 100644 index 0000000..90af83a --- /dev/null +++ b/src/common/csvoutput.py @@ -0,0 +1,53 @@ +import csv +from typing import List, Dict, Optional +from dataclasses import dataclass + +@dataclass +class TaskResult: + task_name: str + component_id: str + task_schedulable: bool + avg_response_time: float + max_response_time: float + component_schedulable: bool + +class CSVOutput: + def __init__(self, filename: str): + self.filename = filename + self.headers = [ + 'task_name', + 'component_id', + 'task_schedulable', + 'avg_response_time', + 'max_response_time', + 'component_schedulable' + ] + self.results: List[TaskResult] = [] + + def add_task_result(self, result: TaskResult) -> None: + """Add a single task result to the collection.""" + self.results.append(result) + + def add_multiple_results(self, results: List[TaskResult]) -> None: + """Add multiple task results at once.""" + self.results.extend(results) + + def write_results(self) -> None: + """Write all results to the CSV file.""" + with open(self.filename, 'w', newline='') as csvfile: + writer = csv.DictWriter(csvfile, fieldnames=self.headers) + writer.writeheader() + + for result in self.results: + writer.writerow({ + 'task_name': result.task_name, + 'component_id': result.component_id, + 'task_schedulable': 1 if result.task_schedulable else 0, + 'avg_response_time': result.avg_response_time, + 'max_response_time': result.max_response_time, + 'component_schedulable': 1 if result.component_schedulable else 0 + }) + + def clear_results(self) -> None: + """Clear all stored results.""" + self.results.clear() \ No newline at end of file diff --git a/src/common/csvreader.py b/src/common/csvreader.py index 5c36230..0fecf8b 100644 --- a/src/common/csvreader.py +++ b/src/common/csvreader.py @@ -2,13 +2,13 @@ import os import sys -from common.architecture import Architecture -from common.budget import Budget +from common.core import Core +from common.component import Component from common.task import Task from common.scheduler import Scheduler from common.utils import get_project_root -def read_architectures(csv:str)-> list[Architecture]: +def read_cores(csv:str) -> list[Core]: """ Reads the architecture information from a CSV file and returns a list of Architecture objects. @@ -24,8 +24,8 @@ def read_architectures(csv:str)-> list[Architecture]: architectures = [] for _, row in df.iterrows(): - architecture = Architecture( - core_id=row['core_id'], + architecture = Core( + id=row['core_id'], speed_factor=row['speed_factor'], scheduler=Scheduler[row['scheduler']] ) @@ -33,14 +33,14 @@ def read_architectures(csv:str)-> list[Architecture]: return architectures -def read_budgets(csv:str)-> list[Budget]: +def read_budgets(csv:str) -> list[Component]: csv = _get_csv_path(csv) df = pd.read_csv(csv) budgets = [] for _,row in df.iterrows(): - budget = Budget( + budget = Component( component_id=row['component_id'], scheduler=Scheduler[row['scheduler']], budget=row['budget'], @@ -52,7 +52,7 @@ def read_budgets(csv:str)-> list[Budget]: return budgets -def read_tasks(csv:str)-> list[Task]: +def read_tasks(csv:str) -> list[Task]: csv = _get_csv_path(csv) df = pd.read_csv(csv) @@ -61,16 +61,30 @@ def read_tasks(csv:str)-> list[Task]: for _,row in df.iterrows(): task = Task( task_name=row['task_name'], - wcet=(row['wcet']), - period=(row['period']), + wcet=row['wcet'], + period=row['period'], component_id=row['component_id'], - priority=row['priority'], + priority=row['priority'] ) tasks.append(task) return tasks -def read_csv() -> tuple[list[Architecture], list[Budget], list[Task]]: +def _get_csv_path(csv:str) -> str: + if os.path.exists(csv): + return csv + + csv = os.path.join(get_project_root(),csv) + if os.path.exists(csv): + return csv + + raise FileNotFoundError( + f"File {csv} does not exist. " + "Pass to the function an absolute path or a relative path from the project root. " + "For example 'data/testcases/1-tiny-test-case/architecture.csv", csv + ) + +def read_csv() -> tuple[list[Core], list[Component], list[Task]]: if len(sys.argv) != 4: print("Usage: python analysis.py ") sys.exit(1) @@ -80,7 +94,7 @@ def read_csv() -> tuple[list[Architecture], list[Budget], list[Task]]: tasks_file = sys.argv[3] try: - architectures = read_architectures(architecture_file) + architectures = read_cores(architecture_file) budgets = read_budgets(budget_file) tasks = read_tasks(tasks_file) @@ -91,18 +105,4 @@ def read_csv() -> tuple[list[Architecture], list[Budget], list[Task]]: print(f"Error processing files: {e}") sys.exit(1) - return architectures, budgets, tasks - -def _get_csv_path(csv:str) -> str: - if os.path.exists(csv): - return csv - - csv = os.path.join(get_project_root(),csv) - if os.path.exists(csv): - return csv - - raise FileNotFoundError( - f"File {csv} does not exist. " - "Pass to the function an absolute path or a relative path from the project root. " - "For example 'data/testcases/1-tiny-test-case/architecture.csv" - ) \ No newline at end of file + return architectures, budgets, tasks \ No newline at end of file diff --git a/src/common/job.py b/src/common/job.py new file mode 100644 index 0000000..abdee7d --- /dev/null +++ b/src/common/job.py @@ -0,0 +1,23 @@ +class Job: + def __init__(self, task, release_time: int, execution_time: float): + self.id = f"{task.id}_{release_time}" + self.task_id = task.id + self.priority = task.priority + self.release_time: int = release_time + self.execution_time: float = execution_time + self.remaining_time: float = execution_time + self.absolute_deadline: int = release_time + task.period + self.execution_time * 0.0001 # Tie-breaker + self.start_time: int = -1 + + # Make it sortable for priority queues if needed (e.g., for EDF) + def __lt__(self, other): + # Example for EDF: earlier deadline is higher priority + if self.absolute_deadline != other.absolute_deadline: + return self.absolute_deadline < other.absolute_deadline + # Tie-breaking (e.g., by original task priority if RM, or by release time) + # For pure EDF, could be arbitrary or based on task ID for determinism + return self.task_template.priority < other.task_template.priority # Assuming lower prio number is higher + + def __repr__(self): + return (f"Job(id={self.id}, task={self.task_template.id}, release={self.release_time}, " + f"deadline={self.absolute_deadline}, rem={self.remaining_time:.2f})") \ No newline at end of file diff --git a/src/common/scheduler.py b/src/common/scheduler.py index 463763c..657a0b0 100644 --- a/src/common/scheduler.py +++ b/src/common/scheduler.py @@ -1,5 +1,7 @@ from enum import Enum +from common.task import Task + class Scheduler(Enum): RM = "Rate Monotonic" EDF = "Earliest Deadline First" diff --git a/src/common/task.py b/src/common/task.py index b92f52a..727a821 100644 --- a/src/common/task.py +++ b/src/common/task.py @@ -1,11 +1,22 @@ -from dataclasses import dataclass - -@dataclass class Task: - task_name:str - wcet:float - period:float - component_id:str - priority:int|None - + def __init__(self, task_name: str, wcet: int, period: int, component_id: str, priority: int | None): + self.id = task_name + self.wcet = wcet + self.period = period + self.component_id = component_id + self.priority = priority + self.release_time = 0 + self.remaining_time = self.wcet + + + def __eq__(self, other): + if not isinstance(other, Task): + return NotImplemented + return (self.id == other.id and + self.wcet == other.wcet and + self.period == other.period and + self.component_id == other.component_id and + self.priority == other.priority) + def __repr__(self): + return f"Task(task_name='{self.id}', wcet={self.wcet}, period={self.period}, component_id='{self.component_id}', priority={self.priority})" \ No newline at end of file diff --git a/src/common/utils.py b/src/common/utils.py index ff1f837..1170651 100644 --- a/src/common/utils.py +++ b/src/common/utils.py @@ -4,4 +4,10 @@ def get_project_root() -> str: """ Get the root directory of the project. """ - return os.path.dirname(os.path.dirname(os.path.abspath(__file__))) \ No newline at end of file + + current_file = os.path.abspath(__file__) + common_dir = os.path.dirname(current_file) + src_dir = os.path.dirname(common_dir) + project_root = os.path.dirname(src_dir) + + return project_root \ No newline at end of file diff --git a/src/simulator.py b/src/simulator.py index e72531a..7479248 100644 --- a/src/simulator.py +++ b/src/simulator.py @@ -1,13 +1,401 @@ -from common.csvreader import read_architectures +import random as rand +import numpy as np + +from common.csvreader import read_cores +from common.csvreader import read_budgets +from common.csvreader import read_tasks +from common.component import Component +from common.scheduler import Scheduler +from common.core import Core +from common.task import Task +from common.job import Job +from common.csvoutput import TaskResult + +CLOCK_TICK = 1 +SIMULATION_ITERATIONS = 10 +LOWER_BOUND_PERCENTAGE = 1 + +class Simulator: + def __init__(self, cores:Core, components:Component, tasks:Task): + self.cores:list[Core] = cores + self.tasks:list[Task] = tasks + self.components:list[Component] = components + self._adjust_task_wcet() + + self.task_start_times: dict[str, float] = {} # task_id -> start time + self.task_response_times: dict[str, list[float]] = {} # task_id -> list of response times + self.task_deadlines: dict[str, list[bool]] = {} # task_id -> list of deadline met flags + + for task in self.tasks: + self.task_start_times[task.id] = 0 + self.task_response_times[task.id] = [] + self.task_deadlines[task.id] = [] + + def run(self): + print("Running simulation...") + + t = 0 # Simulation time in us + + # Initialize response time tracking + for task in self.tasks: + self.task_response_times[task.id] = [] + self.task_deadlines[task.id] = [] + + simulation_iteration = 0 + hyperperiod = self._get_hyperperiod() + + while simulation_iteration < SIMULATION_ITERATIONS: + # Progress tracking every 10,000 iterations + if t % 10_000 == 0: + progress = (t % hyperperiod) / hyperperiod * 100 + print(f"Time: {t}, Progress: {progress:.2f}%") + + # --- Phase 1 Release tasks --- + for task in self.tasks: + if t % task.period == 0: + self.release_task(t, task) + + # --- Phase 2: Reset budgets --- + for component in self.components: + if t % component.period == 0: + component.remaining_budget = component.budget + + # --- Phase 3: Core-level scheduling --- + for core in self.cores: + eligible_components = [ + c for c in self.components + if c.core_id == core.id and c.remaining_budget > 0 and len(c.jobs_queue) > 0 + ] + + if not eligible_components: + continue + + if core.scheduler == Scheduler.EDF: + next_component = min( + eligible_components, + key=lambda c: c.jobs_queue[0].absolute_deadline + ) + elif core.scheduler == Scheduler.RM: + next_component = min(eligible_components, key=lambda c: c.priority) + else: + next_component = None + + job_to_run = next_component.jobs_queue[0] + + if job_to_run.remaining_time == job_to_run.execution_time: + job_to_run.start_time = t + + job_to_run.remaining_time -= CLOCK_TICK + + if job_to_run.remaining_time <= 0: + response_time = (t + CLOCK_TICK) - job_to_run.start_time + self.task_response_times[job_to_run.task_id].append(response_time) + self.task_deadlines[job_to_run.task_id].append(t <= job_to_run.absolute_deadline) + _ = next_component.jobs_queue.pop(0) + next_component.remaining_budget -= CLOCK_TICK + + if t != 0 and t % hyperperiod == 0: + print(f"\nIteration {simulation_iteration} completed!") + print(f"Summary:") + print(f"- Total time steps: {t}") + print(f"- Hyperperiod: {hyperperiod}") + print("-" * 50) + simulation_iteration += 1 + t = 0 + self._clear_component_queues() + else: + t += CLOCK_TICK + + print("-" * 50) + print(f"Simulation finished. Total simulation time: {t}") + print("-" * 50) + + def generate_output_file(self, filename: str): + """Generate a CSV output file with task simulation results. + + Args: + filename: Path to the output CSV file + """ + task_results = self.get_task_results() + + # Create CSV file + with open(filename, 'w') as f: + # Write header + f.write("Task,Component,Task Schedulable,Avg Response Time,Max Response Time,Component Schedulable\n") + + # Write data for each task + for result in task_results: + f.write(f"{result.task_name},{result.component_id},{result.task_schedulable}," + f"{result.avg_response_time:.2f},{result.max_response_time:.2f}," + f"{result.component_schedulable}\n") + + def _release_jobs_if_due(self, current_time: int): + """ + Checks all task templates and releases new jobs if their period is met. + Args: + current_time: The current simulation time (t). + """ + for task in self.tasks: # self.tasks stores Task templates + if current_time % task.period == 0: + # 1. Get the component for this task template + component = next( + (c for c in self.components if c.id == task.component_id), + None + ) + if not component: + raise(f"Warning: Component {task.component_id} not found for task {task.id}") + + actual_execution_time = self._generate_execution_time(task) + new_job = Job(task, current_time, actual_execution_time) + self._schedule(component, new_job) # Assuming _schedule_job takes (Component, Job) + + def _adjust_task_wcet(self): + """ + Adjust the WCET of tasks based on the speed factor of the core they are assigned to. + """ + for component in self.components: + core = next((c for c in self.cores if c.id == component.core_id), None) + if not core: + continue + + for task in self.tasks: + if task.component_id != component.id: + continue + + # Adjust WCET based on the speed factor of the core + task.wcet = task.wcet / core.speed_factor + task.remaining_time = task.wcet + + def _clear_component_queues(self): + """ + Clear the task queues of all components. + """ + for component in self.components: + component.jobs_queue.clear() + component.remaining_budget = component.budget + + def _generate_execution_time(self, task:Task): + """ + Generate execution time for each task based on its WCET and the speed factor of the core. + """ + # Avionics (DO-178C): Typically ≥80% to ensure strict deadline guarantees. + lower_bound = task.wcet * LOWER_BOUND_PERCENTAGE + return self._generate_normal_exec_time(lower_bound, task.wcet) + + def _generate_normal_exec_time(self,lower_bound, wcet): + """ + Generate execution time following a normal distribution bounded between WCET and lower_bound. + + The function uses a normal distribution with: + - mean: average of WCET and lower_bound ((wcet + lower_bound)/2) + - standard deviation: (wcet - lower_bound)/6 to ensure ~99.7% of values fall within ±3σ + + The while loop ensures the generated execution time stays within the specified bounds + by rejecting and regenerating values that fall outside [lower_bound, wcet]. + + Parameters + ---------- + wcet : float + Worst Case Execution Time - upper bound for execution time + lower_bound : float + Minimum possible execution time - lower bound + + Returns + ------- + float + A randomly generated execution time that follows a normal distribution + and falls between lower_bound and wcet inclusive + + Notes + ----- + - Using (wcet - lower_bound)/6 as std dev ensures most values (~99.7%) + fall within the desired range, minimizing rejections in the while loop + - The distribution is symmetrical around the mean, creating a bell curve + between lower_bound and wcet + """ + mean = (wcet + lower_bound) / 2 + std_dev = (wcet - lower_bound) / 6 + while True: # Ensure value stays within bounds + exec_time = np.random.normal(mean, std_dev) + if lower_bound <= exec_time <= wcet: + return exec_time + + def _is_core_empty(self, core_id): + """ + Check if all components assigned to the specified core have empty task queues. + + Args: + core_id: The ID of the core to check + + Returns: + bool: True if no tasks remain for any component on this core, False otherwise + """ + return all( + len(component.jobs_queue) == 0 + for component in self.components + if component.core_id == core_id + ) + + def release_task(self, t: int, task: Task): + """Releases a single task if its period is met.""" + component = next(c for c in self.components if c.id == task.component_id) + existing_job = next( + (j for j in component.jobs_queue if j.task_id == task.id), + None + ) + if existing_job: + self.task_deadlines[task.id].append( + t <= existing_job.absolute_deadline and + existing_job.remaining_time <= 0 + ) + + execution_time = self._generate_execution_time(task) + job = Job(task, t, execution_time) + job.release_time = t + # component = next(c for c in self.components if c.id == task.component_id) # Already found + self._schedule(t, component, job) + + def _schedule(self, current_time: int, component: Component, job: Job): + """ + Schedule the tasks for a given component based on its scheduling policy. + First removes any existing instance of the task from queue before scheduling new instance. + + Args: + current_time: Current simulation time + component: The component whose tasks are to be scheduled + task: Task to be scheduled + """ + # Remove existing instance of task if present + component.jobs_queue = [j for j in component.jobs_queue if j.task_id != job.task_id] + + insert_idx = 0 + match component.scheduler: + case Scheduler.RM: + # Rate Monotonic: Insert based on priority (lower value = higher priority) + for idx, queue_job in enumerate(component.jobs_queue): + if job.priority > queue_job.priority: + insert_idx = idx + 1 + case Scheduler.EDF: + deadline_new = job.absolute_deadline + + insert_idx = 0 + for idx, queue_job in enumerate(component.jobs_queue): + deadline_queued = queue_job.absolute_deadline + if deadline_new > deadline_queued: + insert_idx = idx + 1 + case _: + raise ValueError(f"Unknown scheduling policy: {component.scheduler}") + + component.jobs_queue.insert(insert_idx, job) + + def get_task_results(self) -> list[TaskResult]: + """Get the simulation results for all tasks. + + Returns: + List[TaskResult]: Results for each task including response times and schedulability. + """ + results = [] + for task in self.tasks: + response_times = self.task_response_times.get(task.id, []) + deadline_flags = self.task_deadlines.get(task.id, []) + + if response_times: + avg_response = sum(response_times) / len(response_times) + max_response = max(response_times) + # Task is schedulable only if ALL instances met their deadlines + task_schedulable = all(deadline_flags) + else: + avg_response = 0.0 + max_response = 0.0 + task_schedulable = False + + # Get component for this task + component = next(c for c in self.components if c.id == task.component_id) + + # A component is schedulable if all its tasks are schedulable + component_tasks = [t for t in self.tasks if t.component_id == component.id] + component_schedulable = all( + all(self.task_deadlines.get(t.id, [])) + for t in component_tasks + ) + + results.append(TaskResult( + task_name=task.id, + component_id=task.component_id, + task_schedulable=task_schedulable, + avg_response_time=avg_response, + max_response_time=max_response, + component_schedulable=component_schedulable + )) + + return results + + def _get_hyperperiod(self): + """Calculate the system hyperperiod hierarchically. + First calculates the hyperperiod (LCM) of tasks within each component, + then calculates the LCM of all component hyperperiods. + + Example: + Component1 has tasks with periods [2,3] -> LCM = 6 + Component2 has tasks with periods [2,4] -> LCM = 4 + System hyperperiod = LCM(6,4) = 12 + + Returns: + int: The hyperperiod value for the entire system + """ + # Calculate hyperperiod for each component + component_hyperperiods = [] + for component in self.components: + # Get all tasks for this component + component_tasks = [task for task in self.tasks if task.component_id == component.id] + if not component_tasks: + # If component has no tasks, use its own period + component_hyperperiods.append(component.period) + continue + + # Calculate LCM of task periods within this component + task_periods = [task.period for task in component_tasks] + component_lcm = task_periods[0] + for period in task_periods[1:]: + component_lcm = (component_lcm * period) // np.gcd(component_lcm, period) + component_hyperperiods.append(component_lcm) + + # Calculate system hyperperiod as LCM of component hyperperiods + system_hyperperiod = component_hyperperiods[0] + for period in component_hyperperiods[1:]: + system_hyperperiod = (system_hyperperiod * period) // np.gcd(system_hyperperiod, period) + + return system_hyperperiod def main(): - # Example usage - csv_path = 'data/testcases/1-tiny-test-case/architecture.csv' - architectures = read_architectures(csv_path) - for architecture in architectures: - print(architecture) + # Base path for test case files + base_path = 'data/testcases/10-unschedulable-test-case' + + # Read architectures + architecture_path = f'{base_path}/architecture.csv' + cores = read_cores(architecture_path) + print("Architectures:") + for core in cores: + print(core) + + # Read tasks + tasks_path = f'{base_path}/tasks.csv' + tasks = read_tasks(tasks_path) + print("\nTasks:") + for task in tasks: + print(task) + + # Read components + budgets_path = f'{base_path}/budgets.csv' + components = read_budgets(budgets_path) + print("\nBudgets:") + for component in components: + print(component) + + simulator = Simulator(cores, components, tasks) + simulator.run() - + simulator.generate_output_file("output.csv") if __name__ == "__main__": main() \ No newline at end of file diff --git a/tests/test_simulator.py b/tests/test_simulator.py new file mode 100644 index 0000000..9119514 --- /dev/null +++ b/tests/test_simulator.py @@ -0,0 +1,27 @@ +import sys +from pathlib import Path + +from src.simulator import Simulator +from src.common.csvreader import read_cores, read_budgets, read_tasks + +def test_simulator_tiny_case(): + cores = read_cores("data/testcases/1-tiny-test-case/architecture.csv") + budgets = read_budgets("data/testcases/1-tiny-test-case/budgets.csv") + tasks = read_tasks("data/testcases/1-tiny-test-case/tasks.csv") + + # Initialize simulator + simulator = Simulator(cores, budgets, tasks) + + # Run simulation + simulator.run() + + # Get results + results = simulator.get_task_results() + + # Assert expected values + # These values should match your tiny test case expected outcomes + assert len(results) > 0 + # Example assertions (adjust according to your actual test data): + + + \ No newline at end of file