------------------------------------------------------------------------------
------------------------------------------------------------------------------
-- 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.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 Processors.extended; use Processors.extended;
with processor_interface; use processor_interface;
use Processors.Core_Units_Table_Package;
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;
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 Parser; use Parser;
with Sections; use Sections;
with section_Set; use section_Set;
with Address_Spaces; use Address_Spaces;
with Address_Spaces.extended; use Address_Spaces.extended;
with Debug; use Debug;
with Scheduler.Hierarchical.offline; use Scheduler.Hierarchical.offline;
with event_analyzers.extended; use event_analyzers.extended;
package body Multiprocessor_Services is
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;
-----------------------------------------------------
-- The two following subprograms are the main entry
-- point of the cheddar scheduling 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;
the_cores : Core_Units_Table;
table_of_local_scheduler : Scheduler_table;
-- Various pointers and iterators
--
Iterator2 : Address_Spaces_Iterator;
A_Addr : Address_Space_Ptr;
scheduler_index : scheduler_range;
Iterator3 : Processors_Iterator;
A_Processor : Generic_Processor_Ptr;
-- Variables for 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;
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
begin
Put_Debug ("Call initialize_Multiprocessor_Scheduling", very_verbose);
Put_Debug(
"initialize_Multiprocessor_Scheduling : check scheduler compliancy of tasks",
very_verbose);
-------------------------------------------------------------------------
-- 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
---------------------------------------------------------
reset_iterator (sys.Processors, Iterator3);
loop
current_element (sys.Processors, A_Processor, Iterator3);
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
the_cores := build_core_table (A_Processor);
for core_id in 0 .. the_cores.nb_entries - 1 loop
Check_Before_Scheduling
(
extended_Core_Unit_Ptr (the_cores.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, Iterator3);
next_element (sys.Processors, Iterator3);
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);
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 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 local/address spaces scheduler table
--
scheduler_index := 0;
table_of_local_scheduler := (others => null);
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 then
if extended_address_space_Ptr (A_Addr).scheduler /=
null
then
table_of_local_scheduler (scheduler_index) :=
new local_scheduler;
table_of_local_scheduler (scheduler_index).scheduler
:= extended_address_space_Ptr (A_Addr).scheduler;
table_of_local_scheduler (scheduler_index).
address_space_name := A_Addr.name;
scheduler_index := scheduler_index + 1;
end if;
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
--
the_cores := build_core_table (Result.entries (J).item);
processor_Initialization
(extended_Core_Unit_Ptr (the_cores.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 .. the_cores.nb_entries - 1 loop
core_unit_Initialization
(
extended_Core_Unit_Ptr (the_cores.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 .. the_cores.nb_entries - 1 loop
begin
if Get_Name(extended_Core_Unit_Ptr (the_cores.entries (core_id)).scheduler.all) = Hierarchical_offline_Protocol
then
Read_From_Xml_File
(partition_Sched,
Sys,
extended_Core_Unit_Ptr (the_cores.entries (core_id)).scheduler.parameters.user_defined_scheduler_source_file_name);
set_event_table(Hierarchical_offline_Scheduler(extended_Core_Unit_Ptr (the_cores.entries (core_id)).scheduler.all), partition_sched);
end if;
if Get_Name(extended_Core_Unit_Ptr (the_cores.entries (core_id)).scheduler.all) = Automata_User_Defined_Protocol
or Get_Name(extended_Core_Unit_Ptr (the_cores.entries (core_id)).scheduler.all) = Pipeline_User_Defined_Protocol
then
File_Content:= read_sequential_file(
extended_Core_Unit_Ptr (the_cores.entries (core_id)).scheduler.parameters.user_defined_scheduler_source_file_name);
set_string_behavior(user_defined_scheduler(extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 &
extended_Core_Unit_Ptr (the_cores.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 .. the_cores.nb_entries - 1 loop
Specific_Scheduler_Initialization
(
extended_Core_Unit_Ptr (the_cores.entries (core_id)).
scheduler.all,
Si,
Result.entries (J).item.name,
To_Unbounded_String (""),
Tmp_Tasks (J),
table_of_local_scheduler,
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);
the_cores := build_core_table (Result.entries (J).item);
for core_id in 0 .. the_cores.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
(
extended_Core_Unit_Ptr (the_cores.entries (core_id)).
scheduler.all) =
not_preemptive)
then
if (
extended_Core_Unit_Ptr (the_cores.entries (
core_id)).scheduler.previous_time_unit_was_busy)
then
Put_Debug ("Preemption management : cpu was busy at previous time", very_verbose);
if Si.Tcbs (
extended_Core_Unit_Ptr (the_cores.entries (
core_id)).scheduler.Previously_Elected).
Rest_Of_Capacity /=
Si.Tcbs (
extended_Core_Unit_Ptr (the_cores.entries (
core_id)).scheduler.Previously_Elected).Tsk.
capacity
then
Put_Debug ("Preemption management : task is not ended ", very_verbose);
Elected :=
extended_Core_Unit_Ptr (the_cores.entries (
core_id)).scheduler.Previously_Elected;
No_Task := False;
must_perform_election := False;
end if;
end if;
end if;
if must_perform_election then
Put_Debug ("Call Do_Election ", very_verbose);
Do_Election
(
extended_Core_Unit_Ptr (the_cores.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
(
extended_Core_Unit_Ptr (the_cores.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;
begin
-- Open file and Write DTD/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);
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;
end Multiprocessor_Services;