------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- Cheddar is a GNU GPL real time scheduling analysis tool. -- This program provides services to automatically check performances -- of real time architectures. -- -- Copyright (C) 2002-2010, by Frank Singhoff, Alain Plantec, Jerome Legrand -- -- The Cheddar project was started in 2002 by -- the LISyC Team, University of Western Britanny. -- -- Since 2008, Ellidiss technologies also contributes to the development of -- Cheddar and provides industrial support. -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program is distributed in the hope that it will be useful, -- but WITHOUT ANY WARRANTY; without even the implied warranty of -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -- GNU General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- -- -- Contact : cheddar@listes.univ-brest.fr -- ----------------------------------------------------------------------------- -- Last update : -- $Rev: 297 $ -- $Date: 2010-11-23 13:39:03 +0100 (mar., 23 nov. 2010) $ -- $Author: singhoff $ ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ with Translate; use Translate; with Buffer_Set; use Buffer_Set; use Buffer_Set.Generic_Buffer_Set; with Resources; use Resources; with natural_util; use natural_util; package body Scheduling_Analysis.extended is package natural_list is new access_lists ( Natural, natural_ptr, put, free, copy, xml_string); use natural_list; function Compute_Average_Buffer_Size_From_Simulation (Buff : in Buffer_Size_Table_Ptr) return Double is Sum : Double := 0.0; begin for I in 0 .. Buff.nb_entries - 1 loop Sum := Sum + Double (Buff.entries (I).size); end loop; return Sum / Double (Buff.nb_entries); end Compute_Average_Buffer_Size_From_Simulation; function Compute_Maximum_Buffer_Size_From_Simulation (Buff : in Buffer_Size_Table_Ptr) return Natural is Max : Natural := 0; begin for I in 0 .. Buff.nb_entries - 1 loop if Buff.entries (I).size > Max then Max := Buff.entries (I).size; end if; end loop; return Max; end Compute_Maximum_Buffer_Size_From_Simulation; procedure Compute_Buffer_Size_From_Simulation (Sched : in Scheduling_Sequence_Ptr; My_Buff : in Buffer_Ptr; Buff : in out Buffer_Size_Table_Ptr) is Current_Size : Natural := 0; A_Buff_Size : Buffer_Size_Item; begin for I in 0 .. Sched.nb_entries - 1 loop if (Sched.entries (I).data.type_of_event = Read_From_Buffer) then if (Sched.entries (I).data.read_buffer.name = My_Buff.name) then A_Buff_Size.time := Sched.entries (I).item; Current_Size := Current_Size - Sched.entries (I).data.read_size; A_Buff_Size.size := Current_Size; add (Buff.all, A_Buff_Size); end if; end if; if (Sched.entries (I).data.type_of_event = Write_To_Buffer) then if (Sched.entries (I).data.write_buffer.name = My_Buff.name) then A_Buff_Size.time := Sched.entries (I).item; Current_Size := Current_Size + Sched.entries (I).data.write_size; A_Buff_Size.size := Current_Size; add (Buff.all, A_Buff_Size); end if; end if; end loop; end Compute_Buffer_Size_From_Simulation; function Compute_Maximum_Waiting_Time_From_Simulation (Buff : in Buffer_Size_Table_Ptr; Average_Consumer_Period : in Double) return Natural is Max : Natural := 0; begin for I in 0 .. Buff.nb_entries - 1 loop if Buff.entries (I).size > Max then Max := Buff.entries (I).size; end if; end loop; return (Max * Natural (Average_Consumer_Period)); end Compute_Maximum_Waiting_Time_From_Simulation; function Compute_Average_Waiting_Time_From_Simulation (Buff : in Buffer_Size_Table_Ptr; Average_Consumer_Period : in Double) return Double is Sum : Double := 0.0; begin for I in 0 .. Buff.nb_entries - 1 loop Sum := Sum + Double (Buff.entries (I).size); end loop; return ((Sum / Double (Buff.nb_entries)) * Average_Consumer_Period); end Compute_Average_Waiting_Time_From_Simulation; procedure Cyclic_Response_Time_By_Simulation (My_Task : in Generic_Task_Ptr; Sched : in Scheduling_Sequence_Ptr; Msg : in out Unbounded_String; Max : in out Natural; Min : in out Natural; Average : in out Double) is Current_Date : Natural := 0; My_Task_Occurence_Table : Task_Occurence_Table_Ptr; Task_Occurence_Number : Task_Occurence_Range; begin -- initialize all occurences -- dates are taken from scheduling table -- My_Task_Occurence_Table := new Task_Occurence_Table; Min := Natural'Last; Max := Natural'First; Average := 0.0; Msg := empty_string; -- Initialize activation time of the task -- Task_Occurence_Number:=0; for J in 0 .. Sched.nb_entries - 1 loop if Sched.entries (J).data.type_of_event = Task_activation then if Sched.entries (J).data.activation_task.name = My_Task.name then Initialize (My_Task_Occurence_Table.entries (Task_Occurence_Number), My_Task, Sched.entries (J).item); Task_Occurence_Number := Task_Occurence_Number + 1; My_Task_Occurence_Table.nb_entries := My_Task_Occurence_Table.nb_entries + 1; end if; end if; end loop; -- Find completion time of task -- compute response time -- Task_Occurence_Number:=0; for T in 0 .. Sched.nb_entries - 1 loop -- the current date -- Current_Date := Sched.entries (T).item; if Sched.entries (T).data.type_of_event = End_Of_Task_Capacity then if Sched.entries (t).data.end_task.name = My_Task.name then My_Task_Occurence_Table.entries (Task_Occurence_Number).completion_Time := current_date; My_Task_Occurence_Table.entries (Task_Occurence_Number).Response_Time := current_date - My_Task_Occurence_Table.entries (Task_Occurence_Number).arrival_time; -- Check deadline missed and update its message -- if (My_Task_Occurence_Table.entries ( Task_Occurence_Number).Response_Time > My_Task.deadline) then Msg := Msg & Lb_Comma & Lb_Check_Deadline (Current_Language) & My_Task_Occurence_Table.entries ( task_occurence_number).Absolute_Deadline'Img & Lb_Completion_Time (Current_Language) & My_Task_Occurence_Table.entries (task_occurence_number).completion_Time'img & To_Unbounded_String (")"); end if; Task_Occurence_Number:=Task_Occurence_Number+1; end if; end if; end loop; -- Compute min/max/average -- for T in 0 .. my_task_occurence_table.nb_entries - 1 loop if (My_Task_Occurence_Table.entries ( t).Response_Time < Min) then Min := My_Task_Occurence_Table.entries ( t).Response_Time; end if; if (My_Task_Occurence_Table.entries ( t).Response_Time > Max) then Max := My_Task_Occurence_Table.entries ( t).Response_Time; end if; Average := Average + Double ( My_Task_Occurence_Table.entries ( t).Response_Time); end loop; if my_task_occurence_table.nb_entries > 0 then Average := Average / Double (my_task_occurence_table.nb_entries); end if; if Min = Natural'Last then Min := 0; end if; Free (My_Task_Occurence_Table); end Cyclic_Response_Time_By_Simulation; procedure Acyclic_Response_Time_By_Simulation (My_Task : in Aperiodic_Task_Ptr; Sched : in Scheduling_Sequence_Ptr; Msg : in out Unbounded_String; Max : in out Natural; Min : in out Natural; Average : in out Double) is My_Task_Occurence : Task_Occurence; Effective_End : Natural := 0; Current_Date : Natural := 0; begin Initialize (My_Task_Occurence, generic_task_ptr(My_Task)); Msg := To_Unbounded_String (""); for T in 0 .. Sched.nb_entries - 1 loop -- the current date -- Current_Date := Sched.entries (T).item; -- Look for task completion and task starting time -- case Sched.entries (T).data.type_of_event is when Task_activation => My_Task_Occurence.arrival_time:= current_date; when End_Of_Task_Capacity => effective_end:=current_date; if (effective_end > My_Task_Occurence.Absolute_Deadline) then Msg := Msg & Lb_Comma & Lb_Check_Deadline (Current_Language) & My_Task_Occurence.Absolute_Deadline'Img & Lb_Completion_Time (Current_Language) & Effective_End'Img & To_Unbounded_String (")"); end if; when others => null; end case; end loop; if Effective_End > 0 then Average := Double (Effective_End - My_Task_Occurence.Arrival_time); Min := Effective_End - My_Task_Occurence.Arrival_time; Max := Min; else Average := 0.0; Min := 0; Max := 0; end if; end Acyclic_Response_Time_By_Simulation; procedure Compute_Response_Time_Distribution (My_Task : in Generic_Task_Ptr; Sched : in Scheduling_Sequence_Ptr; Result : in out Density_Table) is Awoken_Task_Occurence_Number : Task_Occurence_Range := 0; Task_Occurence_Number : Task_Occurence_Range := 0; Running_Awoken_Task_Index : Task_Occurence_Range := 0; Next_My_Task_Occurence_Awake : Task_Occurence_Range := 0; A_Running_Task : Generic_Task_Ptr; Current_Date : Natural := 0; Found : Boolean := False; A_Density : Density_Item; Number_Of_Response_Time : Double; My_Task_Occurence_Table : Task_Occurence_Table_Ptr; begin raise constraint_error; -- My_Task_Occurence_Table := new Task_Occurence_Table; -- compute response time from simulation -- and now compute density -- We have a response time. We look for the -- density table its response time is already -- known. If so, increment the frequency, if -- not, add it to the table -- -- Found := False; -- for K in 0 .. Result.nb_entries - 1 loop -- if Result.entries (K).response_time = -- My_Task_Occurence_Table.entries ( -- Running_Awoken_Task_Index).Response_Time -- then -- Result.entries (K).probability := -- Result.entries (K).probability + 1.0; -- Found := True; -- end if; -- end loop; -- if not Found then -- A_Density.response_time := -- My_Task_Occurence_Table.entries ( -- Running_Awoken_Task_Index).Response_Time; -- A_Density.probability := 1.0; -- add (Result, A_Density); -- end if; -- Now, compute density : find number of activation done and -- divide all entries of the table by this number -- -- Number_Of_Response_Time := 0.0; -- for K in 0 .. Result.nb_entries - 1 loop -- Number_Of_Response_Time := Number_Of_Response_Time + -- Result.entries (K).probability; -- end loop; -- for K in 0 .. Result.nb_entries - 1 loop -- Result.entries (K).probability := Result.entries (K).probability / -- Number_Of_Response_Time; -- end loop; -- Free (My_Task_Occurence_Table); end Compute_Response_Time_Distribution; procedure Compute_Response_Time_Distribution (My_Tasks : in Tasks_Set; Sched : in Scheduling_Sequence_Ptr; Processor_Name : Unbounded_String; Result : in out Densities_Table) is A_Task : Generic_Task_Ptr; My_Iterator : Tasks_Iterator; Working_Density : Density_Table; begin initialize (Result); reset_iterator (My_Tasks, My_Iterator); loop current_element (My_Tasks, A_Task, My_Iterator); if (Processor_Name = A_Task.cpu_name) then initialize (Working_Density); Compute_Response_Time_Distribution (A_Task, Sched, Working_Density); add (Result, A_Task, Working_Density); end if; exit when is_last_element (My_Tasks, My_Iterator); next_element (My_Tasks, My_Iterator); end loop; end Compute_Response_Time_Distribution; procedure Response_Time_By_Simulation (My_Task : Generic_Task_Ptr; Sched : in Scheduling_Sequence_Ptr; Msg : in out Unbounded_String; Max : in out Natural; Min : in out Natural; Average : in out Double) is begin case My_Task.task_type is when Aperiodic_Type => Acyclic_Response_Time_By_Simulation (Aperiodic_Task_Ptr (My_Task), Sched, Msg, Max, Min, Average); when others => Cyclic_Response_Time_By_Simulation (My_Task, Sched, Msg, Max, Min, Average); end case; end Response_Time_By_Simulation; procedure All_Response_Time_By_Simulation (My_Task : in Generic_Task_Ptr; Sched : in Scheduling_Sequence_Ptr; Result : in out Task_Occurence_Table_Ptr) is begin raise constraint_error; end All_Response_Time_By_Simulation; procedure Blocking_Time_From_Simulation (My_Task : in Generic_Task_Ptr; My_Resources : in Resources_Set; Sched : in Scheduling_Sequence_Ptr; Max : in out Natural; Min : in out Natural; Average : in out Double) is A_Resource : Generic_Resource_Ptr; Resource_Ite : Resources_Iterator; Running_Task : Generic_Task_Ptr; Event_List : Time_Unit_Lists_Package.list; An_Event : Time_Unit_Event_Ptr; Wait_Event : Time_Unit_Event_Ptr; Event_Ite : Time_Unit_Lists_Package.iterator; Date_List : natural_list.list; A_Date : natural_ptr; Wait_Date : natural_ptr; Date_Ite : natural_list.iterator; Nb_Blocking_Time : Natural; begin Max := 0; Min := Natural'Last; Average := 0.0; Nb_Blocking_Time := 0; for T in 0 .. Sched.nb_entries - 1 loop -- Store events on shared resources -- case Sched.entries (T).data.type_of_event is when Wait_For_Resource => Running_Task := Sched.entries (T).data.wait_for_resource_task; if Running_Task.name = My_Task.name then add (Event_List, Sched.entries (T).data); -- the current date -- A_Date := new Natural; A_Date.all := Sched.entries (T).item; add (Date_List, A_Date); end if; when Allocate_Resource => Running_Task := Sched.entries (T).data.allocate_task; if Running_Task.name = My_Task.name then add (Event_List, Sched.entries (T).data); -- the current date -- A_Date := new Natural; A_Date.all := Sched.entries (T).item; add (Date_List, A_Date); end if; when others => null; end case; end loop; -- compute maximum, minimum and average blocking time -- if not is_empty (Event_List) then reset_iterator (My_Resources, Resource_Ite); loop current_element (My_Resources, A_Resource, Resource_Ite); -- for each resource allocation, find the corresponding -- wait resource event -- reset_tail_iterator (Event_List, Event_Ite); reset_tail_iterator (Date_List, Date_Ite); loop current_element (Event_List, An_Event, Event_Ite); current_element (Date_List, A_Date, Date_Ite); -- first, find a wait event for the current resource -- if (An_Event.type_of_event = Wait_For_Resource) and (Wait_Event = null) then if (An_Event.wait_for_resource.name = A_Resource.name) then Wait_Event := An_Event; Wait_Date := A_Date; end if; end if; if (An_Event.type_of_event = Allocate_Resource) and (Wait_Event /= null) then Max := Natural'Max (Max, (A_Date.all - Wait_Date.all)); Min := Natural'Min (Min, (A_Date.all - Wait_Date.all)); Average := Average + Double (A_Date.all - Wait_Date.all); Nb_Blocking_Time := Nb_Blocking_Time + 1; Wait_Event := null; end if; exit when is_head_element (Event_List, Event_Ite); previous_element (Event_List, Event_Ite); previous_element (Date_List, Date_Ite); end loop; exit when is_last_element (My_Resources, Resource_Ite); next_element (My_Resources, Resource_Ite); end loop; end if; if Min = Natural'Last then Min := 0; end if; if Nb_Blocking_Time /= 0 then Average := Average / Double (Nb_Blocking_Time); end if; end Blocking_Time_From_Simulation; function Deadlock_From_Simulation (My_Tasks : in Tasks_Set; My_Resources : in Resources_Set; Processor_Name : in Unbounded_String; Sched : in Scheduling_Sequence_Ptr) return Deadlock_List is Result : Deadlock_List; -- Variables required to scan the resource and task -- Item : Deadlock_Item_Ptr; Item_Task : Generic_Task_Ptr; Item_Resource : Generic_Resource_Ptr; -- To store number of Tasks -- Number_Of_Tasks : constant Tasks_Range := get_number_of_elements (My_Tasks); -- To store number of resource -- Number_Of_Resources : constant Resources_Range := get_number_of_elements (My_Resources); -- Stamp to represent the tree graphic for the allocated resources and --the awaited resources -- Stamp_For_Allocate : array (Tasks_Range'Range, Resources_Range' Range) of Integer; Stamp_For_Wait : array (Tasks_Range'Range, Resources_Range' Range) of Integer; --Tables of names of Tasks -- Table_Name_Tasks : array (Tasks_Range'Range) of Unbounded_String; -- Table of names of resources -- Table_Name_Resources : array (Resources_Range'Range) of Unbounded_String; -- Tables to store the indices of the tasks and the resources -- Table_Index_Task : array (Natural range 0 .. Framework_Config.Max_Resources - 1) of Tasks_Range; Table_Index_Resource : array (Natural range 0 .. Framework_Config.Max_Resources - 1) of Resources_Range; -- Index -- Current_Time : Natural := 0; Index_Task : Tasks_Range := 200; Index_Resource : Resources_Range := 30; -- booleen to say if there is deadlock -- Ok : Boolean; -- procedure being used to find the index of a task -- procedure Index_Of_Tasks (Name : in out Unbounded_String; Index : in out Tasks_Range) is begin for I in 0 .. Number_Of_Tasks - 1 loop if (Table_Name_Tasks (I) = Name) then Index := I; end if; end loop; end Index_Of_Tasks; -- procedure being used to find the index of a resource -- procedure Index_Of_Resources (Name : in out Unbounded_String; Index : in out Resources_Range) is begin for I in 0 .. Number_Of_Resources - 1 loop if (Table_Name_Resources (I) = Name) then Index := I; end if; end loop; end Index_Of_Resources; -- procedure being used to find if a resource is held by a task -- procedure Seek_Of_Task (R : in out Resources_Range; Index : in out Tasks_Range) is begin for I in 0 .. Number_Of_Tasks - 1 loop if (Stamp_For_Allocate (I, R) = 1) then Index := I; end if; end loop; end Seek_Of_Task; -- procedure being used to find if a task awaits a resource -- procedure Seek_Of_Resource (T : in out Tasks_Range; Index : in out Resources_Range) is begin for I in 0 .. Number_Of_Resources - 1 loop if (Stamp_For_Wait (T, I) = 1) then Index := I; end if; end loop; end Seek_Of_Resource; procedure Perform_Analysis_Of_Resources is Item2 : Deadlock_Item_Ptr; List_Ite : Deadlock_Iterator; Found : Boolean := False; begin -- Initiazation of stamps -- for I in 0 .. Number_Of_Tasks - 1 loop for J in 0 .. Number_Of_Resources - 1 loop Stamp_For_Allocate (I, J) := 0; Stamp_For_Wait (I, J) := 0; end loop; end loop; for I in 0 .. Sched.entries (Sched.nb_entries - 1).item loop for J in 0 .. Sched.nb_entries - 1 loop -- construction of the tree -- if (Sched.entries (J).item = I) then if (Sched.entries (J).data.type_of_event = Allocate_Resource) then Item_Task := Sched.entries (J).data.allocate_task; Item_Resource := Sched.entries (J).data.allocate_resource; Index_Of_Tasks (Item_Task.name, Index_Task); Index_Of_Resources (Item_Resource.name, Index_Resource); Stamp_For_Allocate (Index_Task, Index_Resource) := 1; Stamp_For_Wait (Index_Task, Index_Resource) := 0; end if; if (Sched.entries (J).data.type_of_event = Wait_For_Resource) then Item_Task := Sched.entries (J).data.wait_for_resource_task; Item_Resource := Sched.entries (J).data.wait_for_resource; Index_Of_Tasks (Item_Task.name, Index_Task); Index_Of_Resources (Item_Resource.name, Index_Resource); Stamp_For_Wait (Index_Task, Index_Resource) := 1; end if; if (Sched.entries (J).data.type_of_event = Release_Resource) then Item_Task := Sched.entries (J).data.release_task; Item_Resource := Sched.entries (J).data.release_resource; Index_Of_Tasks (Item_Task.name, Index_Task); Index_Of_Resources (Item_Resource.name, Index_Resource); Stamp_For_Allocate (Index_Task, Index_Resource) := 0; end if; end if; end loop; --analyse of stamps -- for K in 0 .. Number_Of_Resources - 1 loop for L in 0 .. Framework_Config.Max_Resources - 1 loop Table_Index_Task (L) := 0; Table_Index_Resource (L) := 0; end loop; Current_Time := 0; Index_Resource := K; loop Index_Task := 30; Ok := False; Seek_Of_Task (Index_Resource, Index_Task); if (Index_Task /= 30) then Table_Index_Task (Current_Time) := Index_Task; Table_Index_Resource (Current_Time) := Index_Resource; Index_Resource := 30; Seek_Of_Resource (Index_Task, Index_Resource); if (Index_Resource /= 30) then for P in 0 .. Current_Time loop if (Table_Index_Resource (P) = Index_Resource) then Ok := True; end if; end loop; if Ok then for P in 0 .. Current_Time loop Item := new Deadlock_Item; Item.time := I; Item.task_name := Table_Name_Tasks (Table_Index_Task (P)); Item.resource_name := Table_Name_Resources (Table_Index_Resource (P)) ; Found := False; -- to check if data is already present in the --list -- if not is_empty (Result) then reset_head_iterator (Result, List_Ite); loop current_element (Result, Item2, List_Ite); if ((Item2.task_name = Item.task_name) and (Item2.resource_name = Item.resource_name)) then Found := True; exit; end if; if is_tail_element (Result, List_Ite) then exit; end if; next_element (Result, List_Ite); end loop; end if; -- addition of data in the list -- if not Found then add (Result, Item); end if; end loop; exit; end if; else exit; end if; else exit; end if; Current_Time := Current_Time + 1; end loop; end loop; end loop; end Perform_Analysis_Of_Resources; begin -- Initialization of tables of tasks names -- for I in 0 .. Number_Of_Tasks - 1 loop get_element_number (My_Tasks, Item_Task, I); Table_Name_Tasks (I) := Item_Task.name; end loop; -- Initialization of tables of resources of names -- for I in 0 .. Number_Of_Resources - 1 loop get_element_number (My_Resources, Item_Resource, I); Table_Name_Resources (I) := Item_Resource.name; end loop; Perform_Analysis_Of_Resources; return Result; end Deadlock_From_Simulation; function Priority_Inversion_From_Simulation (My_Tasks : in Tasks_Set; My_Resources : in Resources_Set; Processor_Name : in Unbounded_String; Sched : in Scheduling_Sequence_Ptr) return Priority_Inversion_List is Result : Priority_Inversion_List; -- Variables required to scan the resource set -- Item : Priority_Inversion_Item_Ptr; A_Resource : Generic_Resource_Ptr; My_Iterator : Resources_Iterator; -- Store the event of the resource allocation -- Allocation : Time_Unit_Event_Ptr; -- Store all Wait_For_Resource events -- Wait_Events : array (Time_Unit_Range) of Time_Unit_Event_Ptr; -- Simulation time of the stored event -- Wait_Event_Time : array (Time_Unit_Range) of Natural; -- Index on Wait_Events and Indexes tables -- Index : Time_Unit_Range := 0; -- Index on the scheduling table -- Current_Time : Time_Unit_Range := 0; procedure Perform_Analysis_Of_One_Resource is begin Current_Time := 0; -- First, find an Allocation Event -- loop if (Current_Time >= Sched.nb_entries - 1) then return; end if; if (Sched.entries (Current_Time).data.type_of_event = Allocate_Resource) then if (Sched.entries (Current_Time).data.allocate_resource.name = A_Resource.name) then Allocation := Sched.entries (Current_Time).data; exit; end if; end if; Current_Time := Current_Time + 1; end loop; loop Current_Time := Current_Time + 1; -- Search all Wait_For_Resource events upto the next allocation -- if (Current_Time >= Sched.nb_entries - 1) then return; end if; if (Sched.entries (Current_Time).data.type_of_event = Allocate_Resource) then if (Sched.entries (Current_Time).data.allocate_resource.name = A_Resource.name) then -- The next Allocate event is found, stop collecting data -- and do analysis -- -- Check that between the two "Allocate" events when have --middle priority -- tasks and that the priority of the first allocating task --is less than -- 2nd one. -- if (Allocation.allocate_task.priority < Sched.entries (Current_Time).data.allocate_task.priority) then declare -- Start time of the priority inversion -- Start_Time : Natural := Sched.entries (Current_Time).item; begin -- look for the start time of the priority inversion -- for Z in reverse 0 .. Index - 1 loop if Wait_Events (Z).wait_for_resource_task.name = Sched.entries (Current_Time).data.allocate_task. name then Start_Time := Wait_Event_Time (Z); end if; end loop; -- Store the detected priority inversion -- if Start_Time < Sched.entries (Current_Time).item then Item := new Priority_Inversion_Item; Item.start_time := Start_Time; Item.end_time := Sched.entries (Current_Time).item; Item.task_name := Sched.entries (Current_Time).data.allocate_task. name; Item.resource_name := Sched.entries (Current_Time).data. allocate_resource.name; add (Result, Item); end if; end; end if; -- Ready for the next priority inversion analysis -- Index := 0; Allocation := Sched.entries (Current_Time).data; end if; end if; if (Sched.entries (Current_Time).data.type_of_event = Wait_For_Resource) then if (Sched.entries (Current_Time).data.wait_for_resource.name = A_Resource.name) then Wait_Events (Index) := Sched.entries (Current_Time).data; Wait_Event_Time (Index) := Sched.entries (Current_Time).item; Index := Index + 1; end if; end if; end loop; end Perform_Analysis_Of_One_Resource; begin reset_iterator (My_Resources, My_Iterator); initialize (Result); loop current_element (My_Resources, A_Resource, My_Iterator); if (Processor_Name = A_Resource.cpu_name) then Perform_Analysis_Of_One_Resource; end if; exit when is_last_element (My_Resources, My_Iterator); next_element (My_Resources, My_Iterator); end loop; return Result; end Priority_Inversion_From_Simulation; function Number_Of_Preemption_From_Simulation (Sched : in Scheduling_Sequence_Ptr; My_Tasks : in Tasks_Set) return Natural is Nb : Natural := 0; A_Task : Generic_Task_Ptr; Usage_Time : Natural; begin for I in 0 .. Sched.nb_entries - 1 loop if (Sched.entries (I).data.type_of_event = Running_Task) then for K in reverse 0 .. I - 1 loop if (Sched.entries (K).data.type_of_event = Running_Task) then if ((Sched.entries (K).data.running_task.name /= Sched.entries (I).data.running_task.name) and (Sched.entries (K).item + 1 = Sched.entries (I).item)) then -- We know that the previous unit of time, another -- task was running. Check now that is was a preeemption -- -- look for the previously elected task and its state -- A_Task := Search_Task (My_Tasks, Sched.entries (I).data.running_task.name); -- Compute the running time of the task until its wake up --time -- Usage_Time := 0; for Z in reverse 0 .. K - 1 loop if (Sched.entries (Z).data.type_of_event = Running_Task) then if A_Task.name = Sched.entries (Z).data.running_task.name then Usage_Time := Usage_Time + 1; end if; end if; if (Sched.entries (Z).data.type_of_event = Task_activation) then if A_Task.name = Sched.entries (Z).data.activation_task.name then if (Usage_Time /= A_Task.capacity) and (Usage_Time /= 0) then Nb := Nb + 1; end if; exit; end if; end if; end loop; exit; end if; end if; end loop; end if; end loop; return Nb; end Number_Of_Preemption_From_Simulation; function Number_Of_Switch_Context_From_Simulation (Sched : in Scheduling_Sequence_Ptr) return Natural is Nb : Natural := 0; begin for I in 0 .. Sched.nb_entries - 1 loop if (Sched.entries (I).data.type_of_event = Running_Task) then for K in reverse 0 .. I - 1 loop if (Sched.entries (K).data.type_of_event = Running_Task) then if (Sched.entries (K).data.running_task.name /= Sched.entries (I).data.running_task.name) then Nb := Nb + 1; end if; exit; end if; end loop; end if; end loop; return Nb; end Number_Of_Switch_Context_From_Simulation; procedure Consumer_Response_Time (Sched : in Scheduling_Sequence_Ptr; Consumer_Resp_Time : in out Resp_Time_Consumer_Table_Ptr; My_Consumer_Task : in Generic_Task_Ptr) is My_Consumer_Task_Occurence_Table : Task_Occurence_Table_Ptr; Index : Resp_Time_Consumer_Range := 0; begin -- initialize -- My_Consumer_Task_Occurence_Table := new Task_Occurence_Table; All_Response_Time_By_Simulation (My_Consumer_Task, Sched, My_Consumer_Task_Occurence_Table); -- affect response time value -- for I_Occurence in Task_Occurence_Range loop if (My_Consumer_Task_Occurence_Table.entries (I_Occurence). Response_Time /= 0) then Consumer_Resp_Time.entries (Index).data := Double ( My_Consumer_Task_Occurence_Table.entries (I_Occurence). Response_Time); Index := Index + 1; end if; end loop; Consumer_Resp_Time.nb_entries := Index; Free (My_Consumer_Task_Occurence_Table); end Consumer_Response_Time; end Scheduling_Analysis.extended;