[Ada] Elaboration order v4.0 and infinite loops

Message ID 20190711080342.GA95066@adacore.com
State New
Headers show
Series
  • [Ada] Elaboration order v4.0 and infinite loops
Related show

Commit Message

Pierre-Marie de Rodat July 11, 2019, 8:03 a.m.
This patch introduces binder switch -d_S which prompts the various
phases of the elaboration order mechanism to output a short message
concerning their commencement and completion. The output is useful when
trying to determine whether a phase is stuck in an infinite loop.

------------
-- Source --
------------

--  main.adb

procedure Main is begin null; end Main;

----------------------------
-- Compilation and output --
----------------------------

$ gnatmake -q main.adb -bargs -d_S -d_V
elaborating units...
collecting units...
units collected.
constructing library graph...
validating library graph...
library graph validated.
library graph constructed.
constructing invocation graph...
validating invocation graph...
invocation graph validated.
invocation graph constructed.
augmenting library graph...
library graph augmented.
discovering components...
components discovered.
validating elaboration order...
elaboration order validated.
units elaborated.

Tested on x86_64-pc-linux-gnu, committed on trunk

2019-07-11  Hristian Kirtchev  <kirtchev@adacore.com>

gcc/ada/

	* bindo.adb: Update the section of switches and debugging
	elaboration issues.
	* bindo.ads: Add type Elaboration_Phase.
	* bindo-augmentors.adb: Add use clause for
	Bindo.Writers.Phase_Writers.
	(Augment_Library_Graph): Signal the start and end of the
	aubmentation phase.
	* bindo-builders.adb: Add with and use clause for Bindo.Writers.
	Add use clause for Bindo.Writers.Phase_Writers.
	(Build_Invocation_Graph): Signal the start and end of the
	invocation graph construction phase.
	(Build_Library_Graph): Signal the start and end of the library
	graph construction phase.
	* bindo-diagnostics.adb: Add use clause for
	Bindo.Writers.Phase_Writers.
	(Diagnose_Cycle): Signal the start and end of the cycle
	diagnostic phase.
	* bindo-elaborators.adb: Add use clause for
	Bindo.Writers.Phase_Writers.
	(Elaborate_Units): Signal the start and end of the unit
	elaboration phase.
	* bindo-graphs.adb: Add use clause for
	Bindo.Writers.Phase_Writers.
	(Find_Components): Signal the start and end of the component
	discovery phase.
	(Find_Cycles): Signal the start and end of the cycle discovery
	phase.
	* bindo-units.adb: Add with and use clause for Bindo.Writers.
	Add use clause for Bindo.Writers.Phase_Writers.
	(Collect_Elaborable_Units): Signal the start and end of the unit
	collection phase.
	* bindo-validators.adb: Add with and use clause for
	Bindo.Writers.  Add use clause for Bindo.Writers.Phase_Writers.
	(Validate_Cycles, Validate_Elaboration_Order,
	Validate_Invocation_Graph, Validate_Library_Graph): Signal the
	start and end of the libray graph validation phase.
	* bindo-writers.ads, bindo-writers.adb: Add new nested package
	Phase_Writers.
	* debug.adb: Update the documentation of switch d_S.

Patch

--- gcc/ada/bindo-augmentors.adb
+++ gcc/ada/bindo-augmentors.adb
@@ -27,7 +27,9 @@  with Debug;  use Debug;
 with Output; use Output;
 with Types;  use Types;
 
-with Bindo.Writers; use Bindo.Writers;
+with Bindo.Writers;
+use  Bindo.Writers;
+use  Bindo.Writers.Phase_Writers;
 
 package body Bindo.Augmentors is
 
@@ -124,6 +126,8 @@  package body Bindo.Augmentors is
             return;
          end if;
 
+         Start_Phase (Library_Graph_Augmentation);
+
          --  Prepare the statistics data
 
          Longest_Path  := 0;
