------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- 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: 523 $ -- $Date: 2012-09-26 15:09:39 +0200 (Wed, 26 Sep 2012) $ -- $Author: fotsing $ ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ with Translate; use Translate; with Xml_Tag; use Xml_Tag; with unbounded_strings; use unbounded_strings; with framework; use framework; with Call_Scheduling_Framework; use Call_Scheduling_Framework; with Multiprocessor_Services_Interface; use Multiprocessor_Services_Interface; use Multiprocessor_Services_Interface.Scheduling_Result_Per_Processor_Package; with Queueing_Systems; use Queueing_Systems; with Queueing_System; use Queueing_System; with Queueing_System.theoretical; use Queueing_System.theoretical; with Queueing_System.theoretical.Mp1; use Queueing_System.theoretical.Mp1; with Queueing_System.theoretical.Pp1; use Queueing_System.theoretical.Pp1; with Queueing_System.theoretical.Mm1; use Queueing_System.theoretical.Mm1; with Queueing_System.theoretical.Md1; use Queueing_System.theoretical.Md1; with Queueing_System.theoretical.Mg1; use Queueing_System.theoretical.Mg1; with double_util; use double_util; with Ada.Numerics.Aux; use Ada.Numerics.Aux; with Debug; use Debug; with Dependency_Services; use Dependency_Services; with address_spaces; use address_spaces; with address_space_set; use address_space_set; use address_space_set.Generic_Address_Space_Set; with Buffers.Extended; use Buffers.Extended; with Buffer_Set; use Buffer_Set; use Buffer_Set.Generic_Buffer_Set; with resources; use resources; with resource_Set; use resource_Set; use resource_Set.Generic_resource_Set; with Tasks; use Tasks; with task_Set; use task_Set; use task_Set.Generic_task_Set; package body Call_Memory_Framework is procedure Compute_Buffer_Scheduling_Simulation (Sys : in System; Result : in out Unbounded_String; A_Processor : in Generic_Processor_Ptr; Output : in Output_Format := String_Output) is A_Buffer : Buffer_Ptr; My_Iterator : Buffers_Iterator; Index : Scheduling_Table_Range := 0; A_Buffer_Result : Buffer_Size_Table_Ptr; A_Task : Generic_Task_Ptr; Maximum_Size : Natural; Maximum_Waiting_Time : Natural; Average_Size : Double; Average_Waiting_Time : Double; Average_Consumer_Period : Double := 0.0; Sum_Period : Double := 0.0; Nb_Consumer : Double := 0.0; begin Put_Debug ("Call Compute_Buffer_Scheduling_Simulation"); -- find the processor on which we want to compute buffer utilization -- for I in 0 .. Sched.nb_entries - 1 loop if Sched.entries (I).item.name = A_Processor.name then if Sched.entries (I).data.error_msg = empty_string then Index := I; exit; end if; end if; end loop; -- Compute buffer utilization on all buffer of the -- selected processor -- A_Buffer_Result := new Buffer_Size_Table; loop current_element (Sys.Buffers, A_Buffer, My_Iterator); if A_Processor.name = A_Buffer.cpu_name then Initialize (A_Buffer_Result.all); Compute_Buffer_Size_From_Simulation (Sched.entries (Index).data.result, A_Buffer, A_Buffer_Result); add (Buff, A_Buffer, A_Buffer_Result.all); -- Compute average consumer period -- Average_Consumer_Period := 0.0; Sum_Period := 0.0; Nb_Consumer := 0.0; for J in 0 .. A_Buffer.roles.nb_entries - 1 loop if (A_Buffer.roles.entries (J).data.the_role = Queuing_Consumer) then A_Task := Search_Task (Sys.Tasks, A_Buffer.roles.entries (J).item); if (A_Task.task_type = Periodic_Type) then Sum_Period := +Double (Periodic_Task_Ptr (A_Task).period); Nb_Consumer := Nb_Consumer + 1.0; end if; end if; end loop; Average_Consumer_Period := Sum_Period / Nb_Consumer; -- Compute results -- Maximum_Size := Compute_Maximum_Buffer_Size_From_Simulation (A_Buffer_Result); Average_Size := Compute_Average_Buffer_Size_From_Simulation (A_Buffer_Result); Maximum_Waiting_Time := Compute_Maximum_Waiting_Time_From_Simulation (A_Buffer_Result, Average_Consumer_Period); Average_Waiting_Time := Compute_Average_Waiting_Time_From_Simulation (A_Buffer_Result, Average_Consumer_Period); -- Display results -- Result := Result & unbounded_lf & unbounded_lf & Start_Task & Lb_Buffer (Current_Language) & " " & A_Buffer.name & To_Unbounded_String (" => ") & unbounded_lf; Result := Result & To_Unbounded_String (" ") & Lb_Maximum_Buffer_Size (Current_Language) & Maximum_Size'Img & unbounded_lf & To_Unbounded_String (" ") & Lb_Maximum_Waiting_Time (Current_Language) & Maximum_Waiting_Time'Img & unbounded_lf; Result := Result & To_Unbounded_String (" ") & Lb_Average_Buffer_Size (Current_Language) & format (Average_Size, 8) & unbounded_lf & To_Unbounded_String (" ") & Lb_Average_Waiting_Time (Current_Language) & format (Average_Waiting_Time, 8) & unbounded_lf; end if; exit when is_last_element (Sys.Buffers, My_Iterator); next_element (Sys.Buffers, My_Iterator); end loop; Free (A_Buffer_Result); end Compute_Buffer_Scheduling_Simulation; procedure Compute_Buffer_Feasibility_Tests (Sys : in System; Result : in out Unbounded_String; A_Processor : in Generic_Processor_Ptr; Output : in Output_Format := String_Output) is A_Buffer : Buffer_Ptr; Waiting_Time : Double := 0.0; Occupation : Double := 0.0; Reference, Ref1, Ref2 : Unbounded_String; My_Iterator : buffers_iterator; Nb_Arrival : Double := 0.0; Nb_Server : Double := 0.0; My_Consumer_Task : Generic_Task_Ptr; Service_Rate : Double := 0.0; Arrival_Rate : Double := 0.0; A_Mm1_Queueing_System : Mm1_Queueing_System_theoretical; A_Md1_Queueing_System : Md1_Queueing_System_theoretical; A_Mg1_Queueing_System : Mg1_Queueing_System_theoretical; A_Mp1_Queueing_System : Mp1_Queueing_System_theoretical; A_Pp1_Queueing_System : Pp1_Queueing_System_theoretical; No_Performance_Criteria : Boolean := False; begin Put_Debug ("Call Compute_Buffer_Feasibility_Tests"); if Output = Xml_Output then Set_Tag; else Set_Empty; end if; Result := unbounded_lf & Start_Line & unbounded_lf; reset_iterator (Sys.Buffers, My_Iterator); loop current_element (Sys.Buffers, A_Buffer, My_Iterator); if (A_Buffer.cpu_name = A_Processor.name) then if (Natural (A_Buffer.roles.nb_entries) >= 1) then begin Result := Result & unbounded_lf & unbounded_lf & Start_Task & Lb_Buffer (Current_Language) & " " & A_Buffer.name & To_Unbounded_String (" => (") & Qs_To_Display_String (A_Buffer.queueing_system_type) & To_Unbounded_String (")") & unbounded_lf; Ref1 := empty_string; Ref2 := empty_string; Reference := empty_string; Nb_Arrival := 0.0; Nb_Server := 0.0; No_Performance_Criteria := False; -- Number of producer (arrival) and consumer (server) -- for J in 0 .. A_Buffer.roles.nb_entries - 1 loop if (A_Buffer.roles.entries (J).data.the_role = Queuing_Producer) then Nb_Arrival := Nb_Arrival + 1.0; end if; if (A_Buffer.roles.entries (J).data.the_role = Queuing_Consumer) then My_Consumer_Task := Search_Task (Sys.Tasks, A_Buffer.roles.entries (J).item); Nb_Server := Nb_Server + 1.0; end if; end loop; -- Control before buffer computation -- Periodic_Buffer_Control (Sys.Tasks, A_Buffer); Buffer_Flow_Control (A_Buffer, Sys.Tasks, Service_Rate, Arrival_Rate); case A_Buffer.queueing_system_type is when Qs_Mm1 => -- initalization -- Reset (A_Mm1_Queueing_System); Set_Qs_Arrival_Rate (A_Mm1_Queueing_System, Arrival_Rate); Set_Qs_Service_Rate (A_Mm1_Queueing_System, Service_Rate); Set_Qs_Nb_Arrival (A_Mm1_Queueing_System, Nb_Arrival); Set_Qs_Nb_Server (A_Mm1_Queueing_System, Nb_Server); Set_Qs_Harmonic (A_Mm1_Queueing_System, Is_Cons_Prod_Harmonic (A_Buffer, Sys.Tasks)); -- consumer response time -- Set_Constant_Consumer_Response_Time (A_Mm1_Queueing_System, Double (My_Consumer_Task.deadline)); if (Nb_Server <= 1.0) then -- occupation computation -- Queueing_System.theoretical.Mm1. Qs_Average_Number_Customer (A_Mm1_Queueing_System, Occupation); -- waiting time computation -- Queueing_System.theoretical.Mm1. Qs_Average_Waiting_Time (A_Mm1_Queueing_System, Waiting_Time); -- Update message to be displayed -- Ref1 := To_Unbounded_String (" (") & Lb_See (Current_Language) & To_Unbounded_String ("[12], page 96, ") & Lb_Theorem (Current_Language) & To_Unbounded_String ("3.24). "); Ref2 := To_Unbounded_String (" (") & Lb_See (Current_Language) & To_Unbounded_String ("[12], page 98, ") & Lb_Theorem (Current_Language) & To_Unbounded_String ("3.26). "); Reference := To_Unbounded_String (" ") & Lb_Average_Buffer_Size (Current_Language) & format (Occupation, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref1 & End_Ref & unbounded_lf & To_Unbounded_String (" ") & Lb_Average_Waiting_Time (Current_Language) & format (Waiting_Time, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref2 & End_Ref & End_Task & unbounded_lf & End_Line & End_Buf_Bound & unbounded_lf; else No_Performance_Criteria := True; end if; when Qs_Md1 => -- initalization -- Reset (A_Md1_Queueing_System); Set_Qs_Arrival_Rate (A_Md1_Queueing_System, Arrival_Rate); Set_Qs_Service_Rate (A_Md1_Queueing_System, Service_Rate); Set_Qs_Nb_Arrival (A_Md1_Queueing_System, Nb_Arrival); Set_Qs_Nb_Server (A_Md1_Queueing_System, Nb_Server); Set_Qs_Harmonic (A_Md1_Queueing_System, Is_Cons_Prod_Harmonic (A_Buffer, Sys.Tasks)); -- consumer response time -- Set_Constant_Consumer_Response_Time (A_Md1_Queueing_System, Double (My_Consumer_Task.deadline)); if (Nb_Server <= 1.0) then -- occupation computation -- Queueing_System.theoretical.Md1. Qs_Average_Number_Customer (A_Md1_Queueing_System, Occupation); -- waiting time computation -- Queueing_System.theoretical.Md1. Qs_Average_Waiting_Time (A_Md1_Queueing_System, Waiting_Time); -- Update message to be displayed -- Ref1 := To_Unbounded_String ("to be filled"); Ref2 := To_Unbounded_String ("to be filled"); Reference := To_Unbounded_String (" ") & Lb_Average_Buffer_Size (Current_Language) & format (Occupation, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref1 & End_Ref & unbounded_lf & To_Unbounded_String (" ") & Lb_Average_Waiting_Time (Current_Language) & format (Waiting_Time, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref2 & End_Ref & End_Task & unbounded_lf & End_Line & End_Buf_Bound & unbounded_lf; else No_Performance_Criteria := True; end if; when Qs_Mg1 => -- initalization -- Reset (A_Mg1_Queueing_System); Set_Qs_Arrival_Rate (A_Mg1_Queueing_System, Arrival_Rate); Set_Qs_Service_Rate (A_Mg1_Queueing_System, Service_Rate); Set_Qs_Nb_Arrival (A_Mg1_Queueing_System, Nb_Arrival); Set_Qs_Nb_Server (A_Mg1_Queueing_System, Nb_Server); Set_Qs_Harmonic (A_Mg1_Queueing_System, Is_Cons_Prod_Harmonic (A_Buffer, Sys.Tasks)); -- consumer response time -- Set_Constant_Consumer_Response_Time (A_Mg1_Queueing_System, Double (My_Consumer_Task.deadline)); if (Nb_Server <= 1.0) then -- occupation computation -- Queueing_System.theoretical.Mg1. Qs_Average_Number_Customer (A_Mg1_Queueing_System, Occupation); -- waiting time computation -- Queueing_System.theoretical.Mg1. Qs_Average_Waiting_Time (A_Mg1_Queueing_System, Waiting_Time); -- Update message to be displayed -- Ref1 := To_Unbounded_String ("to be filled"); Ref2 := To_Unbounded_String ("to be filled"); Reference := To_Unbounded_String (" ") & Lb_Average_Buffer_Size (Current_Language) & format (Occupation, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref1 & End_Ref & unbounded_lf & To_Unbounded_String (" ") & Lb_Average_Waiting_Time (Current_Language) & format (Waiting_Time, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref2 & End_Ref & End_Task & unbounded_lf & End_Line & End_Buf_Bound & unbounded_lf; else No_Performance_Criteria := True; end if; when Qs_Mp1 => -- initalization -- Reset (A_Mp1_Queueing_System); Set_Qs_Arrival_Rate (A_Mp1_Queueing_System, Arrival_Rate); Set_Qs_Service_Rate (A_Mp1_Queueing_System, Service_Rate); Set_Qs_Nb_Arrival (A_Mp1_Queueing_System, Nb_Arrival); Set_Qs_Nb_Server (A_Mp1_Queueing_System, Nb_Server); Set_Qs_Harmonic (A_Mp1_Queueing_System, Is_Cons_Prod_Harmonic (A_Buffer, Sys.Tasks)); -- consumer response time -- Set_Constant_Consumer_Response_Time (A_Mp1_Queueing_System, Double (My_Consumer_Task.deadline)); if (Nb_Server <= 1.0) then -- occupation computation -- Queueing_System.theoretical.Mp1. Qs_Average_Number_Customer (A_Mp1_Queueing_System, Occupation); -- waiting time computation -- Queueing_System.theoretical.Mp1. Qs_Average_Waiting_Time (A_Mp1_Queueing_System, Waiting_Time); -- Update message to be displayed -- Ref1 := To_Unbounded_String (" (") & Lb_See (Current_Language) & To_Unbounded_String ("[10], ") & Lb_Theorem (Current_Language) & To_Unbounded_String ("6). "); Ref2 := To_Unbounded_String (" (") & Lb_See (Current_Language) & To_Unbounded_String ("[10], ") & Lb_Theorem (Current_Language) & To_Unbounded_String ("6). "); Reference := To_Unbounded_String (" ") & Lb_Average_Buffer_Size (Current_Language) & format (Occupation, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref1 & End_Ref & unbounded_lf & To_Unbounded_String (" ") & Lb_Average_Waiting_Time (Current_Language) & format (Waiting_Time, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref2 & End_Ref & End_Task & unbounded_lf & End_Line & End_Buf_Bound & unbounded_lf; else No_Performance_Criteria := True; end if; when Qs_Pp1 => -- initalization -- Reset (A_Pp1_Queueing_System); Set_Qs_Arrival_Rate (A_Pp1_Queueing_System, Arrival_Rate); Set_Qs_Service_Rate (A_Pp1_Queueing_System, Service_Rate); Set_Qs_Nb_Arrival (A_Pp1_Queueing_System, Nb_Arrival); Set_Qs_Nb_Server (A_Pp1_Queueing_System, Nb_Server); Set_Qs_Harmonic (A_Pp1_Queueing_System, Is_Cons_Prod_Harmonic (A_Buffer, Sys.Tasks)); -- consumer response time -- Set_Constant_Consumer_Response_Time (A_Mp1_Queueing_System, Double (My_Consumer_Task.deadline)); if (Nb_Server <= 1.0) then -- occupation computation -- Queueing_System.theoretical.Pp1. Qs_Maximum_Number_Customer (A_Pp1_Queueing_System, Occupation); -- waiting time computation -- Queueing_System.theoretical.Pp1. Qs_Maximum_Waiting_Time (A_Pp1_Queueing_System, Waiting_Time); -- Update message to be displayed -- Ref1 := To_Unbounded_String (" (") & Lb_See (Current_Language) & To_Unbounded_String ("[4,10], ") & Lb_Theorem (Current_Language) & To_Unbounded_String ("1 or 8). "); Ref2 := To_Unbounded_String (" (") & Lb_See (Current_Language) & To_Unbounded_String ("[10], ") & Lb_Theorem (Current_Language) & To_Unbounded_String ("8). "); Reference := To_Unbounded_String (" ") & Lb_Maximum_Buffer_Size (Current_Language) & format (Occupation, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref1 & End_Ref & unbounded_lf & To_Unbounded_String (" ") & Lb_Maximum_Waiting_Time (Current_Language) & format (Waiting_Time, 8) & unbounded_lf & To_Unbounded_String (" ") & Start_Ref & Ref2 & End_Ref & End_Task & unbounded_lf & End_Line & End_Buf_Bound & unbounded_lf; else No_Performance_Criteria := True; end if; when others => No_Performance_Criteria := True; end case; if No_Performance_Criteria then Result := Result & To_Unbounded_String (" ") & Lb_Compute_Buffer_Error_4 (Current_Language) & unbounded_lf; else Result := Result & Reference; end if; exception when Not_Implemented => Result := Result & To_Unbounded_String (" ") & Lb_Compute_Buffer_Error_4 (Current_Language) & unbounded_lf; when Task_Set.Task_Model_Error => Result := Result & To_Unbounded_String (" ") & Lb_Compute_Buffer_Error_3 (Current_Language) & unbounded_lf; when Dependency_Services.Task_Must_Be_Periodic => Result := Result & To_Unbounded_String (" ") & Lb_Compute_Buffer_Error_2 (Current_Language) & unbounded_lf; when Flow_Constraint_Not_Respected => Result := Result & To_Unbounded_String (" ") & Lb_Compute_Buffer_Error_1 (Current_Language) & unbounded_lf; end; else Result := Result & To_Unbounded_String (" ") & A_Buffer.name & To_Unbounded_String (" => NA"); end if; end if; exit when is_last_element (Sys.Buffers, My_Iterator); next_element (Sys.Buffers, My_Iterator); end loop; end Compute_Buffer_Feasibility_Tests; procedure Compute_Memory_Requirement_Analysis (Sys : in System; Result : in out Unbounded_String; Update_Address_Spaces_Set : in Boolean; Output : in Output_Format := String_Output) is sum_text : natural :=0; sum_stack : natural :=0; sum_data : natural :=0; task_Ite : tasks_Iterator; A_task : generic_task_ptr; address_space_Ite : Address_Spaces_Iterator; A_Address_Space : address_space_ptr; buffer_Ite : buffers_Iterator; A_buffer : buffer_ptr; resource_Ite : resources_Iterator; A_resource : generic_resource_ptr; begin Put_Debug ("Call Compute_Memory_Requirement_Analysis"); result:= unbounded_lf; if (get_number_of_elements (sys.Address_Spaces) > 0) then reset_iterator (sys.Address_Spaces, address_space_Ite); loop current_element (sys.Address_Spaces, A_Address_Space, address_space_Ite); -- Sum up memory requirements of the address space -- sum_text :=0; sum_stack :=0; sum_data :=0; if (get_number_of_elements (sys.tasks) > 0) then reset_iterator (sys.tasks, task_Ite); loop current_element (sys.tasks, A_task, task_Ite); if a_task.address_space_name = A_Address_Space.name then sum_text:=sum_text+a_task.text_memory_size; sum_stack:=sum_stack+a_task.stack_memory_size; end if; exit when is_last_element (sys.tasks, task_Ite); next_element (sys.tasks, task_Ite); end loop; end if; if (get_number_of_elements (sys.buffers) > 0) then reset_iterator (sys.buffers, buffer_Ite); loop current_element (sys.buffers, A_buffer, buffer_Ite); if a_buffer.address_space_name = A_Address_Space.name then sum_data:=sum_data+a_buffer.buffer_size; end if; exit when is_last_element (sys.buffers, buffer_Ite); next_element (sys.buffers, buffer_Ite); end loop; end if; if (get_number_of_elements (sys.resources) > 0) then reset_iterator (sys.resources, resource_Ite); loop current_element (sys.resources, A_resource, resource_Ite); if a_resource.address_space_name = A_Address_Space.name then sum_data:=sum_data+a_resource.size; end if; exit when is_last_element (sys.resources, resource_Ite); next_element (sys.resources, resource_Ite); end loop; end if; result:=result & " " & A_Address_Space.name & " => Data = " & sum_data'img & " ; Stack = " & sum_stack'img & " Text = " & sum_text'img & unbounded_lf; if Update_Address_Spaces_Set then A_Address_Space.text_memory_size:=sum_text; A_Address_Space.data_memory_size:=sum_data; A_Address_Space.stack_memory_size:=sum_stack; end if; exit when is_last_element (sys.Address_Spaces, address_space_Ite); next_element (sys.Address_Spaces, address_space_Ite); end loop; end if; end Compute_Memory_Requirement_Analysis; end Call_Memory_Framework;