--- tags: Real-Time title: Group stuff author: PH Chou, YA Chen, YW Tung. --- # Meeting Link: ## Google meet: [Link](https://meet.google.com/vjk-ikpa-ofj) vjk-ikpa-ofj ## Overleaf ### Assignment 4: [Link](https://www.overleaf.com/9278639295qjwnkypmkvwj) # ### Problem #4 in Assignment #1 (Submit) [@StackOverFlow](https://stackoverflow.com/questions/68315025/how-to-implement-multi-producer-multi-consumer-single-buffer-model) # Assignment #1 (Incomplete) ## Problem-3 ```= with Ada.Text_IO; use Ada.Text_IO; with Ada.Calendar; use Ada.Calendar; with Ada.Numerics.Discrete_Random; procedure comm1 is Message: constant String := "Process communication"; Flag_accept : Boolean := False; Queue_counter : Integer := 0; task buffer is -- add your task entries for communication entry Put(X:in Integer); entry Get(X:out Integer); entry Stop; end buffer; task producer is -- add your task entries for communication entry Stop; end producer; task consumer is -- add your task entries for communication end consumer; task body buffer is Message: constant String := "buffer executing"; -- change/add your local declarations here front : Integer := -1; rear : Integer := -1; --buffer size setting: size : Integer := 20; queue : array (0..size) of integer; total_queue : integer := 0; Buffer_Flag : Boolean := False; begin Put_Line(Message); loop -- add your task code inside this loop select accept Put(X:Integer) do --design buffer is a circular buffer. if (front = 0 and rear = (size-1)) or (rear = (front-1) rem (size-1)) then Put_line("Queue is Full."); --Set flag false Flag_accept := False; elsif (front = -1) then --first time input --clear the array first for index in queue'Range loop queue(index) := 0; end loop; front := 0; rear := 0; queue(rear) := X; total_queue := total_queue + queue(rear); --C++ Queue_counter := Queue_counter + 1; --set flag if is not empty Flag_accept := True; elsif (rear = (size-1) and front /= 0) then rear := 0; queue(rear) := X; total_queue := total_queue + queue(rear); --C++ Queue_counter := Queue_counter + 1; --set flag if is not empty Flag_accept := True; else rear := rear + 1; queue(rear) := X; total_queue := total_queue + queue(rear); --C++ Queue_counter := Queue_counter + 1; --set flag if is not empty Flag_accept := True; end if; --display queue for debug for index in queue'Range loop Put(queue(index)'Img); null; end loop; New_line; if total_queue>0 then Buffer_Flag:=True; end if; end; or accept Get(X:out Integer) do --check whether the Queue is empty if front = -1 then --set flag to prevent the deadlock Flag_accept := False; Put_Line("Queue is Empty"); X := -1; else X := queue(front); --clear array value queue(front) := 0; --Clear the memory and move the front if front = rear then front := -1; rear := -1; --C-- Queue_counter := Queue_counter - 1; elsif (front = (size-1)) then front := 0; --C-- Queue_counter := Queue_counter - 1; else front := front +1; --C-- Queue_counter := Queue_counter - 1; end if; end if; end; or accept Stop; Put_line("Buffer stop!"); exit; end select; end loop; end buffer; task body producer is Message: constant String := "producer executing"; -- change/add your local declarations here --random number subtype Random_Number is Integer range 0 .. 20; --the range of the Integer package R_N is new Ada.Numerics.Discrete_Random (Random_Number); use R_N; G : R_N.Generator; X : Random_Number; --random time Random_Duration : Duration; type Random_Time is range 0..5000; package R_T is new Ada.Numerics.Discrete_Random (Random_Time); use R_T; G_T : R_T.Generator; X_T : Random_Time; period : Time := Clock; begin Put_Line(Message); loop -- add your task code inside this loop select accept Stop; Put_line("Producer is terminate!"); exit; else Reset (G); X := Random (G); --Put if Queue_counter <= 20 then Buffer.Put(X); Put_line("Producer Put: " & Integer'Image(X)); Put_Line("Queue counter is: " & Integer'Image(Queue_counter)); end if; Reset(G_T); X_T := Random (G_T); -- Convert Num to a Duration value from 0.5 to 3.0 Random_Duration := Duration(X_T) / 1000.0; delay Random_Duration; end select; end loop; end producer; task body consumer is Message: constant String := "consumer executing"; -- change/add your local declarations here get_number : Integer := 0; consume_total : Integer := 0; --random time Random_Duration : Duration; type Random_Time is range 0..5000; package R_T is new Ada.Numerics.Discrete_Random (Random_Time); use R_T; G_T : R_T.Generator; X_T : Random_Time; period : Time := Clock; begin Put_Line(Message); Main_Cycle: loop -- add your task code inside this loop Reset(G_T); X_T := Random (G_T); -- Convert Num to a Duration value from 1.0 to 3.0 Random_Duration := Duration(X_T) / 1000.0; delay Random_Duration; --get the buffer number by FIFO if Flag_accept = True then Buffer.Get(get_number); if get_number <= 20 and get_number >= 0 then Put_line("----------------------------"); Put_line("Consumer Get: " & Integer'Image(get_number)); consume_total := consume_total + get_number; Put_line("Consumer Total Get: " & Integer'Image(consume_total)); Put_line("----------------------------"); end if; end if; --when sum > 100, exit main_cycle if consume_total >= 100 then Put_Line("The Consumer has more than 100."); exit Main_Cycle; end if; end loop Main_Cycle; -- add your code to stop executions of other tasks producer.Stop; buffer.Stop; exception when TASKING_ERROR => Put_Line("Buffer finished before producer"); Put_Line("Ending the consumer"); end consumer; begin Put_Line(Message); end comm1; ``` ### An ```= with Ada.Text_IO; use Ada.Text_IO; with Ada.Calendar; use Ada.Calendar; with Ada.Numerics.Discrete_Random; procedure comm1 is Message: constant String := "Process communication"; Flag_accept : Boolean := False; task buffer is -- add your task entries for communication entry Put(X:in Integer); entry Get(X:out Integer); entry Stop; end buffer; task producer is -- add your task entries for communication entry Stop; end producer; task consumer is -- add your task entries for communication end consumer; task body buffer is Message: constant String := "buffer executing"; -- change/add your local declarations here front : Integer := -1; rear : Integer := -1; --buffer size setting: size : Integer := 20; queue : array (0..(size-1)) of integer; total_queue : integer := 0; Buffer_Flag : Boolean := False; begin Put_Line(Message); loop -- add your task code inside this loop select when not((front = 0 and rear = (size-1)) or (rear = (front-1) rem (size-1)))=> accept Put(X:Integer) do --design buffer is a circular buffer. if (front = 0 and rear = (size-1)) or (rear = (front-1) rem (size-1)) then Put_line("Queue is Full."); elsif (front = -1) then --first time input --clear the array first for index in queue'Range loop queue(index) := 0; end loop; front := 0; rear := 0; queue(rear) := X; total_queue := total_queue + queue(rear); elsif (rear = (size-1) and front /= 0) then rear := 0; queue(rear) := X; total_queue := total_queue + queue(rear); else rear := rear + 1; queue(rear) := X; total_queue := total_queue + queue(rear); end if; --display queue for debug for index in queue'Range loop --Put(queue(index)'Img); null; end loop; --New_line; if total_queue>0 then Buffer_Flag:=True; end if; --set flag if is not empty Flag_accept := True; end; or when front /= -1 => accept Get(X:out Integer) do --check whether the Queue is empty if front = -1 then --set flag to prevent the deadlock Flag_accept := False; Put_Line("Queue is Empty"); X := -1; else X := queue(front); --clear array value queue(front) := 0; --Clear the memory and move the front if front = rear then front := -1; rear := -1; elsif (front = (size-1)) then front := 0; else front := front +1; end if; end if; end; or accept Stop; Put_line("Buffer stop!"); exit; end select; end loop; end buffer; task body producer is Message: constant String := "producer executing"; -- change/add your local declarations here --random number subtype Random_Number is Integer range 0 .. 20; --the range of the Integer package R_N is new Ada.Numerics.Discrete_Random (Random_Number); use R_N; G : R_N.Generator; X : Random_Number; --random time Random_Duration : Duration; type Random_Time is range 0..5000; package R_T is new Ada.Numerics.Discrete_Random (Random_Time); use R_T; G_T : R_T.Generator; X_T : Random_Time; period : Time := Clock; begin Put_Line(Message); loop -- add your task code inside this loop select accept Stop; Put_line("Producer is terminate!"); exit; else Reset (G); X := Random (G); Buffer.Put(X); Put_line("Producer Put: " & Integer'Image(X)); Reset(G_T); X_T := Random (G_T); -- Convert Num to a Duration value from 0.5 to 3.0 Random_Duration := Duration(X_T) / 1000.0; delay Random_Duration; end select; end loop; end producer; task body consumer is Message: constant String := "consumer executing"; -- change/add your local declarations here get_number : Integer := 0; consume_total : Integer := 0; --random time Random_Duration : Duration; type Random_Time is range 0..5000; package R_T is new Ada.Numerics.Discrete_Random (Random_Time); use R_T; G_T : R_T.Generator; X_T : Random_Time; period : Time := Clock; begin Put_Line(Message); Main_Cycle: loop -- add your task code inside this loop Reset(G_T); X_T := Random (G_T); -- Convert Num to a Duration value from 1.0 to 3.0 Random_Duration := Duration(X_T) / 1000.0; delay Random_Duration; --get the buffer number by FIFO Buffer.Get(get_number); if get_number <= 20 and get_number >= 0 then Put_line("----------------------------"); Put_line("Consumer Get: " & Integer'Image(get_number)); consume_total := consume_total + get_number; Put_line("Consumer Total Get: " & Integer'Image(consume_total)); Put_line("----------------------------"); end if; --when sum > 100, exit main_cycle if consume_total >= 100 then Put_Line("The Consumer has more than 100."); exit Main_Cycle; end if; end loop Main_Cycle; -- add your code to stop executions of other tasks producer.Stop; buffer.Stop; exception when TASKING_ERROR => Put_Line("Buffer finished before producer"); Put_Line("Ending the consumer"); end consumer; begin Put_Line(Message); end comm1; ``` # Assignment #2 (Complete!!) [Difference between Interrupt and Polling](https://www.geeksforgeeks.org/difference-between-interrupt-and-polling/) ## LSD sensor number LSD 1: left, LSD 2: middle, LSD 3: right. If sensor number := 800, is on the white area, and if sensor number is := 200-300 is on the black line. # Assignment #3 ## Part 1 ### 1-1 ```=c++ ``` ### 1-2 ```=c++ ``` ### 1-3 ```=c++ ``` ### 1-4 ```=c++ ``` ### 1-5 ```=c++ ``` ### 1-6 ```=c++ ``` ### 1-7 ```=c++ system Example { declarations { tasks t1, t2, t3; indexed T,C,R,D,U; priority P; } initialise { ! Periods T[t1] = 10; T[t2] = 15; T[t3] = 35; ! WCETs C[t1] = 2; C[t2] = 4; C[t3] = 10; ! Deadlines (not used) D[t1] = 10; D[t2] = 15; D[t3] = 35; ! Priorities P[t1] = 1; P[t2] = 2; P[t3] = 3; } formulas { ! Calculate the response-time for each task R[i] = C[i] + sigma(hp, ceiling((R[i])/T[j]) * C[j]); ! Calculate the utilization in the system ! U must be indexed since lside and rside must be the same. U[i] = sigma(all, C[j]/T[j]); } } ``` ![](https://i.imgur.com/61DWuMi.png) ## Part 2 ## 2-1 DM ```=c++ system Example { declarations { tasks t1, t2, t3, t4; indexed T,C,R,D,U; priority P; } initialise { ! Periods T[t1] = 20; T[t2] = 7; T[t3] = 14; T[t4] = 100; ! WCETs C[t1] = 2; C[t2] = 3; C[t3] = 5; C[t4] = 4; ! Deadlines (not used) D[t1] = 6; D[t2] = 7; D[t3] = 13; D[t4] = 60; ! Priorities P[t1] = 1; P[t2] = 2; P[t3] = 3; P[t4] = 4; } formulas { R[i] = C[i] + sigma(hp, ceiling((R[i])/T[j]) * C[j]); U[i] = sigma(all, C[j]/T[j]); } } ``` ![](https://i.imgur.com/dKFpQph.png) RM ```=c++ system Example { declarations { tasks t1, t2, t3, t4; indexed T,C,R,D,U; priority P; } initialise { T[t1] = 20; T[t2] = 7; T[t3] = 14; T[t4] = 100; C[t1] = 2; C[t2] = 3; C[t3] = 5; C[t4] = 4; D[t1] = 6; D[t2] = 7; D[t3] = 13; D[t4] = 60; P[t1] = 3; P[t2] = 1; P[t3] = 2; P[t4] = 4; } formulas { R[i] = C[i] + sigma(hp, ceiling((R[i])/T[j]) * C[j]); U[i] = sigma(all, C[j]/T[j]); } } ``` ![](https://i.imgur.com/oP54WcY.png) ## 2-2 Short Ci high priority ```=c++ system Example { declarations { tasks t1, t2, t3, t4; indexed T,C,R,D,U; priority P; } initialise { T[t1] = 20; T[t2] = 7; T[t3] = 14; T[t4] = 100; C[t1] = 2; C[t2] = 3; C[t3] = 5; C[t4] = 4; D[t1] = 6; D[t2] = 7; D[t3] = 13; D[t4] = 60; P[t1] = 1; P[t2] = 2; P[t3] = 4; P[t4] = 3; } formulas { R[i] = C[i] + sigma(hp, ceiling((R[i])/T[j]) * C[j]); U[i] = sigma(all, C[j]/T[j]); } } ``` ![](https://i.imgur.com/rvVxS5E.png) met case ```=c++ system Example { declarations { tasks t1, t2, t3, t4; indexed T,C,R,D,U; priority P; } initialise { T[t1] = 20; T[t2] = 7; T[t3] = 14; T[t4] = 100; C[t1] = 2; C[t2] = 3; C[t3] = 5; C[t4] = 4; D[t1] = 6; D[t2] = 7; D[t3] = 13; D[t4] = 60; P[t1] = 2; P[t2] = 1; P[t3] = 3; P[t4] = 4; } formulas { R[i] = C[i] + sigma(hp, ceiling((R[i])/T[j]) * C[j]); U[i] = sigma(all, C[j]/T[j]); } } ``` ![](https://i.imgur.com/lWSpfx0.png) Revised: high to low -> T2, T1, T3, T4. ### 2-3 ```=c++ system Example { declarations { tasks t1, t2, t3, t4; indexed T,C,R,D,U; priority P; } initialise { T[t1] = 20; T[t2] = 7; T[t3] = 14; T[t4] = 100; C[t1] = 2; C[t2] = 3; C[t3] = 5; C[t4] = 4; D[t1] = 6; D[t2] = 7; D[t3] = 13; D[t4] = 60; P[t1] = 1; P[t2] = 2; P[t3] = 2; P[t4] = 3; } formulas { R[i] = sigma(ep,C[j]) + sigma(hp, ceiling((R[i])/T[j]) * C[j]); U[i] = sigma(all, C[j]/T[j]); } } ``` ## Part 3 ### 3-1 ```=c++ system Example { declarations { tasks t1, t2, t3, t4; indexed T,C,R,D,U; priority P; } initialise { T[t1] = 10; T[t2] = 20; T[t3] = 40; T[t4] = 100; C[t1] = 2; C[t2] = 3; C[t3] = 10; C[t4] = 4; D[t1] = 5; D[t2] = 12; D[t3] = 40; D[t4] = 50; P[t1] = 1; P[t2] = 2; P[t3] = 3; P[t4] = 4; } formulas { R[i] = C[i] + sigma(hp, ceiling((R[i])/T[j]) * C[j]); U[i] = sigma(all, C[j]/T[j]); } } ``` ![](https://i.imgur.com/FHShQC1.png) ### 3-2 #### Comment: About 3.2, based on the question you should use a critical instant scheme to answer it (“by doing a critical instant scheme”). You should add a corresponding diagram to your report. ```= c++ scalar GlobalVar; system testing { declarations { indexed Period, Deadline, CompTime, RespTime; blocking Blockvar; priority Priovar; tasks T1, T2, T3, T4; } semaphores { semaphore(S1,T2,1); semaphore(S1,T4,2); } initialise { Period[T1]=10; Period[T2]=20; Period[T3]=40; Period[T4]=100; Deadline[T1]=5; Deadline[T2]=12; Deadline[T3]=40; Deadline[T4]=50; Priovar[T1]=1; Priovar[T2]=2; Priovar[T3]=4; Priovar[T4]=3; CompTime[T1]=2; CompTime[T2]=3; CompTime[T3]=10; CompTime[T4]=4; } formulas { RespTime[i]=CompTime[i]+Blockvar[i]+sigma(hp,ceiling(RespTime[i]/Period[j])*CompTime[j]); GlobalVar=CompTime[T1]+CompTime[T2]*CompTime[T3]; } } ``` ![](https://i.imgur.com/KiJrwUH.png) ### 3-3 #### Comment: About 3.3, similar to 3.2, You should add a corresponding diagram to your report. ```= c++ scalar GlobalVar; system testing { declarations { indexed Period, Deadline, CompTime, RespTime; blocking Blockvar; priority Priovar; tasks T1, T2, T3, T4; } semaphores { semaphore(S1,T2,1); semaphore(S1,T4,2); semaphore(S2,T2,1); semaphore(S2,T3,5); } initialise { Period[T1]=10; Period[T2]=20; Period[T3]=40; Period[T4]=100; Deadline[T1]=5; Deadline[T2]=12; Deadline[T3]=40; Deadline[T4]=50; Priovar[T1]=2; Priovar[T2]=3; Priovar[T3]=4; Priovar[T4]=1; CompTime[T1]=2; CompTime[T2]=3; CompTime[T3]=10; CompTime[T4]=4; } formulas { RespTime[i]=CompTime[i]+Blockvar[i]+sigma(hp,ceiling(RespTime[i]/Period[j])*CompTime[j]); GlobalVar=CompTime[T1]+CompTime[T2]*CompTime[T3]; } } ``` ![](https://i.imgur.com/fZn6eGG.png) ### 3-4 #### Comment: about 3.4, You should cover all parts of the question: “What are the blocking times for the tasks in Figure 6 using the priority inheritance protocol?” and “What are the response times for the tasks when using the priority inheritance protocol?” You should report blocking time for all the tasks (for example in table) and then apply the worst-case response time analysis test using these. ### 3-5 #### Comment: about 3.5, “What are the blocking times for the tasks in Figure 6 using the immediate inheritance protocol?” and “Will all tasks complete before their deadlines?” I couldn’t find anything about these parts of the question in your report. You should cover all parts of the question. You should provide a table with blocking time for each task and apply the worst-case response-time analysis test to check schedulability of the task set. ## Part 4 #### Commnet: Ex4: - 4.2 and 4.3: It's better to state clearly the value of jitter instead of pointing to the figure. The second part of the question specifically ask for the jitter ### 4-4 ```= c++ scalar GlobalVar; system testing { declarations { indexed Period, Deadline, CompTime, RespTime,W; tasks T1, T2; priority Priority; } initialise { Period[T1]=20; Period[T2]=50; Deadline[T1]=10; Deadline[T2]=50; CompTime[T1]=5; CompTime[T2]=30; Priority[T1]=1; Priority[T2]=2; } formulas { W[i]=CompTime[i]+sigma(hp,ceiling(W[i]/Period[j])*CompTime[j]); !W[i]=CompTime[i]+sigma(hp,ceiling(1+((W[i]-Period[j])/Period[j]))*CompTime[j]); RespTime[i]=W[i]; GlobalVar=CompTime[T1]+CompTime[T2]; } } ``` ![](https://i.imgur.com/zHMCKSP.png) ### 4-5 #### 4.5 and 4.6: the calculated values are correct, but your figures 13, 14 are wrong. First, this is not the worst case scenario that give the maximum response time for the tasks. Second, your drawing about jitter is not correct. Jitter is counted from the arrival time of the task until the time the task can start its execution, but still can be blocked by higher priority task, the time when the task is blocked by higher priority task is not counted as jitter (Yeah I know this is a little bit confusing with the first 4.1, 4.2, 4.3 exercises) ```= c++ scalar GlobalVar; system testing { declarations { indexed Period, Deadline, CompTime, RespTime,W,jitter; priority Priority; tasks T1, T2; } initialise { Period[T1]=20; Period[T2]=50; Deadline[T1]=10; Deadline[T2]=50; Priority[T1]=1; Priority[T2]=2; CompTime[T1]=5; CompTime[T2]=30; jitter[T1]=5; jitter[T2]=10; } formulas { W[i]=CompTime[i]+sigma(hp,ceiling((W[i]+jitter[j])/Period[j])*CompTime[j]); RespTime[i]=W[i]+jitter[i]; !W[i]=CompTime[i]+sigmng(1+((W[i]-(Period[j]-jitter[j]))/Period[j]))*CompTime[j]); !RespTime[i]=W[i]+jitter[i]; } } ``` ![](https://i.imgur.com/aunZyZu.png) ### 4-6 ```= c++ scalar GlobalVar; system testing { declarations { indexed Period, Deadline, CompTime, RespTime,W,jitter; priority Priority; tasks T1, T2; } initialise { Period[T1]=20; Period[T2]=50; Deadline[T1]=10; Deadline[T2]=50; Priority[T1]=2; Priority[T2]=1; CompTime[T1]=5; CompTime[T2]=30; jitter[T1]=5; jitter[T2]=10; } formulas { W[i]=CompTime[i]+sigma(hp,ceiling((W[i]+jitter[j])/Period[j])*CompTime[j]); RespTime[i]=W[i]+jitter[i]; !W[i]=CompTime[i]+sigmng(1+((W[i]-(Period[j]-jitter[j]))/Period[j]))*CompTime[j]); !RespTime[i]=W[i]+jitter[i]; } } ``` ![](https://i.imgur.com/SvDjudt.png) # Assignment 4 verifier ``` E<> done_counter == 5 ``` then click "get trace" # References * [1] Ada Learning source: [Introduction to Ada](https://learn.adacore.com/courses/intro-to-ada/index.html) * [2] Matplotlib arrow: [Annotations](https://matplotlib.org/stable/tutorials/text/annotations.html) * [3] Drawing the arrow with Matplotlib: [Drawing arrows in Matplotlib](https://www.skytowner.com/explore/drawing_arrows_in_matplotlib)