@@ -131,6 +135,8 @@  package body Bindo.Augmentors is
 
          Visit_Elaboration_Roots (Inv_Graph, Lib_Graph);
          Write_Statistics;
+
+         End_Phase (Library_Graph_Augmentation);
       end Augment_Library_Graph;
 
       ----------------------------

--- gcc/ada/bindo-builders.adb
+++ gcc/ada/bindo-builders.adb
@@ -37,6 +37,10 @@  use  Bindo.Validators;
 use  Bindo.Validators.Invocation_Graph_Validators;
 use  Bindo.Validators.Library_Graph_Validators;
 
+with Bindo.Writers;
+use  Bindo.Writers;
+use  Bindo.Writers.Phase_Writers;
+
 with GNAT;                 use GNAT;
 with GNAT.Dynamic_HTables; use GNAT.Dynamic_HTables;
 
@@ -99,6 +103,8 @@  package body Bindo.Builders is
       begin
          pragma Assert (Present (Lib_G));
 
+         Start_Phase (Invocation_Graph_Construction);
+
          --  Prepare the global data
 
          Inv_Graph :=
@@ -111,6 +117,7 @@  package body Bindo.Builders is
          For_Each_Elaborable_Unit (Create_Edges'Access);
 
          Validate_Invocation_Graph (Inv_Graph);
+         End_Phase (Invocation_Graph_Construction);
 
          return Inv_Graph;
       end Build_Invocation_Graph;
@@ -375,6 +382,8 @@  package body Bindo.Builders is
 
       function Build_Library_Graph return Library_Graph is
       begin
+         Start_Phase (Library_Graph_Construction);
+
          --  Prepare the global data
 
          Lib_Graph :=
@@ -388,6 +397,7 @@  package body Bindo.Builders is
          Create_Forced_Edges;
 
          Validate_Library_Graph (Lib_Graph);
+         End_Phase (Library_Graph_Construction);
 
          return Lib_Graph;
       end Build_Library_Graph;

--- gcc/ada/bindo-diagnostics.adb
+++ gcc/ada/bindo-diagnostics.adb
@@ -36,6 +36,7 @@  use  Bindo.Validators.Cycle_Validators;
 with Bindo.Writers;
 use  Bindo.Writers;
 use  Bindo.Writers.Cycle_Writers;
+use  Bindo.Writers.Phase_Writers;
 
 package body Bindo.Diagnostics is
 
@@ -348,6 +349,8 @@  package body Bindo.Diagnostics is
       Next_Edge    : Library_Graph_Edge_Id;
 
    begin
+      Start_Phase (Cycle_Diagnostics);
+
       First_Edge := No_Library_Graph_Edge;
 
       --  Inspect the edges of the cycle in pairs, emitting diagnostics based
@@ -402,6 +405,8 @@  package body Bindo.Diagnostics is
         (G          => Lib_Graph,
          Cycle      => Cycle,
          First_Edge => First_Edge);
+
+      End_Phase (Cycle_Diagnostics);
    end Diagnose_Cycle;
 
    --------------------------------------

--- gcc/ada/bindo-elaborators.adb
+++ gcc/ada/bindo-elaborators.adb
@@ -54,6 +54,7 @@  use  Bindo.Writers.Dependency_Writers;
 use  Bindo.Writers.Elaboration_Order_Writers;
 use  Bindo.Writers.Invocation_Graph_Writers;
 use  Bindo.Writers.Library_Graph_Writers;
+use  Bindo.Writers.Phase_Writers;
 use  Bindo.Writers.Unit_Closure_Writers;
 
 with GNAT;        use GNAT;
@@ -711,6 +712,8 @@  package body Bindo.Elaborators is
          Status    : Elaboration_Order_Status;
 
       begin
+         Start_Phase (Unit_Elaboration);
+
          --  Initialize all unit-related data structures and gather all units
          --  that need elaboration.
 
@@ -786,6 +789,7 @@  package body Bindo.Elaborators is
          --  Destroy all unit-related data structures
 
          Finalize_Units;
+         End_Phase (Unit_Elaboration);
 
          --  Halt the bind when there is no satisfactory elaboration order
 

--- gcc/ada/bindo-graphs.adb
+++ gcc/ada/bindo-graphs.adb
@@ -31,6 +31,7 @@  with Output; use Output;
 
 with Bindo.Writers;
 use  Bindo.Writers;
+use  Bindo.Writers.Phase_Writers;
 
 package body Bindo.Graphs is
 
@@ -2636,6 +2637,8 @@  package body Bindo.Graphs is
       begin
          pragma Assert (Present (G));
 
+         Start_Phase (Component_Discovery);
+
          --  Initialize or reinitialize the components of the graph
 
          Initialize_Components (G);
@@ -2660,6 +2663,7 @@  package body Bindo.Graphs is
          --  before they can be elaborated.
 
          Update_Pending_Predecessors_Of_Components (G);
+         End_Phase (Component_Discovery);
       end Find_Components;
 
       -----------------
@@ -2683,6 +2687,8 @@  package body Bindo.Graphs is
       begin
          pragma Assert (Present (G));
 
+         Start_Phase (Cycle_Discovery);
+
          --  The cycles of graph G are discovered using Tarjan's enumeration
          --  of the elementary circuits of a directed-graph algorithm. Do not
          --  modify this code unless you intimately understand the algorithm.
@@ -2721,6 +2727,8 @@  package body Bindo.Graphs is
                Cycle_Count => Cycle_Count,
                Cycle_Limit => All_Cycle_Limit);
          end loop;
