OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [gnu-src/] [gcc-4.5.1/] [gcc/] [ada/] [gnatmem.adb] - Rev 454

Go to most recent revision | Compare with Previous | Blame | View Log

------------------------------------------------------------------------------
--                                                                          --
--                         GNAT COMPILER COMPONENTS                         --
--                                                                          --
--                              G N A T M E M                               --
--                                                                          --
--                                 B o d y                                  --
--                                                                          --
--                     Copyright (C) 1997-2008, AdaCore                     --
--                                                                          --
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
-- terms of the  GNU General Public License as published  by the Free Soft- --
-- ware  Foundation;  either version 3,  or (at your option) any later ver- --
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
-- OUT 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  distributed with GNAT; see file COPYING3.  If not, go to --
-- http://www.gnu.org/licenses for a complete copy of the license.          --
--                                                                          --
-- GNAT was originally developed  by the GNAT team at  New York University. --
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
--                                                                          --
------------------------------------------------------------------------------
 
--  GNATMEM is a utility that tracks memory leaks. It is based on a simple
--  idea:
 
--      - Read the allocation log generated by the application linked using
--        instrumented memory allocation and deallocation (see memtrack.adb for
--        this circuitry). To get access to this functionality, the application
--        must be relinked with library libgmem.a:
 
--            $ gnatmake my_prog -largs -lgmem
 
--        The running my_prog will produce a file named gmem.out that will be
--        parsed by gnatmem.
 
--      - Record a reference to the allocated memory on each allocation call
 
--      - Suppress this reference on deallocation
 
--      - At the end of the program, remaining references are potential leaks.
--        sort them out the best possible way in order to locate the root of
--        the leak.
 
--   This capability is not supported on all platforms, please refer to
--   memtrack.adb for further information.
 
--   In order to help finding out the real leaks,  the notion of "allocation
--   root" is defined. An allocation root is a specific point in the program
--   execution generating memory allocation where data is collected (such as
--   number of allocations, amount of memory allocated, high water mark, etc.)
 
with Ada.Float_Text_IO;
with Ada.Integer_Text_IO;
with Ada.Text_IO;             use Ada.Text_IO;
 
with System;                  use System;
with System.Storage_Elements; use System.Storage_Elements;
 
with GNAT.Command_Line;       use GNAT.Command_Line;
with GNAT.Heap_Sort_G;
with GNAT.OS_Lib;             use GNAT.OS_Lib;
with GNAT.HTable;             use GNAT.HTable;
 
with Gnatvsn; use Gnatvsn;
with Memroot; use Memroot;
 
