------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- 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: 548 $ -- $Date: 2012-10-12 01:48:51 +0200 (Fri, 12 Oct 2012) $ -- $Author: singhoff $ ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ with ada.tags; use ada.tags; with Ada.Numerics; use Ada.Numerics; with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions; with scheduler_io; use scheduler_io; with Statements; use Statements; with Expressions; use Expressions; use Expressions.Variables_Type_Package; with processor_interface; use processor_interface; with Tasks; use Tasks; with Ada.Strings.Unbounded.Text_IO; use Ada.Strings.Unbounded.Text_IO; with unbounded_strings; use unbounded_strings; with Scheduler; use Scheduler; use Scheduler.schedulers_Table_Package; with Scheduler_builder; use Scheduler_builder; with Scheduler.user_defined; use Scheduler.user_defined; with Scheduler_Interface; use Scheduler_Interface; with Interpreter.extended; use Interpreter.extended; with Dependency_Services; use Dependency_Services; with Translate; use Translate; with io_tools; use io_tools; with Ada.IO_Exceptions; use Ada.IO_Exceptions; with Ada.Exceptions; use Ada.Exceptions; with Xml_generic_Parsers; use Xml_generic_Parsers; with Xml_generic_Parsers.event_table; use Xml_generic_Parsers.event_table; with Input_Sources.File; use Input_Sources.File; with Sax.Readers; use Sax.Readers; with Text_IO; use Text_IO; with Ada.Text_IO.Text_Streams; use Ada.Text_IO.Text_Streams; with Parser; use Parser; with Sections; use Sections; with section_Set; use section_Set; with Address_Spaces; use Address_Spaces; with Debug; use Debug; with Scheduler.Hierarchical.offline; use Scheduler.Hierarchical.offline; with event_analyzers.extended; use event_analyzers.extended; with core_units; use core_units; use core_units.Core_Units_Table_Package; with buffer_set; use buffer_set; use buffer_set.Generic_Buffer_Set; with resource_set; use resource_set; use resource_set.Generic_resource_Set; with DOM.Core.Documents; use DOM.Core, DOM.Core.Documents; with DOM.core; use DOM.core; with DOM.Core.Nodes; use DOM.Core.Nodes; with DOM.Readers; use DOM.Readers; with GNAT.Command_Line; use GNAT.Command_Line; with GNAT.Expect; use GNAT.Expect; with GNAT.OS_Lib; use GNAT.OS_Lib; with Input_Sources.File; use Input_Sources.File; with Input_Sources.Http; use Input_Sources.Http; with Input_Sources; use Input_Sources; with Sax.Readers; use Sax.Readers; with Sax.Symbols; with Sax.Utils; use Sax.Utils; with Sax.Encodings; use Sax.Encodings; with Unicode.CES; use Unicode.CES; with Unicode.Encodings; use Unicode.Encodings; with Ada.Direct_IO; with Ellidiss_Tools; use Ellidiss_Tools; package body Multiprocessor_Services is ------------------------------------- -- Internal data of the simulator ------------------------------------- -- Data simulation -- Tmp_Buffers : array (Scheduling_Table_Range) of Buffers_Set; Tmp_Tasks : array (Scheduling_Table_Range) of Tasks_Set; Tmp_Resources : array (Scheduling_Table_Range) of Resources_Set; Si : Scheduling_Information; -- Tables of scheduler instances that are used to compute the -- scheduling -- table_of_address_space_scheduler : array (Scheduling_Table_Range) of Scheduler_table; table_of_core_scheduler : array(Scheduling_Table_Range) of scheduler_table; -- Various pointers and iterators -- a_address_space_scheduler : address_space_scheduler_ptr; a_core_scheduler : core_scheduler_ptr; Iterator1 : Processors_Iterator; Iterator2 : Address_Spaces_Iterator; Iterator3 : core_units_Iterator; A_Addr : Address_Space_Ptr; A_Processor : Generic_Processor_Ptr; -- Variables to drive the main loop of the simulation -- Last_Current_Time : Natural := 0; Current_Time : array (Scheduling_Table_Range) of Natural := (others => 0); Elected : Tasks_Range := Tasks_Range'First; No_Task : Boolean := True; must_perform_election : Boolean := True; -- Variable to store an event table (to be used by a scheduler) -- partition_sched : scheduling_table_ptr; -- Variable to store .sc file of .XML file content -- File_Content : unbounded_string; ----------------------------------------------------- -- The two following subprograms are the main entry -- point of the cheddar scheduling simulator ----------------------------------------------------- procedure initialize_Multiprocessor_Scheduling (Sys : in system; Result : in out Scheduling_Table_Ptr; Event_To_Generate : in Time_Unit_Event_Type_Boolean_Table; Last_Time : in Natural; With_Offsets : in Boolean := True; With_Precedencies : in Boolean := True; With_Resources : in Boolean := True; With_Task_Specific_Seed : in Boolean := True; Global_Seed_Value : in Integer := 0; Predictable_Global_Seed : in Boolean := True) is partition_filename : unbounded_string := empty_string; begin Put_Debug( "initialize_Multiprocessor_Scheduling : initialize internal simulator variables ", very_verbose); for i in scheduling_table_range loop Current_Time(i):=0; reset(tmp_buffers(i)); reset(tmp_tasks(i)); reset(tmp_resources(i)); initialize(table_of_address_space_scheduler(i)); initialize(table_of_core_scheduler(i)); end loop; initialize(Si); Last_Current_Time := 0; Elected :=Tasks_Range'First; No_Task :=true; must_perform_election :=true; ------------------------------------------------------------------------- -- Before initialization, check if the tasks can be -- scheduled with the selected scheduler -- -- If so, we prepar the scheduling result (i.e. table of -- scheduling_sequence, with one scheduling_sequence per processor) -- otherwise, a error message is prepared instead --------------------------------------------------------- Put_Debug( "initialize_Multiprocessor_Scheduling : check scheduler compliancy of tasks", very_verbose); reset_iterator (sys.Processors, Iterator1); loop current_element (sys.Processors, A_Processor, Iterator1); begin Result.entries (Result.nb_entries).item := A_Processor; Result.entries (Result.nb_entries).data.scheduling_msg := empty_string; Result.entries (Result.nb_entries).data.error_msg := empty_string; if (Get_Number_Of_Task_From_Processor (sys.Tasks, A_Processor.name) /= 0) then -- Build core scheduler table -- initialize(table_of_core_scheduler(Result.nb_entries)); a_processor:=search_processor(sys.processors, a_processor.name); if a_processor.processor_type = Monocore_type then a_core_scheduler := new core_scheduler; a_core_scheduler.scheduler := build_a_scheduler(mono_core_processor_ptr(a_processor).core, a_processor); a_core_scheduler.entity := mono_core_processor_ptr(a_processor).core; add(table_of_core_scheduler(Result.nb_entries), entity_scheduler_ptr(a_core_scheduler)); else for k in 0..multi_cores_processor_ptr(a_processor).cores.nb_entries-1 loop a_core_scheduler := new core_scheduler; a_core_scheduler.scheduler := build_a_scheduler(multi_cores_processor_ptr(a_processor).cores.entries(k), a_processor); a_core_scheduler.entity := multi_cores_processor_ptr(a_processor).cores.entries(k); add(table_of_core_scheduler(Result.nb_entries), entity_scheduler_ptr(a_core_scheduler)); end loop; end if; -- Check that the scheduler can be run on the architecture model -- for core_id in 0 .. table_of_core_scheduler(Result.nb_entries).nb_entries - 1 loop Check_Before_Scheduling ( table_of_core_scheduler(Result.nb_entries).entries (core_id).scheduler.all, sys.Tasks, A_Processor.name); end loop; if With_Precedencies then Dependencies_Periods_Control (sys.Tasks, sys.Dependencies, A_Processor.name); end if; else Result.entries (Result.nb_entries).data.error_msg := Lb_Minus & Lb_Define_Tasks_Before (Current_Language); end if; exception when Dependency_Services.Dependencies_Period_Error => Result.entries (Result.nb_entries).data.error_msg := Lb_Precedencies_Period_Error (Current_Language) & unbounded_lf; when Task_Set.Task_Must_Be_Periodic => Result.entries (Result.nb_entries).data.error_msg := Lb_Compute_Scheduling_Error_15 (Current_Language) & unbounded_lf; when Task_Set.Task_Must_Have_Period_Equal_To_Deadline => Result.entries (Result.nb_entries).data.error_msg := Lb_Compute_Scheduling_Error_14 (Current_Language) & unbounded_lf; when Task_Set.Task_Model_Error => Result.entries (Result.nb_entries).data.error_msg := Lb_Compute_Scheduling_Error_1 (Current_Language) & unbounded_lf; when Task_Set.Priority_Error => Result.entries (Result.nb_entries).data.error_msg := Lb_Compute_Scheduling_Error_11 (Current_Language) & unbounded_lf; end; Result.nb_entries := Result.nb_entries + 1; exit when is_last_element (sys.Processors, Iterator1); next_element (sys.Processors, Iterator1); end loop; --------------------------------------------------------- -- Now, perform scheduling simulation initialization -- This initialization is made in 5 steps : -- 1) initialization of variables to all processors and core units -- 2) gather all the data that will be handled by the simulateur -- 3) initialization of each processor -- 4) initialization of each core unit -- 5) Loading of all text file that may be uses by the simulator -- e.g. user defined scheduler, offline scheduling, ... -- by the schedulers -- 6) basic initialization that are specific for each scheduler --------------------------------------------------------- ------------------------------------------------ -- Step 1 : initialization of variables to all processors and core units -- Put_Debug( "initialize_Multiprocessor_Scheduling : initialization of processor and core units variables" , very_verbose); -- Variables to store architecture model to simulate -- Si.Number_Of_Tasks := 0; Si.Number_Of_Resources := 0; Si.Number_Of_Processors := Integer (get_number_of_elements (sys.Processors)); Si.Number_Of_Address_Spaces := Integer (get_number_of_elements (sys.Address_Spaces)); Si.Simulation_Length := Last_Time; for z in tasks_range loop Si.Tcbs (z):=null; end loop; for z in resources_range loop Si.shared_resources (z):=null; end loop; for J in 0 .. Result.nb_entries - 1 loop if Result.entries (J).data.error_msg = empty_string then Current_Processor_Name := Result.entries (J).item.name; Put_Debug ("initialize_Multiprocessor_Scheduling : initialization of processor " & Current_Processor_Name, very_verbose); ------------------------------------------------ -- Step 2 : gather all the data that will be handled by the --simulateur -- -- Select tasks/resources/buffers -- select_and_copy (sys.Tasks, Tmp_Tasks (J), Select_Cpu'Access); if (not is_empty(Tmp_Tasks(J))) then select_and_copy (sys.Resources, Tmp_Resources (J), Select_Cpu'Access); select_and_copy (sys.Buffers, Tmp_Buffers (J), Select_Cpu'Access); -- Build address spaces scheduler table -- initialize(table_of_address_space_scheduler(j)); if not is_empty (sys.Address_Spaces) then reset_iterator (sys.Address_Spaces, iterator2); loop current_element (sys.Address_Spaces, A_Addr, iterator2); if (A_Addr.cpu_name = Current_Processor_Name) and (A_Addr.scheduling.scheduler_type /= No_Scheduling_Protocol) then a_address_space_scheduler := new address_space_scheduler; a_processor := search_processor(sys.processors, current_processor_name); a_address_space_scheduler.scheduler := build_a_scheduler(A_Addr, a_processor); a_address_space_scheduler.entity := A_Addr; a_address_space_scheduler.used_cpu:= 0; add(table_of_address_space_scheduler(j), entity_scheduler_ptr(a_address_space_scheduler)); end if; exit when is_last_element (sys.Address_Spaces, iterator2); next_element (sys.Address_Spaces, iterator2); end loop; end if; ------------------------------------------------ -- Step 3 : initialization of each processor -- processor_Initialization (table_of_core_scheduler(j).entries(0).scheduler.all, Si, Result.entries (J).item.name, Tmp_Tasks (J), Tmp_Resources (J), Tmp_Buffers (J), Result.entries (J).data.result, With_Offsets, With_Precedencies, With_Resources, With_Task_Specific_Seed, Global_Seed_Value, Predictable_Global_Seed, Last_Time, Event_To_Generate); ------------------------------------------------ -- Step 4 : initialization of each core unit -- for core_id in 0 .. table_of_core_scheduler(j).nb_entries - 1 loop core_unit_Initialization ( table_of_core_scheduler(j).entries (core_id).scheduler.all, Si, Result.entries (J).item.name, Tmp_Tasks (J), Tmp_Resources (J), Tmp_Buffers (J), Result.entries (J).data.result, With_Offsets, With_Precedencies, With_Resources, With_Task_Specific_Seed, Global_Seed_Value, Predictable_Global_Seed, Last_Time, Event_To_Generate); end loop; -------------------------------------------------------------------- -- Step 5 : Loading of all text file that may be used by schedulers -- e.g. user defined scheduler, offline scheduling, ... -- for core_id in 0 .. table_of_core_scheduler(j).nb_entries - 1 loop begin if Get_Name(table_of_core_scheduler(j).entries (core_id).scheduler.all) = Hierarchical_offline_Protocol then partition_filename := Get_Arinc653_Partition_Table_Filename(table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name); Read_From_Xml_File (partition_Sched, Sys, partition_filename); set_event_table(Hierarchical_offline_Scheduler(table_of_core_scheduler(j).entries (core_id).scheduler.all), partition_sched); end if; if Get_Name(table_of_core_scheduler(j).entries (core_id).scheduler.all) = Automata_User_Defined_Protocol or Get_Name(table_of_core_scheduler(j).entries (core_id).scheduler.all) = Pipeline_User_Defined_Protocol then File_Content:= read_sequential_file( table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name); set_string_behavior(user_defined_scheduler(table_of_core_scheduler(j).entries (core_id).scheduler.all), file_content); end if; exception when Ada.IO_Exceptions.Name_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Name_Error"); when Ada.IO_Exceptions.Status_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Status_Error"); when Ada.IO_Exceptions.Mode_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Mode_Error"); when Ada.IO_Exceptions.Use_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Use_Error"); when Ada.IO_Exceptions.Device_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Device_Error"); when Ada.IO_Exceptions.End_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", End_Error"); when Ada.IO_Exceptions.Data_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Data_Error"); when Ada.IO_Exceptions.Layout_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Layout_Error"); when others => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & table_of_core_scheduler(j).entries (core_id).scheduler.parameters.user_defined_scheduler_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language))); end; end loop; --------------------------------------------------------------- -- Step 6 : basic initializations that are specific for each scheduler -- for core_id in 0 .. table_of_core_scheduler(j).nb_entries - 1 loop Specific_Scheduler_Initialization ( table_of_core_scheduler(j).entries (core_id).scheduler.all, Si, Result.entries (J).item.name, To_Unbounded_String (""), Tmp_Tasks (J), table_of_address_space_scheduler(j), Tmp_Resources (J), Tmp_Buffers (J), sys.Messages, Result.entries (J).data.scheduling_msg); end loop; end if; end if; end loop; end initialize_Multiprocessor_Scheduling; procedure Build_Multiprocessor_Scheduling (Sys : in system; Result : in out Scheduling_Table_Ptr; Event_To_Generate : in Time_Unit_Event_Type_Boolean_Table; Last_Time : in Natural; With_Offsets : in Boolean := True; With_Precedencies : in Boolean := True; With_Resources : in Boolean := True; With_Task_Specific_Seed : in Boolean := True; Global_Seed_Value : in Integer := 0; Predictable_Global_Seed : in Boolean := True) is begin Put_Debug ("Call Build_Multiprocessor_Scheduling", very_verbose); initialize_Multiprocessor_Scheduling (sys, Result, Event_To_Generate, Last_Time, With_Offsets, With_Precedencies, With_Resources, With_Task_Specific_Seed, Global_Seed_Value, Predictable_Global_Seed); -------------------------------------------------------------- -- Now, we compute the scheduling of the overall architecture -------------------------------------------------------------- while (Last_Current_Time < Last_Time) loop Last_Current_Time := Natural'Last; for z in 0 .. Si.Number_Of_Tasks - 1 loop Si.Tcbs (z).already_run_at_current_time := False; end loop; for J in 0 .. Result.nb_entries - 1 loop if (Result.entries (J).data.error_msg = empty_string) then if (Current_Time (J) < Last_Time) then Put_Debug ( "Build_Multiprocessor_Scheduling : compute scheduling of time " & To_Unbounded_String (Natural'Image (Current_Time (J))), very_verbose); for core_id in 0 .. table_of_core_scheduler(j).nb_entries - 1 loop -- Preemptive case : if a task has been previously --elected and if -- it has not ended its work => re-elect it ! -- must_perform_election := True; if (Get_Preemptive ( table_of_core_scheduler(j).entries (core_id).scheduler.all) = not_preemptive) then if table_of_core_scheduler(j).entries (core_id).scheduler.previous_running_task_is_not_completed then Put_Debug ("Preemption management : task is not ended ", very_verbose); Elected := table_of_core_scheduler(j).entries (core_id).scheduler.Previously_Elected; No_Task := False; must_perform_election := False; end if; end if; if must_perform_election then Put_Debug ("Call Do_Election ", very_verbose); Do_Election ( table_of_core_scheduler(j).entries (core_id).scheduler.all, Si, Result.entries (J).data.result, Result.entries (J).data.scheduling_msg, Current_Time (J), Result.entries (J).item.name, To_Unbounded_String (""), sys.Dependencies, With_Offsets, With_Precedencies, With_Resources, Event_To_Generate, Elected, No_Task); end if; -- We have a task to run -- if not No_Task then Put_Debug( "Call Update_Task_Simulation_Properties_And_Produce_Events ", very_verbose); -- Update task properties and produce events -- Update_Task_Simulation_Properties_And_Produce_Events ( table_of_core_scheduler(j).entries (core_id).scheduler.all, Result.entries (J).item.name, Si, sys.Dependencies, Elected, Result.entries (J).data.result, Current_Time (J), Last_Time, With_Offsets, With_Precedencies, With_Resources, Event_To_Generate); end if; end loop; Current_Time (J) := Current_Time (J) + 1; Last_Current_Time := Natural'Min (Last_Current_Time, Current_Time (J)); end if; end if; end loop; end loop; end Build_Multiprocessor_Scheduling; procedure Display_Scheduling (Sched : in Scheduling_Table_Ptr) is begin Put_Line (""); for I in 0 .. Sched.Nb_Entries - 1 loop Put (To_String(xml_string (Sched.entries (I).data))); end loop; Put_Line (""); New_Line; New_Line; end Display_Scheduling; procedure Run_An_Event_Analyzer (Sys : in system; Sched : in Scheduling_Table_Ptr; An_Event_Analyzer : in Event_Analyzer_Ptr; Result : in out Unbounded_String) is Current : Generic_Statement_Ptr; Var, Var_Time, Var_Type, Var_Processor, Var_Message, Var_Resource, Var_Task, Var_Buffer : Variables_Range; Global_Sched : array (Scheduling_Table_Range) of Scheduling_Sequence_Ptr; Global_Sched_Index : array (Scheduling_Table_Range) of Time_Unit_Range := (others => 0); Global_Processor_Name : array (Scheduling_Table_Range) of Unbounded_String; Global_Sched_Number : Scheduling_Table_Range := 0; Min_Time : Natural := 0; Current_Min_Time_Processor : Scheduling_Table_Range; ext_event_analyzer : extended_event_analyzer_ptr := extended_event_analyzer_ptr(An_Event_Analyzer); a_section : Computation_Section_Ptr; begin begin ext_event_analyzer.String_Behavior := read_sequential_file (ext_Event_Analyzer.event_analyzer_source_file_name); exception when Ada.IO_Exceptions.Name_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Name_Error"); when Ada.IO_Exceptions.Status_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Status_Error"); when Ada.IO_Exceptions.Mode_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Mode_Error"); when Ada.IO_Exceptions.Use_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Use_Error"); when Ada.IO_Exceptions.Device_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Device_Error"); when Ada.IO_Exceptions.End_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", End_Error"); when Ada.IO_Exceptions.Data_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Data_Error"); when Ada.IO_Exceptions.Layout_Error => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language)) & ", Layout_Error"); when others => Raise_Exception (Parametric_File_Error'Identity, To_String (Lb_File (Current_Language) & Lb_Colon & ext_Event_Analyzer.event_analyzer_source_file_name & Lb_Comma & Lb_Can_Not_Open_File (Current_Language))); end; -- We should check the scheduler behavior syntax ... -- Open_Input (ext_Event_Analyzer.String_Behavior); Parser.First_File (ext_Event_Analyzer.event_analyzer_source_file_name); Create_Parametric_Variables (Parser.Variables_Table, sys.Tasks); Parser.Yyparse; -- Store syntax tree and compiling information -- begin a_section := Computation_Section_Ptr (Search_section (Parser.Root_Statement_Pointer, Sections.Start_Type)); ext_Event_Analyzer.Root_Statement_Pointer (Sections.Start_Type) := a_section.first_statement; exception when others => ext_Event_Analyzer.Root_Statement_Pointer (Sections.Start_Type) := null; end; begin a_section := Computation_Section_Ptr (Search_section (Parser.Root_Statement_Pointer, Sections.Gather_Event_Analyzer_Type)); ext_Event_Analyzer.Root_Statement_Pointer ( Sections.Gather_Event_Analyzer_Type) := a_section.first_statement; exception when others => ext_Event_Analyzer.Root_Statement_Pointer ( Sections.Gather_Event_Analyzer_Type) := null; end; begin a_section := Computation_Section_Ptr (Search_section (Parser.Root_Statement_Pointer, Sections.Display_Event_Analyzer_Type)); ext_Event_Analyzer.Root_Statement_Pointer ( Sections.Display_Event_Analyzer_Type) := a_section.first_statement; exception when others => ext_Event_Analyzer.Root_Statement_Pointer ( Sections.Display_Event_Analyzer_Type) := null; end; ext_Event_Analyzer.Variables_Table := Parser.Variables_Table; ext_Event_Analyzer.Sets_Table := Parser.Sets_Table; -- Initialize parametric variables which are constant -- Initialize_Parametric_Variables (ext_Event_Analyzer.Variables_Table, sys.Messages, sys.Buffers, sys.Resources, sys.Tasks); -- "nb_processors" -- Var := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("nb_processors")); ext_Event_Analyzer.Variables_Table.entries (Var).Simulation.Integer_Value := Integer (get_number_of_elements (sys.Processors)); -- "nb_address_spaces" -- Var := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("nb_address_spaces")); ext_Event_Analyzer.Variables_Table.entries (Var).Simulation.Integer_Value := Integer (get_number_of_elements (sys.Address_Spaces)); -- Now : run "start" statements -- Current := ext_Event_Analyzer.Root_Statement_Pointer (Sections.Start_Type); Dispatch (Current, Sections.Start_Type, To_Unbounded_String ("none"), ext_Event_Analyzer.Variables_Table, Result); -- Now : run "event analyzer" statements -- Current := ext_Event_Analyzer.Root_Statement_Pointer ( Sections.Gather_Event_Analyzer_Type); -- Find variables before running the simulation -- Var_Time := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("events.time")); Var_Type := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("events.type")); Var_Processor := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("events.processor_name")); Var_Message := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("events.message_name")); Var_Resource := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("events.resource_name")); Var_Task := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("events.task_name")); Var_Buffer := Find_Variable (ext_Event_Analyzer.Variables_Table, To_Unbounded_String ("events.buffer_name")); -- how many processors scheduling should we run analysis ? -- for I in 0 .. Sched.nb_entries - 1 loop if (Sched.entries (I).data.error_msg = empty_string) then Global_Sched (Global_Sched_Number) := Sched.entries (I).data.result; Global_Processor_Name (Global_Sched_Number) := Sched.entries (I).item.name; Global_Sched_Number := Global_Sched_Number + 1; end if; end loop; -- Now, scan each time unit -- while Min_Time /= Natural'Last loop -- find the smallest time unit -- Min_Time := Natural'Last; for I in 0 .. Global_Sched_Number - 1 loop if Global_Sched_Index (I) < Global_Sched (I).nb_entries then if Global_Sched (I).entries (Global_Sched_Index (I)).item < Min_Time then Min_Time := Global_Sched (I).entries (Global_Sched_Index (I)).item; Current_Min_Time_Processor := I; end if; end if; end loop; if Min_Time /= Natural'Last then -- "events.time" -- ext_Event_Analyzer.Variables_Table.entries (Var_Time).Simulation. Integer_Value := Integer ( Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).item); -- "events.type" -- ext_Event_Analyzer.Variables_Table.entries (Var_Type).Simulation. String_Value := to_lower ( Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data.type_of_event'Img); -- "events.processor_name" -- ext_Event_Analyzer.Variables_Table.entries (Var_Processor). Simulation.String_Value := Global_Processor_Name (Current_Min_Time_Processor); -- "events.buffer_name" -- ext_Event_Analyzer.Variables_Table.entries (Var_Buffer).Simulation. String_Value := empty_string; -- "events.resource_name" -- ext_Event_Analyzer.Variables_Table.entries (Var_Resource). Simulation.String_Value := empty_string; -- "events.message_name" -- ext_Event_Analyzer.Variables_Table.entries (Var_Message).Simulation. String_Value := empty_string; case Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data.type_of_event is when Start_Of_Task_Capacity => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. start_task.name; when End_Of_Task_Capacity => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. end_task.name; when Write_To_Buffer => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. write_task.name; ext_Event_Analyzer.Variables_Table.entries (Var_Buffer). Simulation.String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. write_buffer.name; when Read_From_Buffer => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. read_task.name; ext_Event_Analyzer.Variables_Table.entries (Var_Buffer). Simulation.String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. read_buffer.name; when Running_Task => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. running_task.name; when Context_Switch_Overhead => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. switched_task.name; when Task_activation => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. activation_task.name; when Allocate_Resource => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. allocate_task.name; ext_Event_Analyzer.Variables_Table.entries (Var_Resource). Simulation.String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. allocate_resource.name; when Release_Resource => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. release_task.name; ext_Event_Analyzer.Variables_Table.entries (Var_Resource). Simulation.String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. release_resource.name; when Wait_For_Resource => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. wait_for_resource_task.name; ext_Event_Analyzer.Variables_Table.entries (Var_Resource). Simulation.String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. wait_for_resource.name; when Send_Message => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. send_task.name; ext_Event_Analyzer.Variables_Table.entries (Var_Message). Simulation.String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. send_message.name; when Receive_Message => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. receive_task.name; ext_Event_Analyzer.Variables_Table.entries (Var_Message). Simulation.String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. receive_message.name; when wait_for_memory => null; when Address_Space_Activation => ext_Event_Analyzer.Variables_Table.entries (Var_Task).Simulation. String_Value := Global_Sched (Current_Min_Time_Processor).entries ( Global_Sched_Index (Current_Min_Time_Processor)).data. activation_address_space; end case; -- Do analysis on the current time : run "event_analyzer" --section/statements -- Dispatch (Current, Sections.Gather_Event_Analyzer_Type, To_Unbounded_String ("none"), ext_Event_Analyzer.Variables_Table, Result); Global_Sched_Index (Current_Min_Time_Processor) := Global_Sched_Index (Current_Min_Time_Processor) + 1; end if; end loop; -- The end of the line : run "display_event" section/statements -- Current := ext_Event_Analyzer.Root_Statement_Pointer ( Sections.Display_Event_Analyzer_Type); Dispatch (Current, Sections.Display_Event_Analyzer_Type, To_Unbounded_String ("none"), ext_event_analyzer.Variables_Table, Result); end Run_An_Event_Analyzer; procedure Write_To_Xml_File (Sched : in Scheduling_Table_Ptr; Sys : in System; File_Name : in String) is begin Write_To_Xml_File (Sched, Sys, To_Unbounded_String (File_Name)); end Write_To_Xml_File; procedure Write_To_Xml_File (Sched : in Scheduling_Table_Ptr; Sys : in System; File_Name : in Unbounded_String) is Into : File_Type; Input : File_Input; Reader : Tree_Reader; d : Document; begin -- Open file and Write XML Header -- Create (Into, Mode => Out_File, Name => To_String (File_Name)); Put_Line (Into, " "); -- Put_Line (Into, ""); -- Put_Line (Into, ""); New_Line (Into, 2); Put_Line (Into, ""); for I in 0 .. Sched.Nb_Entries - 1 loop Put (Into, To_String(xml_string (Sched.entries (I).data))); end loop; Put_Line (Into, ""); New_Line (Into); New_Line (Into); Close (Into); Open (to_string(file_name), Input); Parse (Reader, Input); d:=Get_Tree(Reader); Close (Input); Create (Into, Mode => Out_File, Name => To_String (File_Name)); Write (Stream => Stream (into), N => d, Print_Comments => false, Print_XML_Declaration => true, With_URI => false, EOL_Sequence => "" & ASCII.LF, Pretty_Print => true, Encoding => Unicode.Encodings.Get_By_Name ("utf-8"), Collapse_Empty_Nodes => false); Free (Reader); Close (into); end Write_To_Xml_File; procedure Read_From_Xml_File (Sched : in out Scheduling_Table_Ptr; Sys : in System; File_Name : in Unbounded_String) is Read : File_Input; My_Reader : Xml_Event_Table_Parser; Name_Start : Natural; S : constant String := To_String (File_Name); begin -- Base file name should be used as the public Id -- Name_Start := S'Last; while Name_Start >= S'First and then S (Name_Start) /= '/' loop Name_Start := Name_Start - 1; end loop; Set_Public_Id (Read, S (Name_Start + 1 .. S'Last)); Set_System_Id (Read, S); Open (S, Read); -- xmlns:* attributes will be reported in Start_Element -- Set_Feature (My_Reader, Namespace_Prefixes_Feature, False); Set_Feature (My_Reader, Validation_Feature, True); Set_Scheduled_System (My_Reader, Sys); Parse (My_Reader, Read); Free (Sched); Sched := Get_Parsed_Event_Table (My_Reader); Close (Read); exception when XML_Fatal_Error => Close (Read); raise Xml_Read_Error; end Read_From_Xml_File; procedure Read_From_Xml_File (Sched : in out Scheduling_Table_Ptr; Sys : in System; File_Name : in String) is begin Read_From_Xml_File (Sched, Sys, To_Unbounded_String (File_Name)); end Read_From_Xml_File; procedure Free (Sched : in out Scheduling_Table_Ptr) is procedure Free_Pointer is new Unchecked_Deallocation ( Scheduling_Table, Scheduling_Table_Ptr); begin if Sched /= null then for I in Scheduling_Table_Range loop if Sched.entries (I).data.result /= null then free (Sched.entries (I).data.result); end if; end loop; Free_Pointer (Sched); end if; end Free; end Multiprocessor_Services;