+
+         End_Phase (Cycle_Discovery);
       end Find_Cycles;
 
       --------------------------------

--- gcc/ada/bindo-units.adb
+++ gcc/ada/bindo-units.adb
@@ -23,6 +23,10 @@ 
 --                                                                          --
 ------------------------------------------------------------------------------
 
+with Bindo.Writers;
+use  Bindo.Writers;
+use  Bindo.Writers.Phase_Writers;
+
 package body Bindo.Units is
 
    -------------------
@@ -79,9 +83,13 @@  package body Bindo.Units is
 
    procedure Collect_Elaborable_Units is
    begin
+      Start_Phase (Unit_Collection);
+
       for U_Id in ALI.Units.First .. ALI.Units.Last loop
          Process_Unit (U_Id);
       end loop;
+
+      End_Phase (Unit_Collection);
    end Collect_Elaborable_Units;
 
    ------------------------

--- gcc/ada/bindo-validators.adb
+++ gcc/ada/bindo-validators.adb
@@ -27,7 +27,12 @@  with Debug;  use Debug;
 with Output; use Output;
 with Types;  use Types;
 
-with Bindo.Units; use Bindo.Units;
+with Bindo.Units;
+use  Bindo.Units;
+
+with Bindo.Writers;
+use  Bindo.Writers;
+use  Bindo.Writers.Phase_Writers;
 
 package body Bindo.Validators is
 
@@ -188,6 +193,8 @@  package body Bindo.Validators is
             return;
          end if;
 
+         Start_Phase (Cycle_Validation);
+
          Iter := Iterate_All_Cycles (G);
          while Has_Next (Iter) loop
             Next (Iter, Cycle);
@@ -195,6 +202,8 @@  package body Bindo.Validators is
             Validate_Cycle (G, Cycle);
          end loop;
 
+         End_Phase (Cycle_Validation);
+
          if Has_Invalid_Cycle then
             raise Invalid_Cycle;
          end if;
@@ -330,8 +339,12 @@  package body Bindo.Validators is
             return;
          end if;
 
+         Start_Phase (Elaboration_Order_Validation);
+
          Validate_Units (Order);
 
+         End_Phase (Elaboration_Order_Validation);
+
          if Has_Invalid_Data then
             raise Invalid_Elaboration_Order;
          end if;
@@ -444,8 +457,12 @@  package body Bindo.Validators is
             return;
          end if;
 
