------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- Cheddar is a GNU GPL real-time scheduling analysis tool. -- This program provides services to automatically check schedulability and -- other performance criteria of real-time architecture models. -- -- Copyright (C) 2002-2020, Frank Singhoff, Alain Plantec, Jerome Legrand, -- Hai Nam Tran, Stephane Rubini -- -- The Cheddar project was started in 2002 by -- Frank Singhoff, Lab-STICC UMR 6285, Université de Bretagne Occidentale -- -- Cheddar has been published in the "Agence de Protection des Programmes/France" in 2008. -- Since 2008, Ellidiss technologies also contributes to the development of -- Cheddar and provides industrial support. -- -- The full list of contributors and sponsors can be found in AUTHORS.txt and SPONSORS.txt -- -- 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$ -- $Date$ -- $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 battery_set; use battery_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 primitive_write_xml; use primitive_write_xml; with Ellidiss_Tools; use Ellidiss_Tools; -- start : ellidiss simulation optimization with GNAT.Sockets; use GNAT.Sockets; with Sockets_Overlay; use Sockets_Overlay; with Marzhin_Utils; use Marzhin_Utils; with Task_Set; with Resource_Set; with Heuristics; use Heuristics; with Tables; with Tasks; use Tasks; with Task_Set; use Task_Set; use Task_Set.Generic_Task_Set; with Resources; use Resources; use Resources.resource_accesses; with Resource_Set; use Resource_Set; use Resource_Set.Generic_Resource_Set; with Buffers; use Buffers; use Buffers.Buffer_Roles_package; with Buffer_Set; use Buffer_Set; use Buffer_Set.Generic_Buffer_Set; with Messages; use Messages; with Message_Set; use Message_Set; use Message_Set.Generic_Message_Set; with Task_Dependencies; use Task_Dependencies; use Task_Dependencies.Half_Dep_Set; with Processors; use Processors; with core_units; use core_units; with processor_set; use processor_set; with address_spaces; use address_spaces; with address_space_set; use address_space_set; with deployments; use deployments; with deployment_set; use deployment_set; with Ada.Strings.Unbounded; use Ada.Strings.Unbounded; with unbounded_strings; use unbounded_strings; with Framework_Config; use Framework_Config; --with Ada.Numerics.Aux; use Ada.Numerics.Aux; with Ada.Numerics.Float_Random; use Ada.Numerics.Float_Random; with Time_Unit_Events; use Time_Unit_Events; use Time_Unit_Events.Time_Unit_Package; with Scheduling_Analysis; use Scheduling_Analysis; with Ada.Finalization; with Unchecked_Deallocation; with indexed_tables; with tables; with natural_util; with access_lists; with Unchecked_Deallocation; with primitive_xml_strings; use primitive_xml_strings; with Scheduler_Interface; use Scheduler_Interface; with processor_interface; use processor_interface; with Integer_Arrays; use Integer_Arrays; with Cache_Set; use Cache_Set; with Cache_Block_Set; use Cache_Block_Set; with Cache_Access_Profile_Set; use Cache_Access_Profile_Set; -- end : ellidiss simulation optimization with Ada.Real_Time; use Ada.Real_Time; 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_jitters : in Boolean := True; With_Task_Specific_Seed : in Boolean := True; Global_Seed_Value : in Integer := 0; Predictable_Global_Seed : in Boolean := True; With_CRPD : in Boolean := False) is -- ellidiss modification 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); when Task_Set.Task_Must_Be_Periodic => Result.entries (Result.nb_entries).data.error_msg := Lb_Compute_Scheduling_Error_15 (Current_Language); 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); when Task_Set.Task_Model_Error => Result.entries (Result.nb_entries).data.error_msg := Lb_Compute_Scheduling_Error_1 (Current_Language); when Task_Set.Priority_Error => Result.entries (Result.nb_entries).data.error_msg := Lb_Compute_Scheduling_Error_11 (Current_Language); 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; duplicate(sys.batteries, si.Batteries); 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, sys.Cache_Access_Profiles, sys.Caches, With_CRPD); ------------------------------------------------ -- 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 -- ellidiss modification 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; --------------------------------------------------------------------- -- Build_Multiprocessor_Scheduling -- Purpose: Calculations in order to build the scheduling simulation -- (Time-Driven) and send at each unit of time the scheduling -- informations to a data socket (AADLInspector). Moreover, -- the simulation can be stopped/accelerated/paused/played -- by a command socket (AADLInspector command to Cheddar) -- Extra: -Currently two packages are used for handling -- -- 1) The sockets and stuff linked to their manipulation: Sockets_Overlays -- 2) The manipulations/translation of events strings for -- AADLInspector / Marzhin replacement: Marzhin_Utils --------------------------------------------------------------------- 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_jitters : in Boolean := True; With_minimize_preemption : in Boolean := True; With_Task_Specific_Seed : in Boolean := True; Global_Seed_Value : in Integer := 0; Predictable_Global_Seed : in Boolean := True; With_CRPD : in Boolean := False) is -- ellidiss simulation optimization Speed : Duration := 1.0; -- The time delay between each time unit calculation (seconds) SpeedFactor : constant Duration := 0.001; -- The speed factor used to calculate delay (SpeedValue * SpeedFactor) Exit_Simulation : Boolean := False; -- True if simulation received "stop" command Slice_Size : Natural := Last_Time; -- Size of the simulation time slice Last_Time_Mod : Natural := Last_Time; -- End simulation time unit clock : Ada.Real_Time.Time; Time_Span : Ada.Real_Time.Time_Span; Dur : Duration; begin clock := Ada.Real_Time.Clock; Put_Debug ("Call Build_Multiprocessor_Scheduling", very_verbose); if Socket_Mode_Activated then Initialize_Sockets; Current_Communication_State := Starting; Command_Communication (Slice_Size, Last_Time_Mod, Speed, SpeedFactor, Exit_Simulation); end if; Put_Debug("__INFO__ :: Starting simulation up to " & Last_Time_Mod'Img, very_verbose); initialize_Multiprocessor_Scheduling (sys, Result, Event_To_Generate, Last_Time_Mod, With_Offsets, With_Precedencies, With_Resources, with_jitters, With_Task_Specific_Seed, Global_Seed_Value, Predictable_Global_Seed, With_CRPD); -------------------------------------------------------------- -- Now, we compute the scheduling of the overall architecture -------------------------------------------------------------- Process_Each_Time_Unit: while (Last_Current_Time < Last_Time_Mod + 2) loop Last_Current_Time := Natural'Last; -------------------------------------------------------------- -- Initialize TCB variables -------------------------------------------------------------- for i in 0 .. Si.Number_Of_Tasks - 1 loop Si.Tcbs (i).already_run_at_current_time := False; si.tcbs (i).wait_for_a_resource:=null; end loop; Process_Each_Result_Entry: for J in 0 .. Result.nb_entries - 1 loop -------------------------------------------------------------- -- Check time and errors conditions -------------------------------------------------------------- if (Result.entries (J).data.error_msg /= empty_string) and (Current_Time (J) >= Last_Time_Mod + 2) then goto End_Of_Entries_Loop; end if; Put_Debug ("__INFO__ :: Last_Time : " & Last_Time'Img); Put_Debug ("__INFO__ :: Build_Multiprocessor_Scheduling : compute scheduling of time " & To_Unbounded_String (Natural'Image (Current_Time (J))), very_verbose); Process_Each_Core: for core_id in 0 .. table_of_core_scheduler(j).nb_entries - 1 loop -------------------------------------------------------------- -- Check if re-election of previous running task's needed -------------------------------------------------------------- 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, With_jitters, With_minimize_preemption, Event_To_Generate, Elected, No_Task); end if; -- Update task properties and produce events -- Put_Debug ("Call Update_Task_Simulation_Data_And_Produce_Events ", very_verbose); Update_Task_Simulation_Data_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_Mod, With_Offsets, With_Precedencies, With_Resources, with_jitters, Event_To_Generate, With_CRPD); if not No_Task then Update_Task_Simulation_Data_And_Produce_Events_when_task_is_run (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_Mod, With_Offsets, With_Precedencies, With_Resources, with_jitters, Event_To_Generate, With_CRPD); end if; if Optimization_Mode_Activated then -------------------------------------------------------------- -- Computing of the idle times based heuristic -------------------------------------------------------------- First_Heuristic: declare Jump_Time : Natural; -- local variable used only for first heuristic calculations. begin Update_Values (Heuristic_1(Idle_Heuristic.all), No_Task, Natural(core_id)); if Heuristic_1(Idle_Heuristic.all).Number_Of_Valid_Idle_Times = Natural(table_of_core_scheduler(j).nb_entries) then Jump_Time := Calculate_Heuristic (Idle_Heuristic.all, Si); if Jump_Time > Current_Time (J) + 2 then Heuristic_1(Idle_Heuristic.all).Current_Time := Current_Time(J); if table_of_core_scheduler(j).entries (core_id).scheduler.all in Hierarchical_offline_Scheduler then Increase_Used_CPU(Hierarchical_offline_Scheduler(table_of_core_scheduler(j).entries (core_id).scheduler.all), (Jump_Time-Current_Time(J)-1)); Jump_Time := Jump_Time - 1; end if; Current_Time (J) := Jump_Time; Last_Current_Time := Current_Time (J); Reset_Values (Heuristic_1(Idle_Heuristic.all), Natural(core_id)); goto BACK_TO_THE_FUTURE; end if; end if; end First_Heuristic; -------------------------------------------------------------- -- Computing of the last job running based heuristic -------------------------------------------------------------- --Heuristic_2(Last_Job_Heuristic.all).Current_Time := Current_Time(J); --if Verify_Pre_Conditions(Heuristic_2(Last_Job_Heuristic.all), Si) then --for RC in 0 .. Si.Tcbs(Heuristic_2(Last_Job_Heuristic.all).Remaining_Task_Id).Rest_Of_Capacity - 1 loop --Generate_Running_Event(table_of_core_scheduler(j).entries (core_id).scheduler.all, Si, --Result.entries (J).data.result, Elected, Current_Time (J) + RC); --end loop; --Current_Time(J) := Calculate_Heuristic(Last_Job_Heuristic.all, Si); --Last_Current_Time := Current_Time (J); --Reset_Values (Heuristic_2(Last_Job_Heuristic.all), Si); --goto BACK_TO_THE_FUTURE; --end if; end if; -------------------------------------------------------------- -- Send events data -------------------------------------------------------------- if Socket_Mode_Activated then Data_Communication(Sys, Result, J, Current_Time(J), Last_Time_Mod, SpeedFactor, Speed, Slice_Size, Exit_Simulation); end if; if Exit_Simulation then goto End_Of_Simulation; end if; end loop Process_Each_Core; Current_Time (J) := Current_Time (J) + 1; Last_Current_Time := Natural'Min (Last_Current_Time, Current_Time (J)); <> -- Check if simulation reached it's last time unit: if (Current_Time(J) = Last_Time_Mod + 2) and Socket_Mode_Activated then Current_Communication_State := Ending; Command_Communication (Slice_Size, Last_Time_Mod, Speed, SpeedFactor, Exit_Simulation); end if; if Exit_Simulation then goto End_Of_Simulation; end if; <> end loop Process_Each_Result_Entry; end loop Process_Each_Time_Unit; <> Put_Debug("__INFO__ :: End of simulation"); if Socket_Mode_Activated then Close_Sockets; end if; Time_Span := clock - Time_Of(0, Time_Span_Zero); Dur := Ada.Real_Time.To_Duration(Time_Span); Put_Debug ("__INFO__ :: Duration : " & Dur'Img); 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 for j in 0 .. Sched.Entries(i).data.result.nb_entries - 1 loop put(" "); put(xml_string(Sched.entries (I).data.result.entries(j).item)); put(xml_string(Sched.entries (I).data.result.entries(j).data)); put_line(" "); end loop; 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 Buffer_Overflow => null; when Buffer_Underflow => null; 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; when preemption => null; 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 for j in 0 .. Sched.Entries(i).data.result.nb_entries - 1 loop put(into,""); write_xml(into, Sched.entries (I).data.result.entries(j).item); put_line(into, ""); write_xml(into, Sched.entries (I).data.result.entries(j).data ); end loop; 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;