procedure Gnatmem is
 
   package Int_IO renames Ada.Integer_Text_IO;
 
   ------------------------
   -- Other Declarations --
   ------------------------
 
   type Storage_Elmt is record
      Elmt : Character;
      --  *  = End of log file
      --  A  = found a ALLOC mark in the log
      --  D  = found a DEALL mark in the log
 
      Address : Integer_Address;
      Size    : Storage_Count;
      Timestamp : Duration;
   end record;
   --  This type is used to read heap operations from the log file.
   --  Elmt contains the type of the operation, which can be either
   --  allocation, deallocation, or a special mark indicating the
   --  end of the log file. Address is used to store address on the
   --  heap where a chunk was allocated/deallocated, size is only
   --  for A event and contains size of the allocation, and Timestamp
   --  is the clock value at the moment of allocation
 
   Log_Name : String_Access;
   --  Holds the name of the heap operations log file
 
   Program_Name : String_Access;
   --  Holds the name of the user executable
 
   function Read_Next return Storage_Elmt;
   --  Reads next dynamic storage operation from the log file
 
   function Mem_Image (X : Storage_Count) return String;
   --  X is a size in storage_element. Returns a value
   --  in Megabytes, Kilobytes or Bytes as appropriate.
 
   procedure Process_Arguments;
   --  Read command line arguments
 
   procedure Usage;
   --  Prints out the option help
 
   function Gmem_Initialize (Dumpname : String) return Boolean;
   --  Opens the file represented by Dumpname and prepares it for
   --  work. Returns False if the file does not have the correct format, True
   --  otherwise.
 
   procedure Gmem_A2l_Initialize (Exename : String);
   --  Initialises the convert_addresses interface by supplying it with
   --  the name of the executable file Exename
 
   -----------------------------------
   -- HTable address --> Allocation --
   -----------------------------------
 
   type Allocation is record
      Root : Root_Id;
      Size : Storage_Count;
   end record;
 
   type Address_Range is range 0 .. 4097;
   function H (A : Integer_Address) return Address_Range;
   No_Alloc : constant Allocation := (No_Root_Id, 0);
 
   package Address_HTable is new GNAT.HTable.Simple_HTable (
     Header_Num => Address_Range,
     Element    => Allocation,
     No_Element => No_Alloc,
     Key        => Integer_Address,
     Hash       => H,
     Equal      => "=");
 
   BT_Depth   : Integer := 1;
 
   --  Some global statistics
 
   Global_Alloc_Size : Storage_Count := 0;
   --  Total number of bytes allocated during the lifetime of a program
 
   Global_High_Water_Mark : Storage_Count := 0;
   --  Largest amount of storage ever in use during the lifetime
 
   Global_Nb_Alloc : Integer := 0;
   --  Total number of allocations
 
   Global_Nb_Dealloc : Integer := 0;
   --  Total number of deallocations
 
   Nb_Root : Integer := 0;
   --  Total number of allocation roots
 
   Nb_Wrong_Deall : Integer := 0;
   --  Total number of wrong deallocations (i.e. without matching alloc)
 
   Minimum_Nb_Leaks : Integer := 1;
   --  How many unfreed allocs should be in a root for it to count as leak
 
   T0 : Duration := 0.0;
   --  The moment at which memory allocation routines initialized (should
   --  be pretty close to the moment the program started since there are
   --  always some allocations at RTL elaboration
 
   Tmp_Alloc     : Allocation;
   Dump_Log_Mode : Boolean := False;
   Quiet_Mode    : Boolean := False;
 
   ------------------------------
   -- Allocation Roots Sorting --
   ------------------------------
 
   Sort_Order : String (1 .. 3) := "nwh";
   --  This is the default order in which sorting criteria will be applied
   --  n -  Total number of unfreed allocations
   --  w -  Final watermark
   --  h -  High watermark
 
   --------------------------------
   -- GMEM functionality binding --
   --------------------------------
 
   ---------------------
   -- Gmem_Initialize --
   ---------------------
 
   function Gmem_Initialize (Dumpname : String) return Boolean is
      function Initialize (Dumpname : System.Address) return Duration;
      pragma Import (C, Initialize, "__gnat_gmem_initialize");
 
      S : aliased String := Dumpname & ASCII.NUL;
 
   begin
      T0 := Initialize (S'Address);
      return T0 > 0.0;
   end Gmem_Initialize;
 
   -------------------------
   -- Gmem_A2l_Initialize --
   -------------------------
 
   procedure Gmem_A2l_Initialize (Exename : String) is
      procedure A2l_Initialize (Exename : System.Address);
      pragma Import (C, A2l_Initialize, "__gnat_gmem_a2l_initialize");
 
      S : aliased String := Exename & ASCII.NUL;
 
   begin
      A2l_Initialize (S'Address);
   end Gmem_A2l_Initialize;
 
   ---------------
   -- Read_Next --
   ---------------
 
   function Read_Next return Storage_Elmt is
      procedure Read_Next (buf : System.Address);
      pragma Import (C, Read_Next, "__gnat_gmem_read_next");
 
      S : Storage_Elmt;
 
   begin
      Read_Next (S'Address);
      return S;
   end Read_Next;
 
   -------
   -- H --
   -------
 
   function H (A : Integer_Address) return Address_Range is
   begin
      return Address_Range (A mod Integer_Address (Address_Range'Last));
   end H;
 
   ---------------
   -- Mem_Image --
   ---------------
 
   function Mem_Image (X : Storage_Count) return String is
      Ks   : constant Storage_Count := X / 1024;
      Megs : constant Storage_Count := Ks / 1024;
      Buff : String (1 .. 7);
 
   begin
      if Megs /= 0 then
         Ada.Float_Text_IO.Put (Buff, Float (X) / 1024.0 / 1024.0, 2, 0);
         return Buff & " Megabytes";
 
      elsif Ks /= 0 then
         Ada.Float_Text_IO.Put (Buff, Float (X) / 1024.0, 2, 0);
         return Buff & " Kilobytes";
 
      else
         Ada.Integer_Text_IO.Put (Buff (1 .. 4), Integer (X));
         return Buff (1 .. 4) & " Bytes";
      end if;
   end Mem_Image;
 
   -----------
   -- Usage --
   -----------
 
   procedure Usage is
   begin
      New_Line;
      Put ("GNATMEM ");
      Put_Line (Gnat_Version_String);
      Put_Line ("Copyright 1997-2007, Free Software Foundation, Inc.");
      New_Line;
 
      Put_Line ("Usage: gnatmem switches [depth] exename");
      New_Line;
      Put_Line ("  depth    backtrace depth to take into account, default is"
                & Integer'Image (BT_Depth));
      Put_Line ("  exename  the name of the executable to be analyzed");
      New_Line;
      Put_Line ("Switches:");
      Put_Line ("  -b n     same as depth parameter");
      Put_Line ("  -i file  read the allocation log from specific file");
      Put_Line ("           default is gmem.out in the current directory");
      Put_Line ("  -m n     masks roots with less than n leaks, default is 1");
      Put_Line ("           specify 0 to see even released allocation roots");
      Put_Line ("  -q       quiet, minimum output");
      Put_Line ("  -s order sort allocation roots according to an order of");
      Put_Line ("           sort criteria");
      GNAT.OS_Lib.OS_Exit (1);
   end Usage;
 
   -----------------------
   -- Process_Arguments --
   -----------------------
 
   procedure Process_Arguments is
   begin
      --  Parse the options first
 
      loop
         case Getopt ("b: dd m: i: q s:") is
            when ASCII.NUL => exit;
 
            when 'b' =>
               begin
                  BT_Depth := Natural'Value (Parameter);
               exception
                  when Constraint_Error =>
                     Usage;
               end;
 
            when 'd' =>
               Dump_Log_Mode := True;
 
            when 'm' =>
               begin
                  Minimum_Nb_Leaks := Natural'Value (Parameter);
               exception
                  when Constraint_Error =>
                     Usage;
               end;
 
            when 'i' =>
               Log_Name := new String'(Parameter);
 
            when 'q' =>
               Quiet_Mode := True;
 
            when 's' =>
               declare
                  S : constant String (Sort_Order'Range) := Parameter;
               begin
                  for J in Sort_Order'Range loop
                     if S (J) = 'n' or else
                        S (J) = 'w' or else
                        S (J) = 'h'
                     then
                        Sort_Order (J) := S (J);
                     else
                        Put_Line ("Invalid sort criteria string.");
                        GNAT.OS_Lib.OS_Exit (1);
                     end if;
                  end loop;
               end;
 
            when others =>
               null;
         end case;
      end loop;
 
      --  Set default log file if -i hasn't been specified
 
      if Log_Name = null then
         Log_Name := new String'("gmem.out");
      end if;
 
      --  Get the optional backtrace length and program name
 
      declare
         Str1 : constant String := GNAT.Command_Line.Get_Argument;
         Str2 : constant String := GNAT.Command_Line.Get_Argument;
 
      begin
         if Str1 = "" then
            Usage;
         end if;
 
         if Str2 = "" then
            Program_Name := new String'(Str1);
         else
            BT_Depth := Natural'Value (Str1);
            Program_Name := new String'(Str2);
         end if;
 
      exception
         when Constraint_Error =>
            Usage;
      end;
 
      --  Ensure presence of executable suffix in Program_Name
 
      declare
         Suffix : String_Access := Get_Executable_Suffix;
         Tmp    : String_Access;
 
      begin
         if Suffix.all /= ""
           and then
             Program_Name.all
              (Program_Name.all'Last - Suffix.all'Length + 1 ..
                               Program_Name.all'Last) /= Suffix.all
         then
            Tmp := new String'(Program_Name.all & Suffix.all);
            Free (Program_Name);
            Program_Name := Tmp;
         end if;
 
         Free (Suffix);
 
         --  Search the executable on the path. If not found in the PATH, we
         --  default to the current directory. Otherwise, libaddr2line will
         --  fail with an error:
 
         --     (null): Bad address
 
         Tmp := Locate_Exec_On_Path (Program_Name.all);
 
         if Tmp = null then
            Tmp := new String'('.' & Directory_Separator & Program_Name.all);
         end if;
 
         Free (Program_Name);
         Program_Name := Tmp;
      end;
 
      if not Is_Regular_File (Log_Name.all) then
         Put_Line ("Couldn't find " & Log_Name.all);
         GNAT.OS_Lib.OS_Exit (1);
      end if;
 
      if not Gmem_Initialize (Log_Name.all) then
         Put_Line ("File " & Log_Name.all & " is not a gnatmem log file");
         GNAT.OS_Lib.OS_Exit (1);
      end if;
 
      if not Is_Regular_File (Program_Name.all) then
         Put_Line ("Couldn't find " & Program_Name.all);
      end if;
 
      Gmem_A2l_Initialize (Program_Name.all);
 
   exception
      when GNAT.Command_Line.Invalid_Switch =>
         Ada.Text_IO.Put_Line ("Invalid switch : "
                               & GNAT.Command_Line.Full_Switch);
         Usage;
   end Process_Arguments;
 
   --  Local variables
 
   Cur_Elmt : Storage_Elmt;
   Buff     : String (1 .. 16);
 
--  Start of processing for Gnatmem
 
begin
   Process_Arguments;
 
   if Dump_Log_Mode then
      Put_Line ("Full dump of dynamic memory operations history");
      Put_Line ("----------------------------------------------");
 
      declare
         function CTime (Clock : Address) return Address;
         pragma Import (C, CTime, "ctime");
 
         Int_T0     : Integer := Integer (T0);
         CTime_Addr : constant Address := CTime (Int_T0'Address);
 
         Buffer : String (1 .. 30);
         for Buffer'Address use CTime_Addr;
 
      begin
         Put_Line ("Log started at T0 =" & Duration'Image (T0) & " ("
                   & Buffer (1 .. 24) & ")");
      end;
   end if;
 
   --  Main loop analysing the data generated by the instrumented routines.
   --  For each allocation, the backtrace is kept and stored in a htable
   --  whose entry is the address. For each deallocation, we look for the
   --  corresponding allocation and cancel it.
 
   Main : loop
      Cur_Elmt := Read_Next;
 
      case Cur_Elmt.Elmt is
         when '*' =>
            exit Main;
 
         when 'A' =>
 
            --  Read the corresponding back trace
 
            Tmp_Alloc.Root := Read_BT (BT_Depth);
 
            if Quiet_Mode then
 
               if Nb_Alloc (Tmp_Alloc.Root) = 0 then
                  Nb_Root := Nb_Root + 1;
               end if;
 
               Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) + 1);
               Address_HTable.Set (Cur_Elmt.Address, Tmp_Alloc);
 
            elsif Cur_Elmt.Size > 0 then
 
               --  Update global counters if the allocated size is meaningful
 
               Global_Alloc_Size := Global_Alloc_Size + Cur_Elmt.Size;
               Global_Nb_Alloc   := Global_Nb_Alloc + 1;
 
               if Global_High_Water_Mark < Global_Alloc_Size then
                  Global_High_Water_Mark := Global_Alloc_Size;
               end if;
 
               --  Update the number of allocation root if this is a new one
 
               if Nb_Alloc (Tmp_Alloc.Root) = 0 then
                  Nb_Root := Nb_Root + 1;
               end if;
 
               --  Update allocation root specific counters
 
               Set_Alloc_Size (Tmp_Alloc.Root,
                 Alloc_Size (Tmp_Alloc.Root) + Cur_Elmt.Size);
 
               Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) + 1);
 
               if High_Water_Mark (Tmp_Alloc.Root) <
                                               Alloc_Size (Tmp_Alloc.Root)
               then
                  Set_High_Water_Mark (Tmp_Alloc.Root,
                    Alloc_Size (Tmp_Alloc.Root));
               end if;
 
               --  Associate this allocation root to the allocated address
 
               Tmp_Alloc.Size := Cur_Elmt.Size;
               Address_HTable.Set (Cur_Elmt.Address, Tmp_Alloc);
 
            end if;
 
         when 'D' =>
 
            --  Get the corresponding Dealloc_Size and Root
 
            Tmp_Alloc := Address_HTable.Get (Cur_Elmt.Address);
 
            if Tmp_Alloc.Root = No_Root_Id then
 
               --  There was no prior allocation at this address, something is
               --  very wrong. Mark this allocation root as problematic.
 
               Tmp_Alloc.Root := Read_BT (BT_Depth);
 
               if Nb_Alloc (Tmp_Alloc.Root) = 0 then
                  Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) - 1);
                  Nb_Wrong_Deall := Nb_Wrong_Deall + 1;
               end if;
 
            else
               --  Update global counters
 
               if not Quiet_Mode then
                  Global_Alloc_Size := Global_Alloc_Size - Tmp_Alloc.Size;
               end if;
 
               Global_Nb_Dealloc   := Global_Nb_Dealloc + 1;
 
               --  Update allocation root specific counters
 
               if not Quiet_Mode then
                  Set_Alloc_Size (Tmp_Alloc.Root,
                    Alloc_Size (Tmp_Alloc.Root) - Tmp_Alloc.Size);
               end if;
 
               Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) - 1);
 
               --  Update the number of allocation root if this one disappears
 
               if Nb_Alloc (Tmp_Alloc.Root) = 0
                 and then Minimum_Nb_Leaks > 0 then
                  Nb_Root := Nb_Root - 1;
               end if;
 
               --  Deassociate the deallocated address
 
               Address_HTable.Remove (Cur_Elmt.Address);
            end if;
 
         when others =>
            raise Program_Error;
      end case;
 
      if Dump_Log_Mode then
         case Cur_Elmt.Elmt is
            when 'A' =>
               Put ("ALLOC");
               Int_IO.Put (Buff (1 .. 16), Integer (Cur_Elmt.Address), 16);
               Put (Buff);
               Int_IO.Put (Buff (1 .. 8), Integer (Cur_Elmt.Size));
               Put (Buff (1 .. 8) & " bytes at moment T0 +");
               Put_Line (Duration'Image (Cur_Elmt.Timestamp - T0));
 
            when 'D' =>
               Put ("DEALL");
               Int_IO.Put (Buff (1 .. 16), Integer (Cur_Elmt.Address), 16);
               Put (Buff);
               Put_Line (" at moment T0 +"
                         & Duration'Image (Cur_Elmt.Timestamp - T0));
            when others =>
               raise Program_Error;
         end case;
 
         Print_BT (Tmp_Alloc.Root);
      end if;
 
   end loop Main;
 
   --  Print out general information about overall allocation
 
   if not Quiet_Mode then
      Put_Line ("Global information");
      Put_Line ("------------------");
 
      Put      ("   Total number of allocations        :");
      Ada.Integer_Text_IO.Put (Global_Nb_Alloc, 4);
      New_Line;
 
      Put      ("   Total number of deallocations      :");
      Ada.Integer_Text_IO.Put (Global_Nb_Dealloc, 4);
      New_Line;
 
      Put_Line ("   Final Water Mark (non freed mem)   :"
        & Mem_Image (Global_Alloc_Size));
      Put_Line ("   High Water Mark                    :"
        & Mem_Image (Global_High_Water_Mark));
      New_Line;
   end if;
 
   --  Print out the back traces corresponding to potential leaks in order
   --  greatest number of non-deallocated allocations.
 
   Print_Back_Traces : declare
      type Root_Array is array (Natural range <>) of Root_Id;
      type Access_Root_Array is access Root_Array;
 
      Leaks        : constant Access_Root_Array :=
                       new Root_Array (0 .. Nb_Root);
      Leak_Index   : Natural := 0;
 
      Bogus_Dealls : constant Access_Root_Array :=
                       new Root_Array (1 .. Nb_Wrong_Deall);
      Deall_Index  : Natural := 0;
      Nb_Alloc_J   : Natural := 0;
 
      procedure Move (From : Natural; To : Natural);
      function Lt (Op1, Op2 : Natural) return Boolean;
      package Root_Sort is new GNAT.Heap_Sort_G (Move, Lt);
 
      ----------
      -- Move --
      ----------
 
      procedure Move (From : Natural; To : Natural) is
      begin
         Leaks (To) := Leaks (From);
      end Move;
 
      --------
      -- Lt --
      --------
 
      function Lt (Op1, Op2 : Natural) return Boolean is
 
         function Apply_Sort_Criterion (S : Character) return Integer;
         --  Applies a specific sort criterion; returns -1, 0 or 1 if Op1 is
         --  smaller than, equal, or greater than Op2 according to criterion.
 
         --------------------------
         -- Apply_Sort_Criterion --
         --------------------------
 
         function Apply_Sort_Criterion (S : Character) return Integer is
            LOp1, LOp2 : Integer;
 
         begin
            case S is
               when 'n' =>
                  LOp1 := Nb_Alloc (Leaks (Op1));
                  LOp2 := Nb_Alloc (Leaks (Op2));
 
               when 'w' =>
                  LOp1 := Integer (Alloc_Size (Leaks (Op1)));
                  LOp2 := Integer (Alloc_Size (Leaks (Op2)));
 
               when 'h' =>
                  LOp1 := Integer (High_Water_Mark (Leaks (Op1)));
                  LOp2 := Integer (High_Water_Mark (Leaks (Op2)));
 
               when others =>
                  return 0;  --  Can't actually happen
            end case;
 
            if LOp1 < LOp2 then
               return -1;
            elsif LOp1 > LOp2 then
               return 1;
            else
               return 0;
            end if;
 
         exception
            when Constraint_Error =>
               return 0;
         end Apply_Sort_Criterion;
 
         --  Local Variables
 
         Result : Integer;
 
      --  Start of processing for Lt
 
      begin
         for S in Sort_Order'Range loop
            Result := Apply_Sort_Criterion (Sort_Order (S));
            if Result = -1 then
               return False;
            elsif Result = 1 then
               return True;
            end if;
         end loop;
         return False;
      end Lt;
 
   --  Start of processing for Print_Back_Traces
 
   begin
      --  Transfer all the relevant Roots in the Leaks and a Bogus_Deall arrays
 
      Tmp_Alloc.Root := Get_First;
      while Tmp_Alloc.Root /= No_Root_Id loop
         if Nb_Alloc (Tmp_Alloc.Root) = 0 and then Minimum_Nb_Leaks > 0 then
            null;
 
         elsif Nb_Alloc (Tmp_Alloc.Root) < 0  then
            Deall_Index := Deall_Index + 1;
            Bogus_Dealls (Deall_Index) := Tmp_Alloc.Root;
 
         else
            Leak_Index := Leak_Index + 1;
            Leaks (Leak_Index) := Tmp_Alloc.Root;
         end if;
 
         Tmp_Alloc.Root := Get_Next;
      end loop;
 
      --  Print out wrong deallocations
 
      if Nb_Wrong_Deall > 0 then
         Put_Line    ("Releasing deallocated memory at :");
         if not Quiet_Mode then
            Put_Line ("--------------------------------");
         end if;
 
         for J in  1 .. Bogus_Dealls'Last loop
            Print_BT (Bogus_Dealls (J), Short => Quiet_Mode);
            New_Line;
         end loop;
      end if;
 
      --  Print out all allocation Leaks
 
      if Leak_Index > 0 then
 
         --  Sort the Leaks so that potentially important leaks appear first
 
         Root_Sort.Sort (Leak_Index);
 
         for J in  1 .. Leak_Index loop
            Nb_Alloc_J := Nb_Alloc (Leaks (J));
 
            if Nb_Alloc_J >= Minimum_Nb_Leaks then
               if Quiet_Mode then
                  if Nb_Alloc_J = 1 then
                     Put_Line (" 1 leak at :");
                  else
                     Put_Line (Integer'Image (Nb_Alloc_J) & " leaks at :");
                  end if;
 
               else
                  Put_Line ("Allocation Root #" & Integer'Image (J));
                  Put_Line ("-------------------");
 
                  Put      (" Number of non freed allocations    :");
                  Ada.Integer_Text_IO.Put (Nb_Alloc_J, 4);
                  New_Line;
 
                  Put_Line
                    (" Final Water Mark (non freed mem)   :"
                     & Mem_Image (Alloc_Size (Leaks (J))));
 
                  Put_Line
                    (" High Water Mark                    :"
                     & Mem_Image (High_Water_Mark (Leaks (J))));
 
                  Put_Line (" Backtrace                          :");
               end if;
 
               Print_BT (Leaks (J), Short => Quiet_Mode);
               New_Line;
            end if;
         end loop;
      end if;
   end Print_Back_Traces;
end Gnatmem;
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.