+         Start_Phase (Invocation_Graph_Validation);
+
          Validate_Invocation_Graph_Vertices (G);
-         Validate_Invocation_Graph_Edges (G);
+         Validate_Invocation_Graph_Edges    (G);
+
+         End_Phase (Invocation_Graph_Validation);
 
          if Has_Invalid_Data then
             raise Invalid_Invocation_Graph;
@@ -638,8 +655,12 @@  package body Bindo.Validators is
             return;
          end if;
 
+         Start_Phase (Library_Graph_Validation);
+
          Validate_Library_Graph_Vertices (G);
-         Validate_Library_Graph_Edges (G);
+         Validate_Library_Graph_Edges    (G);
+
+         End_Phase (Library_Graph_Validation);
 
          if Has_Invalid_Data then
             raise Invalid_Library_Graph;

--- gcc/ada/bindo-writers.adb
+++ gcc/ada/bindo-writers.adb
@@ -1404,6 +1404,94 @@  package body Bindo.Writers is
       end Write_Statistics;
    end Library_Graph_Writers;
 
+   -------------------
+   -- Phase_Writers --
+   -------------------
+
+   package body Phase_Writers is
+
+      subtype Phase_Message is String (1 .. 32);
+
+      --  The following table contains the phase-specific messages for phase
+      --  completion.
+
+      End_Messages : constant array (Elaboration_Phase) of Phase_Message :=
+        (Component_Discovery           => "components discovered.          ",
+         Cycle_Diagnostics             => "cycle diagnosed.                ",
+         Cycle_Discovery               => "cycles discovered.              ",
+         Cycle_Validation              => "cycles validated.               ",
+         Elaboration_Order_Validation  => "elaboration order validated.    ",
+         Invocation_Graph_Construction => "invocation graph constructed.   ",
+         Invocation_Graph_Validation   => "invocation graph validated.     ",
+         Library_Graph_Augmentation    => "library graph augmented.        ",
+         Library_Graph_Construction    => "library graph constructed.      ",
+         Library_Graph_Elaboration     => "library graph elaborated.       ",
+         Library_Graph_Validation      => "library graph validated.        ",
+         Unit_Collection               => "units collected.                ",
+         Unit_Elaboration              => "units elaborated.               ");
+
+      --  The following table contains the phase-specific messages for phase
+      --  commencement.
+
+      Start_Messages : constant array (Elaboration_Phase) of Phase_Message :=
+        (Component_Discovery           => "discovering components...       ",
+         Cycle_Diagnostics             => "diagnosing cycle...             ",
+         Cycle_Discovery               => "discovering cycles...           ",
+         Cycle_Validation              => "validating cycles...            ",
+         Elaboration_Order_Validation  => "validating elaboration order... ",
+         Invocation_Graph_Construction => "constructing invocation graph...",
+         Invocation_Graph_Validation   => "validating invocation graph...  ",
+         Library_Graph_Augmentation    => "augmenting library graph...     ",
+         Library_Graph_Construction    => "constructing library graph...   ",
+         Library_Graph_Elaboration     => "elaborating library graph...    ",
+         Library_Graph_Validation      => "validating library graph...     ",
+         Unit_Collection               => "collecting units...             ",
+         Unit_Elaboration              => "elaborating units...            ");
+
+      -----------------------
+      -- Local subprograms --
+      -----------------------
+
+      procedure Write_Phase_Message (Msg : Phase_Message);
+      pragma Inline (Write_Phase_Message);
+      --  Write elaboration phase-related message Msg to standard output
+
+      ---------------
+      -- End_Phase --
+      ---------------
+
+      procedure End_Phase (Phase : Elaboration_Phase) is
+      begin
+         Write_Phase_Message (End_Messages (Phase));
+      end End_Phase;
+
+      -----------------
+      -- Start_Phase --
+      -----------------
+
+      procedure Start_Phase (Phase : Elaboration_Phase) is
+      begin
+         Write_Phase_Message (Start_Messages (Phase));
+      end Start_Phase;
+
+      -------------------------
+      -- Write_Phase_Message --
+      -------------------------
+
+      procedure Write_Phase_Message (Msg : Phase_Message) is
+      begin
+         --  Nothing to do when switch -d_S (output elaboration order status)
+         --  is not in effect.
+
+         if not Debug_Flag_Underscore_SS then
+            return;
+         end if;
+
+         Write_Str (Msg);
+         Write_Eol;
+      end Write_Phase_Message;
+   end Phase_Writers;
+
    --------------------------
    -- Unit_Closure_Writers --
    --------------------------

