taste-concurrency_view.adb 16.2 KB
Newer Older
1
--  *************************** kazoo ***********************  --
Maxime Perrotin's avatar
Maxime Perrotin committed
2
--  (c) 2019 European Space Agency - maxime.perrotin@esa.int
3
4
--  LGPL license, see LICENSE file

Maxime Perrotin's avatar
Maxime Perrotin committed
5
6
with Ada.Directories,
     Ada.IO_Exceptions,
Maxime Perrotin's avatar
Maxime Perrotin committed
7
8
     Ada.Exceptions,
     Ada.Characters.Latin_1;
Maxime Perrotin's avatar
Maxime Perrotin committed
9
10
11

use Ada.Directories;

12
13
package body TASTE.Concurrency_View is

Maxime Perrotin's avatar
Maxime Perrotin committed
14
15
   Newline : Character renames Ada.Characters.Latin_1.LF;

16
   procedure Debug_Dump (CV : Taste_Concurrency_View; Output : File_Type) is
Maxime Perrotin's avatar
Maxime Perrotin committed
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
      procedure Dump_Partition (Partition : CV_Partition) is
      begin
         for Block of Partition.Blocks loop
            Put_Line (Output, "Protected Block : " & To_String (Block.Name));
            for Provided of Block.Provided loop
               Put_Line (Output, " |_ PI : " & To_String (Provided.Name));
            end loop;
            for Required of Block.Required loop
               Put_Line (Output, " |_ RI : " & To_String (Required.Name));
            end loop;
            for Thread of Block.Calling_Threads loop
               Put_Line (Output, " |_ Calling_Thread : " & Thread);
            end loop;
            if Block.Node.Has_Value then
               Put_Line (Output, " |_ Node : "
                         & To_String (Block.Node.Unsafe_Just.Name));
               declare
                  P : constant Taste_Partition :=
                    Block.Node.Unsafe_Just.Find_Partition
                      (To_String (Block.Name)).Unsafe_Just;
               begin
                  Put_Line (Output, " |_ Partition : " & To_String (P.Name));
                  Put_Line (Output, "   |_ Coverage       : "
                            & P.Coverage'Img);
                  Put_Line (Output, "   |_ Package        : "
                            & To_String (P.Package_Name));
                  Put_Line (Output, "   |_ CPU Name       : "
                            & To_String (P.CPU_Name));
                  Put_Line (Output, "   |_ CPU Platform   : "
                            & P.CPU_Platform'Img);
                  Put_Line (Output, "   |_ CPU Classifier : "
                            & To_String (P.CPU_Classifier));
               end;
            end if;
Maxime Perrotin's avatar
Maxime Perrotin committed
51
         end loop;
52

Maxime Perrotin's avatar
Maxime Perrotin committed
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
         for Thread of Partition.Threads loop
            Put_Line (Output, "Thread : " & To_String (Thread.Name));
            Put_Line (Output, " |_ Port : "
                      & To_String (Thread.Entry_Port_Name));
            Put_Line (Output, " |_ Protected Block : "
                      & To_String (Thread.Protected_Block_Name));
            Put_Line (Output, " |_ Node : "
                      & To_String (Thread.Node.Value_Or
                        (Taste_Node'(Name   => US ("(none)"),
                                     others => <>)).Name));
            for Out_Port of Thread.Output_Ports loop
               Put_Line (Output, " |_ Output port remote thread : "
                         & To_String (Out_Port.Remote_Thread));
               Put_Line (Output, " |_ Output port remote PI : "
                         & To_String (Out_Port.Remote_PI));
            end loop;
         end loop;
      end Dump_Partition;
   begin
      for Node of CV.Nodes loop
         for Partition of Node.Partitions loop
            Dump_Partition (Partition);
Maxime Perrotin's avatar
Maxime Perrotin committed
75
         end loop;
76
77
78
      end loop;
   end Debug_Dump;

79
   --  This function translates a protected block into a template
80
   function Prepare_Template (B : Protected_Block) return Block_As_Template is
81
      Calling_Threads : Tag;
82
      Result          : Block_As_Template;
83
84
85
86
87
   begin
      for Thread of B.Calling_Threads loop
         Calling_Threads := Calling_Threads & Thread;
      end loop;

88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
      for PI of B.Provided loop
         declare
            Basic : constant Translate_Set := PI.PI.To_Template
              & Assoc ("Protected_Block_Name", To_String (PI.Name))
              & Assoc ("Caller_Is_Local", PI.Local_Caller);
         begin
            Result.Provided.Append (Basic);
         end;
      end loop;

      for RI of B.Required loop
         Result.Required.Append (RI.To_Template);
      end loop;

      Result.Header := +Assoc  ("Name",            To_String (B.Name))
                       & Assoc ("Calling_Threads", Calling_Threads)
                       & Assoc ("Node_Name",       To_String (B.Node.Value_Or
                         (Taste_Node'(Name => US (""), others => <>)).Name));
      return Result;
107
   end Prepare_Template;
108
109

   --  This function translates a thread definition into a template
Maxime Perrotin's avatar
Maxime Perrotin committed
110
   function To_Template (T : AADL_Thread) return Translate_Set is
111
112
113
114
      Remote_Thread    : Vector_Tag;
      Remote_PI        : Vector_Tag;  --  Name of the remote PI
      Remote_PI_Sort   : Vector_Tag;  --  ASN.1 type of the parameter
      Remote_PI_Module : Vector_Tag;  --  ASN.1 module containing the type
115
116
117
118
   begin
      for Out_Port of T.Output_Ports loop
         Remote_Thread := Remote_Thread & To_String (Out_Port.Remote_Thread);
         Remote_PI     := Remote_PI     & To_String (Out_Port.Remote_PI);
119
120
121
122
123
124
125
126
127
128
         --  Set the Asn.1 module and type of the optional RI parameter
         if Out_Port.RI.Params.Length > 0 then
            Remote_PI_Sort := Remote_PI_Sort
              & Out_Port.RI.Params.First_Element.Sort;
            Remote_PI_Module := Remote_PI_Module
              & Out_Port.RI.Params.First_Element.ASN1_Module;
         else
            Remote_PI_Sort   := Remote_PI_Sort   & "";
            Remote_PI_Module := Remote_PI_Module & "";
         end if;
129
130
131
      end loop;

      return Result : constant Translate_Set :=
132
133
134
135
136
137
138
139
140
141
142
        T.PI.To_Template   --  Template of the PI used to create the thread
        & Assoc ("Thread_Name",       To_String (T.Name))
        & Assoc ("Entry_Port_Name",   To_String (T.Entry_Port_Name))
        & Assoc ("RCM",               To_String (T.RCM))
        & Assoc ("Pro_Block_Name",    To_String (T.Protected_Block_Name))
        & Assoc ("Node_Name",         To_String (T.Node.Value_Or
          (Taste_Node'(Name => US (""), others => <>)).Name))
        & Assoc ("Remote_Threads",    Remote_Thread)
        & Assoc ("Remote_PIs",        Remote_PI)
        & Assoc ("Remote_PI_Sorts",   Remote_PI_Sort)
        & Assoc ("Remote_PI_Modules", Remote_PI_Module);
Maxime Perrotin's avatar
Maxime Perrotin committed
143
   end To_Template;
144

145
146
   --  Generate the the code by iterating over template folders
   procedure Generate_Code (CV : Taste_Concurrency_View)
147
   is
Maxime Perrotin's avatar
Maxime Perrotin committed
148
      Prefix   : constant String := CV.Base_Template_Path.Element
Maxime Perrotin's avatar
Maxime Perrotin committed
149
150
151
152
153
154
155
156
        & "templates/concurrency_view";
      --  To iterate over template folders
      ST       : Search_Type;
      Current  : Directory_Entry_Type;
      Filter   : constant Filter_Type := (Directory => True,
                                          others    => False);
      Output_File : File_Type;

157
   begin
Maxime Perrotin's avatar
Maxime Perrotin committed
158
159
160
161
162
163
164
165
166
167
168
169
170
      Start_Search (Search    => ST,
                    Pattern   => "",
                    Directory => Prefix,
                    Filter    => Filter);

      if not More_Entries (ST) then
         --  On Unix, this will never happen because "." and ".." are part
         --  of the search result. We'll only get an IO Error if the
         --  concurrency_view folder itself does not exist
         raise Concurrency_View_Error with
           "No folders with templates for concurrency view";
      end if;

171
      --  Iterate over the folders containing template files
Maxime Perrotin's avatar
Maxime Perrotin committed
172
173
174
175
176
177
178
179
      while More_Entries (ST) loop
         Get_Next_Entry (ST, Current);

         --  Ignore Unix special directories
         if Simple_Name (Current) = "." or Simple_Name (Current) = ".." then
            goto continue;
         end if;

Maxime Perrotin's avatar
Maxime Perrotin committed
180
         declare
Maxime Perrotin's avatar
Maxime Perrotin committed
181
182
            Path  : constant String  := Full_Name (Current);

183
184
            function Generate_Partition (Node_Name      : String;
                                         Partition_Name : String)
Maxime Perrotin's avatar
Maxime Perrotin committed
185
                                         return String
Maxime Perrotin's avatar
Maxime Perrotin committed
186
            is
Maxime Perrotin's avatar
Maxime Perrotin committed
187
188
               Partition       : constant CV_Partition :=
                 CV.Nodes (Node_Name).Partitions (Partition_Name);
Maxime Perrotin's avatar
Maxime Perrotin committed
189
               Threads         : Unbounded_String;
190
               Thread_Names    : Tag;
Maxime Perrotin's avatar
Maxime Perrotin committed
191
               Blocks          : Unbounded_String;
Maxime Perrotin's avatar
Maxime Perrotin committed
192
               Partition_Assoc : Translate_Set;
193
194
195
196
197
               --  Connections between threads:
               Thread_Src_Name : Vector_Tag;
               Thread_Src_Port : Vector_Tag;
               Thread_Dst_Name : Vector_Tag;
               Thread_Dst_Port : Vector_Tag;
Maxime Perrotin's avatar
Maxime Perrotin committed
198
            begin
199
200
201
               for T of Partition.Threads loop
                  declare
                     --  Render each thread
202
                     Name         : constant String := To_String (T.Name);
203
                     Thread_Assoc : constant Translate_Set := T.To_Template;
204
                     Result       : constant String :=
205
206
                       (Parse (Path & "/thread.tmplt", Thread_Assoc));
                  begin
207
208
209
210
211
212
213
214
215
216
217
                     Threads      := Threads & Newline & Result;
                     Thread_Names := Thread_Names & Name;
                     for P of T.Output_Ports loop
                        Thread_Src_Name := Thread_Src_Name & Name;
                        Thread_Src_Port := Thread_Src_Port
                          & To_String (P.Name);
                        Thread_Dst_Name := Thread_Dst_Name
                          & To_String (P.Remote_Thread);
                        Thread_Dst_Port := Thread_Dst_Port
                          & To_String (P.Remote_PI);
                     end loop;
218
                  end;
Maxime Perrotin's avatar
Maxime Perrotin committed
219
               end loop;
220

221
222
               for B of Partition.Blocks loop
                  declare
223
224
                     Tmpl        : constant Block_As_Template :=
                       B.Prepare_Template;
225
                     Block_Assoc : Translate_Set := Tmpl.Header;
226
227
                     PI_Tag      : Unbounded_String;
                     RI_Tag      : Unbounded_String;
228
229
                  begin
                     for PI_Assoc of Tmpl.Provided loop
Maxime Perrotin's avatar
Maxime Perrotin committed
230
                        PI_Tag := PI_Tag & Newline
231
232
233
                          & String'(Parse (Path & "/pi.tmplt", PI_Assoc));
                     end loop;
                     for RI_Assoc of Tmpl.Required loop
Maxime Perrotin's avatar
Maxime Perrotin committed
234
                        RI_Tag := RI_Tag & Newline
235
236
237
238
239
240
                          & String'(Parse (Path & "/ri.tmplt", RI_Assoc));
                     end loop;
                     Block_Assoc := Block_Assoc
                       & Assoc ("Provided", PI_Tag)
                       & Assoc ("Required", RI_Tag);

Maxime Perrotin's avatar
Maxime Perrotin committed
241
                     Blocks := Blocks & Newline &
242
243
                       String'(Parse (Path & "/block.tmplt", Block_Assoc));
                  end;
Maxime Perrotin's avatar
Maxime Perrotin committed
244
               end loop;
245
246
247
               --  Association includes Name, Coverage, CPU Info, etc.
               --  (see taste-deployment_view.ads for the complete list)
               Partition_Assoc := Partition.Deployment_Partition.To_Template
248
249
250
251
252
253
254
255
                 & Assoc ("Threads",         Threads)
                 & Assoc ("Thread_Names",    Thread_Names)
                 & Assoc ("Node_Name",       Node_Name)
                 & Assoc ("Blocks",          Blocks)
                 & Assoc ("Thread_Src_Name", Thread_Src_Name)
                 & Assoc ("Thread_Src_Port", Thread_Src_Port)
                 & Assoc ("Thread_Dst_Name", Thread_Dst_Name)
                 & Assoc ("Thread_Dst_Port", Thread_Dst_Port);
Maxime Perrotin's avatar
Maxime Perrotin committed
256
               return Parse (Path & "/partition.tmplt", Partition_Assoc);
Maxime Perrotin's avatar
Maxime Perrotin committed
257
            end Generate_Partition;
Maxime Perrotin's avatar
Maxime Perrotin committed
258

259
260
            --  Generate the code for one node
            function Generate_Node (Node_Name : String) return String is
261
262
263
               Partitions      : Unbounded_String;
               Partition_Names : Tag;
               Node_Assoc      : Translate_Set;
264
            begin
Maxime Perrotin's avatar
Maxime Perrotin committed
265
               for Partition in CV.Nodes (Node_Name).Partitions.Iterate loop
266
267
                  Partition_Names := Partition_Names
                    & CV_Partitions.Key (Partition);
268
269
270
271
                  Partitions := Partitions & Newline
                    & Generate_Partition
                    (Partition_Name => CV_Partitions.Key (Partition),
                     Node_Name      => Node_Name);
Maxime Perrotin's avatar
Maxime Perrotin committed
272
               end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
273
               Node_Assoc := +Assoc ("Partitions", Partitions)
274
                  & Assoc ("Partition_Names", Partition_Names)
Maxime Perrotin's avatar
Maxime Perrotin committed
275
                  & Assoc ("Node_Name", Node_Name);
276
277
               return Parse (Path & "/node.tmplt", Node_Assoc);
            end Generate_Node;
Maxime Perrotin's avatar
Maxime Perrotin committed
278

Maxime Perrotin's avatar
Maxime Perrotin committed
279
280
281
282
283
284
285
286
287
288
289
            Nodes      : Unbounded_String;
            CV_Out_Dir : constant String  :=
              CV.Base_Output_Path.Element & "/concurrency_view/";
            Tmpl_File  : constant String  := Path & "/filesys.tmplt";
            Tmpl_Sys   : constant String  := Path & "/system.tmplt";
            Valid_Dir  : constant Boolean := Exists (Tmpl_File);
            File_Sys   : constant String  :=
              (if Valid_Dir then Strip_String (Parse (Tmpl_File)) else "");
            Trig_Sys   : constant Boolean := Exists (Tmpl_Sys);
            Set_Sys    : Translate_Set;
            Node_Names : Tag;
290
291
292
293
         begin
            for Node in CV.Nodes.Iterate loop
               declare
                  Node_Name    : constant String := CV_Nodes.Key (Node);
Maxime Perrotin's avatar
Maxime Perrotin committed
294
                  Output_Dir   : constant String := CV_Out_Dir & Node_Name;
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
                  Do_It        : constant Boolean :=
                    Exists (Path & "/filenode.tmplt");
                  Filename_Set : constant Translate_Set :=
                    +Assoc ("Node_Name", Node_Name);
                  --  Get output file name from template
                  File_Name    : constant String :=
                    (if Do_It then
                        Strip_String
                       (Parse (Path & "/filenode.tmplt", Filename_Set))
                     else "");
                  --  Check if file already exists
                  Present      : constant Boolean :=
                    (File_Name /= "" and Exists (Output_Dir & File_Name));
                  Trig_Tmpl    : constant Translate_Set :=
                    +Assoc ("Filename_Is_Present", Present);
                  Trigger      : constant Boolean :=
                    (Node_Name /= "interfaceview"
                     and then Exists (Path & "/trigger.tmplt") and then
                     Strip_String
                       (Parse (Path & "/trigger.tmplt", Trig_Tmpl)) = "TRUE");
                  Node_Content : constant String :=
                    (if Trigger then Generate_Node (Node_Name)
                     else "");
               begin
                  if Trigger then
Maxime Perrotin's avatar
Maxime Perrotin committed
320
321
                     Node_Names := Node_Names & Node_Name;
                     Nodes      := Nodes & Newline & Node_Content;
322
323
324
325
326
327
328
329
330
331
332
                     if File_Name /= "" then
                        Create_Path (Output_Dir);
                        Create (File => Output_File,
                                Mode => Out_File,
                                Name => Output_Dir & "/" & File_Name);
                        Put_Line (Output_File, Node_Content);
                        Close (Output_File);
                     end if;
                  end if;
               end;
            end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
333
334
335
336
337
338
339
340
341
342
343
            if Trig_Sys and File_Sys /= "" then
               Put_Info ("Generating system concurrency view");
               Set_Sys := +Assoc ("Nodes", Nodes)
                 & Assoc ("Node_Names", Node_Names);
               Create_Path (CV_Out_Dir);
               Create (File => Output_File,
                       Mode => Out_File,
                       Name => CV_Out_Dir & File_Sys);
               Put_Line (Output_File, Parse (Tmpl_Sys, Set_Sys));
               Close (Output_File);
            end if;
Maxime Perrotin's avatar
Maxime Perrotin committed
344
         end;
Maxime Perrotin's avatar
Maxime Perrotin committed
345
346
         <<continue>>
      end loop;
Maxime Perrotin's avatar
Maxime Perrotin committed
347
      End_Search (ST);
348
   end Generate_Code;
Maxime Perrotin's avatar
Maxime Perrotin committed
349
350
351

   procedure Generate_CV (CV : Taste_Concurrency_View) is
   begin
352
353
354
355
      --  In this first iteration Nodes are generated in standalone files,
      --  and they include their processes. It would be useful to be able
      --  to decide if processes could also have their own files, since
      --  in the future they may be more than one process per node (for TSP).
356
357
358
359
360
361
362
363
      CV.Generate_Code;

--      for Node in CV.Nodes.Iterate loop
--         if CV_Nodes.Key (Node) /= "interfaceview" then
--            CV.Generate_Node (CV_Nodes.Key (Node));
--         end if;
--      end loop;

Maxime Perrotin's avatar
Maxime Perrotin committed
364
365
366
367
368
369
   exception
      when Error : Concurrency_View_Error | Ada.IO_Exceptions.Name_Error =>
         Put_Error ("Concurrency View : "
                    & Ada.Exceptions.Exception_Message (Error));
         raise Quit_Taste;
   end Generate_CV;
Maxime Perrotin's avatar
Maxime Perrotin committed
370

371
end TASTE.Concurrency_View;