--- gcc/ada/bindo-writers.ads
+++ gcc/ada/bindo-writers.ads
@@ -132,6 +132,23 @@  package Bindo.Writers is
 
    end Library_Graph_Writers;
 
+   -------------------
+   -- Phase_Writers --
+   -------------------
+
+   package Phase_Writers is
+      procedure End_Phase (Phase : Elaboration_Phase);
+      pragma Inline (End_Phase);
+      --  Write the end message associated with elaboration phase Phase to
+      --  standard output.
+
+      procedure Start_Phase (Phase : Elaboration_Phase);
+      pragma Inline (Start_Phase);
+      --  Write the start message associated with elaboration phase Phase to
+      --  standard output.
+
+   end Phase_Writers;
+
    --------------------------
    -- Unit_Closure_Writers --
    --------------------------

--- gcc/ada/bindo.adb
+++ gcc/ada/bindo.adb
@@ -355,6 +355,11 @@  package body Bindo is
    --
    --        GNATbind output the cycle paths in text format to standard output
    --
+   --  -d_S  Output elaboration-order status information
+   --
+   --        GNATbind outputs trace information concerning the status of its
+   --        various phases to standard output.
+   --
    --  -d_T  Output elaboration-order trace information
    --
    --        GNATbind outputs trace information on elaboration-order detection
@@ -416,6 +421,11 @@  package body Bindo is
    --    plgv   --  print library-graph vertex
    --    pu     --  print units
    --
+   --  * Apparent infinite loop
+   --
+   --    The elaboration order mechanism appears to be stuck in an infinite
+   --    loop. Use switch -d_S to output the status of each elaboration phase.
+   --
    --  * Invalid elaboration order
    --
    --    The elaboration order is invalid when:

--- gcc/ada/bindo.ads
+++ gcc/ada/bindo.ads
@@ -31,6 +31,24 @@  with Namet; use Namet;
 
 package Bindo is
 
+   --  The following type represents the various phases of the elaboration
+   --  order mechanism.
+
+   type Elaboration_Phase is
+     (Component_Discovery,
+      Cycle_Diagnostics,
+      Cycle_Discovery,
+      Cycle_Validation,
+      Elaboration_Order_Validation,
+      Invocation_Graph_Construction,
+      Invocation_Graph_Validation,
+      Library_Graph_Augmentation,
+      Library_Graph_Construction,
+      Library_Graph_Elaboration,
+      Library_Graph_Validation,
+      Unit_Collection,
+      Unit_Elaboration);
+
    --  The following type represents the various kinds of precedence between
    --  two items.
 

--- gcc/ada/debug.adb
+++ gcc/ada/debug.adb
@@ -394,8 +394,8 @@  package body Debug is
    --  d_P  Output cycle paths
    --  d_Q
    --  d_R
-   --  d_S
-   --  d_T  Output elaboration order trace information
+   --  d_S  Output elaboration-order status
+   --  d_T  Output elaboration-order trace information
    --  d_U
    --  d_V  Validate bindo cycles, graphs, and order
    --  d_W
@@ -1167,6 +1167,9 @@  package body Debug is
 
    --  d_P  GNATBIND outputs the cycle paths to standard output
 
+   --  d_S  GNATBIND outputs trace information concerning the status of its
+   --       various phases to standard output.
+
    --  d_T  GNATBIND outputs trace information of elaboration order detection
    --       activities to standard output.