OpenCores
URL https://opencores.org/ocsvn/scarts/scarts/trunk

Subversion Repositories scarts

[/] [scarts/] [trunk/] [toolchain/] [scarts-gcc/] [gcc-4.1.1/] [gcc/] [ada/] [gnatmem.adb] - Blame information for rev 16

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

Line No. Rev Author Line
1 12 jlechner
------------------------------------------------------------------------------
2
--                                                                          --
3
--                         GNAT COMPILER COMPONENTS                         --
4
--                                                                          --
5
--                              G N A T M E M                               --
6
--                                                                          --
7
--                                 B o d y                                  --
8
--                                                                          --
9
--                     Copyright (C) 1997-2005, AdaCore                     --
10
--                                                                          --
11
-- GNAT is free software;  you can  redistribute it  and/or modify it under --
12
-- terms of the  GNU General Public License as published  by the Free Soft- --
13
-- ware  Foundation;  either version 2,  or (at your option) any later ver- --
14
-- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
15
-- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
16
-- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
17
-- for  more details.  You should have  received  a copy of the GNU General --
18
-- Public License  distributed with GNAT;  see file COPYING.  If not, write --
19
-- to  the  Free Software Foundation,  51  Franklin  Street,  Fifth  Floor, --
20
-- Boston, MA 02110-1301, USA.                                              --
21
--                                                                          --
22
-- GNAT was originally developed  by the GNAT team at  New York University. --
23
-- Extensive contributions were provided by Ada Core Technologies Inc.      --
24
--                                                                          --
25
------------------------------------------------------------------------------
26
 
27
--  GNATMEM is a utility that tracks memory leaks. It is based on a simple
28
--  idea:
29
 
30
--      - Read the allocation log generated by the application linked using
31
--        instrumented memory allocation and dealocation (see memtrack.adb for
32
--        this circuitry). To get access to this functionality, the application
33
--        must be relinked with library libgmem.a:
34
 
35
--            $ gnatmake my_prog -largs -lgmem
36
 
37
--        The running my_prog will produce a file named gmem.out that will be
38
--        parsed by gnatmem.
39
 
40
--      - Record a reference to the allocated memory on each allocation call
41
 
42
--      - Suppress this reference on deallocation
43
 
44
--      - At the end of the program, remaining references are potential leaks.
45
--        sort them out the best possible way in order to locate the root of
46
--        the leak.
47
 
48
--   This capability is not supported on all platforms, please refer to
49
--   memtrack.adb for further information.
50
 
51
--   In order to help finding out the real leaks,  the notion of "allocation
52
--   root" is defined. An allocation root is a specific point in the program
53
--   execution generating memory allocation where data is collected (such as
54
--   number of allocations, amount of memory allocated, high water mark, etc.)
55
 
56
with Gnatvsn; use Gnatvsn;
57
 
58
with Ada.Text_IO;             use Ada.Text_IO;
59
with Ada.Float_Text_IO;
60
with Ada.Integer_Text_IO;
61
 
62
with GNAT.Command_Line;       use GNAT.Command_Line;
63
with GNAT.Heap_Sort_G;
64
with GNAT.OS_Lib;             use GNAT.OS_Lib;
65
with GNAT.HTable;             use GNAT.HTable;
66
 
67
with System;                  use System;
68
with System.Storage_Elements; use System.Storage_Elements;
69
 
70
with Memroot; use Memroot;
71
 
72
procedure Gnatmem is
73
 
74
   ------------------------
75
   -- Other Declarations --
76
   ------------------------
77
 
78
   type Storage_Elmt is record
79
      Elmt : Character;
80
      --  *  = End of log file
81
      --  A  = found a ALLOC mark in the log
82
      --  D  = found a DEALL mark in the log
83
      Address : Integer_Address;
84
      Size    : Storage_Count;
85
   end record;
86
   --  This needs a comment ???
87
 
88
   Log_Name, Program_Name : String_Access;
89
   --  These need comments, and should be on separate lines ???
90
 
91
   function Read_Next return Storage_Elmt;
92
   --  Reads next dynamic storage operation from the log file
93
 
94
   function Mem_Image (X : Storage_Count) return String;
95
   --  X is a size in storage_element. Returns a value
96
   --  in Megabytes, Kilobytes or Bytes as appropriate.
97
 
98
   procedure Process_Arguments;
99
   --  Read command line arguments
100
 
101
   procedure Usage;
102
   --  Prints out the option help
103
 
104
   function Gmem_Initialize (Dumpname : String) return Boolean;
105
   --  Opens the file represented by Dumpname and prepares it for
106
   --  work. Returns False if the file does not have the correct format, True
107
   --  otherwise.
108
 
109
   procedure Gmem_A2l_Initialize (Exename : String);
110
   --  Initialises the convert_addresses interface by supplying it with
111
   --  the name of the executable file Exename
112
 
113
   -----------------------------------
114
   -- HTable address --> Allocation --
115
   -----------------------------------
116
 
117
   type Allocation is record
118
      Root : Root_Id;
119
      Size : Storage_Count;
120
   end record;
121
 
122
   type Address_Range is range 0 .. 4097;
123
   function H (A : Integer_Address) return Address_Range;
124
   No_Alloc : constant Allocation := (No_Root_Id, 0);
125
 
126
   package Address_HTable is new GNAT.HTable.Simple_HTable (
127
     Header_Num => Address_Range,
128
     Element    => Allocation,
129
     No_Element => No_Alloc,
130
     Key        => Integer_Address,
131
     Hash       => H,
132
     Equal      => "=");
133
 
134
   BT_Depth   : Integer := 1;
135
 
136
   --  The following need comments ???
137
 
138
   Global_Alloc_Size      : Storage_Count  := 0;
139
   Global_High_Water_Mark : Storage_Count  := 0;
140
   Global_Nb_Alloc        : Integer        := 0;
141
   Global_Nb_Dealloc      : Integer        := 0;
142
   Nb_Root                : Integer        := 0;
143
   Nb_Wrong_Deall         : Integer        := 0;
144
   Minimum_NB_Leaks       : Integer        := 1;
145
 
146
   Tmp_Alloc   : Allocation;
147
   Quiet_Mode  : Boolean := False;
148
 
149
   ------------------------------
150
   -- Allocation Roots Sorting --
151
   ------------------------------
152
 
153
   Sort_Order : String (1 .. 3) := "nwh";
154
   --  This is the default order in which sorting criteria will be applied
155
   --  n -  Total number of unfreed allocations
156
   --  w -  Final watermark
157
   --  h -  High watermark
158
 
159
   --------------------------------
160
   -- GMEM functionality binding --
161
   --------------------------------
162
 
163
   function Gmem_Initialize (Dumpname : String) return Boolean is
164
      function Initialize (Dumpname : System.Address) return Boolean;
165
      pragma Import (C, Initialize, "__gnat_gmem_initialize");
166
 
167
      S : aliased String := Dumpname & ASCII.NUL;
168
 
169
   begin
170
      return Initialize (S'Address);
171
   end Gmem_Initialize;
172
 
173
   procedure Gmem_A2l_Initialize (Exename : String) is
174
      procedure A2l_Initialize (Exename : System.Address);
175
      pragma Import (C, A2l_Initialize, "__gnat_gmem_a2l_initialize");
176
 
177
      S : aliased String := Exename & ASCII.NUL;
178
 
179
   begin
180
      A2l_Initialize (S'Address);
181
   end Gmem_A2l_Initialize;
182
 
183
   function Read_Next return Storage_Elmt is
184
      procedure Read_Next (buf : System.Address);
185
      pragma Import (C, Read_Next, "__gnat_gmem_read_next");
186
 
187
      S : Storage_Elmt;
188
 
189
   begin
190
      Read_Next (S'Address);
191
      return S;
192
   end Read_Next;
193
 
194
   -------
195
   -- H --
196
   -------
197
 
198
   function H (A : Integer_Address) return Address_Range is
199
   begin
200
      return Address_Range (A mod Integer_Address (Address_Range'Last));
201
   end H;
202
 
203
   ---------------
204
   -- Mem_Image --
205
   ---------------
206
 
207
   function Mem_Image (X : Storage_Count) return String is
208
      Ks    : constant Storage_Count := X / 1024;
209
      Megs  : constant Storage_Count := Ks / 1024;
210
      Buff  : String (1 .. 7);
211
 
212
   begin
213
      if Megs /= 0 then
214
         Ada.Float_Text_IO.Put (Buff, Float (X) / 1024.0 / 1024.0, 2, 0);
215
         return Buff & " Megabytes";
216
 
217
      elsif Ks /= 0 then
218
         Ada.Float_Text_IO.Put (Buff, Float (X) / 1024.0, 2, 0);
219
         return Buff & " Kilobytes";
220
 
221
      else
222
         Ada.Integer_Text_IO.Put (Buff (1 .. 4), Integer (X));
223
         return Buff (1 .. 4) & " Bytes";
224
      end if;
225
   end Mem_Image;
226
 
227
   -----------
228
   -- Usage --
229
   -----------
230
 
231
   procedure Usage is
232
   begin
233
      New_Line;
234
      Put ("GNATMEM ");
235
      Put_Line (Gnat_Version_String);
236
      Put_Line ("Copyright 1997-2005, Free Software Foundation, Inc.");
237
      New_Line;
238
 
239
      Put_Line ("Usage: gnatmem switches [depth] exename");
240
      New_Line;
241
      Put_Line ("  depth    backtrace depth to take into account, default is"
242
                & Integer'Image (BT_Depth));
243
      Put_Line ("  exename  the name of the executable to be analyzed");
244
      New_Line;
245
      Put_Line ("Switches:");
246
      Put_Line ("  -b n     same as depth parameter");
247
      Put_Line ("  -i file  read the allocation log from specific file");
248
      Put_Line ("           default is gmem.out in the current directory");
249
      Put_Line ("  -m n     masks roots with less than n leaks, default is 1");
250
      Put_Line ("           specify 0 to see even released allocation roots");
251
      Put_Line ("  -q       quiet, minimum output");
252
      Put_Line ("  -s order sort allocation roots according to an order of");
253
      Put_Line ("           sort criteria");
254
      GNAT.OS_Lib.OS_Exit (1);
255
   end Usage;
256
 
257
   -----------------------
258
   -- Process_Arguments --
259
   -----------------------
260
 
261
   procedure Process_Arguments is
262
   begin
263
      --  Parse the options first
264
 
265
      loop
266
         case Getopt ("b: m: i: q s:") is
267
            when ASCII.Nul => exit;
268
 
269
            when 'b' =>
270
               begin
271
                  BT_Depth := Natural'Value (Parameter);
272
               exception
273
                  when Constraint_Error =>
274
                     Usage;
275
               end;
276
 
277
            when 'm' =>
278
               begin
279
                  Minimum_NB_Leaks := Natural'Value (Parameter);
280
               exception
281
                  when Constraint_Error =>
282
                     Usage;
283
               end;
284
 
285
            when 'i' =>
286
               Log_Name := new String'(Parameter);
287
 
288
            when 'q' =>
289
               Quiet_Mode := True;
290
 
291
            when 's' =>
292
               declare
293
                  S : constant String (Sort_Order'Range) := Parameter;
294
 
295
               begin
296
                  for J in Sort_Order'Range loop
297
                     if S (J) = 'n' or else
298
                        S (J) = 'w' or else
299
                        S (J) = 'h'
300
                     then
301
                        Sort_Order (J) := S (J);
302
                     else
303
                        Put_Line ("Invalid sort criteria string.");
304
                        GNAT.OS_Lib.OS_Exit (1);
305
                     end if;
306
                  end loop;
307
               end;
308
 
309
            when others =>
310
               null;
311
         end case;
312
      end loop;
313
 
314
      --  Set default log file if -i hasn't been specified
315
 
316
      if Log_Name = null then
317
         Log_Name := new String'("gmem.out");
318
      end if;
319
 
320
      --  Get the optional backtrace length and program name
321
 
322
      declare
323
         Str1 : constant String := GNAT.Command_Line.Get_Argument;
324
         Str2 : constant String := GNAT.Command_Line.Get_Argument;
325
 
326
      begin
327
         if Str1 = "" then
328
            Usage;
329
         end if;
330
 
331
         if Str2 = "" then
332
            Program_Name := new String'(Str1);
333
         else
334
            BT_Depth := Natural'Value (Str1);
335
            Program_Name := new String'(Str2);
336
         end if;
337
 
338
      exception
339
         when Constraint_Error =>
340
            Usage;
341
      end;
342
 
343
      --  Ensure presence of executable suffix in Program_Name
344
 
345
      declare
346
         Suffix : String_Access := Get_Executable_Suffix;
347
         Tmp    : String_Access;
348
 
349
      begin
350
         if Suffix.all /= ""
351
           and then
352
             Program_Name.all
353
              (Program_Name.all'Last - Suffix.all'Length + 1 ..
354
                               Program_Name.all'Last) /= Suffix.all
355
         then
356
            Tmp := new String'(Program_Name.all & Suffix.all);
357
            Free (Program_Name);
358
            Program_Name := Tmp;
359
         end if;
360
 
361
         Free (Suffix);
362
 
363
         --  Search the executable on the path. If not found in the PATH, we
364
         --  default to the current directory. Otherwise, libaddr2line will
365
         --  fail with an error:
366
 
367
         --     (null): Bad address
368
 
369
         Tmp := Locate_Exec_On_Path (Program_Name.all);
370
 
371
         if Tmp = null then
372
            Tmp := new String'('.' & Directory_Separator & Program_Name.all);
373
         end if;
374
 
375
         Free (Program_Name);
376
         Program_Name := Tmp;
377
      end;
378
 
379
      if not Is_Regular_File (Log_Name.all) then
380
         Put_Line ("Couldn't find " & Log_Name.all);
381
         GNAT.OS_Lib.OS_Exit (1);
382
      end if;
383
 
384
      if not Gmem_Initialize (Log_Name.all) then
385
         Put_Line ("File " & Log_Name.all & " is not a gnatmem log file");
386
         GNAT.OS_Lib.OS_Exit (1);
387
      end if;
388
 
389
      if not Is_Regular_File (Program_Name.all) then
390
         Put_Line ("Couldn't find " & Program_Name.all);
391
      end if;
392
 
393
      Gmem_A2l_Initialize (Program_Name.all);
394
 
395
   exception
396
      when GNAT.Command_Line.Invalid_Switch =>
397
         Ada.Text_IO.Put_Line ("Invalid switch : "
398
                               & GNAT.Command_Line.Full_Switch);
399
         Usage;
400
   end Process_Arguments;
401
 
402
   Cur_Elmt : Storage_Elmt;
403
 
404
--  Start of processing for Gnatmem
405
 
406
begin
407
   Process_Arguments;
408
 
409
   --  Main loop analysing the data generated by the instrumented routines.
410
   --  For each allocation, the backtrace is kept and stored in a htable
411
   --  whose entry is the address. For each deallocation, we look for the
412
   --  corresponding allocation and cancel it.
413
 
414
   Main : loop
415
      Cur_Elmt := Read_Next;
416
 
417
      case Cur_Elmt.Elmt is
418
         when '*' =>
419
            exit Main;
420
 
421
         when 'A' =>
422
 
423
            --  Update global counters if the allocated size is meaningful
424
 
425
            if Quiet_Mode then
426
               Tmp_Alloc.Root := Read_BT (BT_Depth);
427
 
428
               if Nb_Alloc (Tmp_Alloc.Root) = 0 then
429
                  Nb_Root := Nb_Root + 1;
430
               end if;
431
 
432
               Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) + 1);
433
               Address_HTable.Set (Cur_Elmt.Address, Tmp_Alloc);
434
 
435
            elsif Cur_Elmt.Size > 0 then
436
 
437
               Global_Alloc_Size := Global_Alloc_Size + Cur_Elmt.Size;
438
               Global_Nb_Alloc   := Global_Nb_Alloc + 1;
439
 
440
               if Global_High_Water_Mark < Global_Alloc_Size then
441
                  Global_High_Water_Mark := Global_Alloc_Size;
442
               end if;
443
 
444
               --  Read the corresponding back trace
445
 
446
               Tmp_Alloc.Root := Read_BT (BT_Depth);
447
 
448
               --  Update the number of allocation root if this is a new one
449
 
450
               if Nb_Alloc (Tmp_Alloc.Root) = 0 then
451
                  Nb_Root := Nb_Root + 1;
452
               end if;
453
 
454
               --  Update allocation root specific counters
455
 
456
               Set_Alloc_Size (Tmp_Alloc.Root,
457
                 Alloc_Size (Tmp_Alloc.Root) + Cur_Elmt.Size);
458
 
459
               Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) + 1);
460
 
461
               if High_Water_Mark (Tmp_Alloc.Root) <
462
                                               Alloc_Size (Tmp_Alloc.Root)
463
               then
464
                  Set_High_Water_Mark (Tmp_Alloc.Root,
465
                    Alloc_Size (Tmp_Alloc.Root));
466
               end if;
467
 
468
               --  Associate this allocation root to the allocated address
469
 
470
               Tmp_Alloc.Size := Cur_Elmt.Size;
471
               Address_HTable.Set (Cur_Elmt.Address, Tmp_Alloc);
472
 
473
            --  non meaningful output, just consumes the backtrace
474
 
475
            else
476
               Tmp_Alloc.Root := Read_BT (BT_Depth);
477
            end if;
478
 
479
         when 'D' =>
480
 
481
            --  Get the corresponding Dealloc_Size and Root
482
 
483
            Tmp_Alloc := Address_HTable.Get (Cur_Elmt.Address);
484
 
485
            if Tmp_Alloc.Root = No_Root_Id then
486
 
487
               --  There was no prior allocation at this address, something is
488
               --  very wrong. Mark this allocation root as problematic
489
 
490
               Tmp_Alloc.Root := Read_BT (BT_Depth);
491
 
492
               if Nb_Alloc (Tmp_Alloc.Root) = 0 then
493
                  Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) - 1);
494
                  Nb_Wrong_Deall := Nb_Wrong_Deall + 1;
495
               end if;
496
 
497
            else
498
               --  Update global counters
499
 
500
               if not Quiet_Mode then
501
                  Global_Alloc_Size := Global_Alloc_Size - Tmp_Alloc.Size;
502
               end if;
503
 
504
               Global_Nb_Dealloc   := Global_Nb_Dealloc + 1;
505
 
506
               --  Update allocation root specific counters
507
 
508
               if not Quiet_Mode then
509
                  Set_Alloc_Size (Tmp_Alloc.Root,
510
                    Alloc_Size (Tmp_Alloc.Root) - Tmp_Alloc.Size);
511
               end if;
512
 
513
               Set_Nb_Alloc (Tmp_Alloc.Root, Nb_Alloc (Tmp_Alloc.Root) - 1);
514
 
515
               --  update the number of allocation root if this one disappear
516
 
517
               if Nb_Alloc (Tmp_Alloc.Root) = 0
518
                 and then Minimum_NB_Leaks > 0 then
519
                  Nb_Root := Nb_Root - 1;
520
               end if;
521
 
522
               --  De-associate the deallocated address
523
 
524
               Address_HTable.Remove (Cur_Elmt.Address);
525
            end if;
526
 
527
         when others =>
528
            raise Program_Error;
529
      end case;
530
   end loop Main;
531
 
532
   --  Print out general information about overall allocation
533
 
534
   if not Quiet_Mode then
535
      Put_Line ("Global information");
536
      Put_Line ("------------------");
537
 
538
      Put      ("   Total number of allocations        :");
539
      Ada.Integer_Text_IO.Put (Global_Nb_Alloc, 4);
540
      New_Line;
541
 
542
      Put      ("   Total number of deallocations      :");
543
      Ada.Integer_Text_IO.Put (Global_Nb_Dealloc, 4);
544
      New_Line;
545
 
546
      Put_Line ("   Final Water Mark (non freed mem)   :"
547
        & Mem_Image (Global_Alloc_Size));
548
      Put_Line ("   High Water Mark                    :"
549
        & Mem_Image (Global_High_Water_Mark));
550
      New_Line;
551
   end if;
552
 
553
   --  Print out the back traces corresponding to potential leaks in order
554
   --  greatest number of non-deallocated allocations
555
 
556
   Print_Back_Traces : declare
557
      type Root_Array is array (Natural range <>) of Root_Id;
558
      Leaks   : Root_Array (0 .. Nb_Root);
559
      Leak_Index   : Natural := 0;
560
 
561
      Bogus_Dealls : Root_Array (1 .. Nb_Wrong_Deall);
562
      Deall_Index  : Natural := 0;
563
      Nb_Alloc_J   : Natural := 0;
564
 
565
      procedure Move (From : Natural; To : Natural);
566
      function  Lt (Op1, Op2 : Natural) return Boolean;
567
      package   Root_Sort is new GNAT.Heap_Sort_G (Move, Lt);
568
 
569
      procedure Move (From : Natural; To : Natural) is
570
      begin
571
         Leaks (To) := Leaks (From);
572
      end Move;
573
 
574
      function Lt (Op1, Op2 : Natural) return Boolean is
575
         function Apply_Sort_Criterion (S : Character) return Integer;
576
         --  Applies a specific sort criterion; returns -1, 0 or 1 if Op1 is
577
         --  smaller than, equal, or greater than Op2 according to criterion
578
 
579
         function Apply_Sort_Criterion (S : Character) return Integer is
580
            LOp1, LOp2 : Integer;
581
         begin
582
            case S is
583
               when 'n' =>
584
                  LOp1 := Nb_Alloc (Leaks (Op1));
585
                  LOp2 := Nb_Alloc (Leaks (Op2));
586
 
587
               when 'w' =>
588
                  LOp1 := Integer (Alloc_Size (Leaks (Op1)));
589
                  LOp2 := Integer (Alloc_Size (Leaks (Op2)));
590
 
591
               when 'h' =>
592
                  LOp1 := Integer (High_Water_Mark (Leaks (Op1)));
593
                  LOp2 := Integer (High_Water_Mark (Leaks (Op2)));
594
 
595
               when others =>
596
                  return 0;  --  Can't actually happen
597
            end case;
598
 
599
            if LOp1 < LOp2 then
600
               return -1;
601
            elsif LOp1 > LOp2 then
602
               return 1;
603
            else
604
               return 0;
605
            end if;
606
         exception
607
            when Constraint_Error =>
608
               return 0;
609
         end Apply_Sort_Criterion;
610
 
611
         Result : Integer;
612
 
613
      --  Start of processing for Lt
614
 
615
      begin
616
         for S in Sort_Order'Range loop
617
            Result := Apply_Sort_Criterion (Sort_Order (S));
618
            if Result = -1 then
619
               return False;
620
            elsif Result = 1 then
621
               return True;
622
            end if;
623
         end loop;
624
         return False;
625
      end Lt;
626
 
627
   --  Start of processing for Print_Back_Traces
628
 
629
   begin
630
      --  Transfer all the relevant Roots in the Leaks and a
631
      --  Bogus_Deall arrays
632
 
633
      Tmp_Alloc.Root := Get_First;
634
      while Tmp_Alloc.Root /= No_Root_Id loop
635
         if Nb_Alloc (Tmp_Alloc.Root) = 0 and then Minimum_NB_Leaks > 0 then
636
            null;
637
 
638
         elsif Nb_Alloc (Tmp_Alloc.Root) < 0  then
639
            Deall_Index := Deall_Index + 1;
640
            Bogus_Dealls (Deall_Index) := Tmp_Alloc.Root;
641
 
642
         else
643
            Leak_Index := Leak_Index + 1;
644
            Leaks (Leak_Index) := Tmp_Alloc.Root;
645
         end if;
646
 
647
         Tmp_Alloc.Root := Get_Next;
648
      end loop;
649
 
650
      --  Print out wrong deallocations
651
 
652
      if Nb_Wrong_Deall > 0 then
653
         Put_Line    ("Releasing deallocated memory at :");
654
         if not Quiet_Mode then
655
            Put_Line ("--------------------------------");
656
         end if;
657
 
658
         for J in  1 .. Bogus_Dealls'Last loop
659
            Print_BT (Bogus_Dealls (J), Short => Quiet_Mode);
660
            New_Line;
661
         end loop;
662
      end if;
663
 
664
      --  Print out all allocation Leaks
665
 
666
      if Nb_Root > 0 then
667
 
668
         --  Sort the Leaks so that potentially important leaks appear first
669
 
670
         Root_Sort.Sort (Nb_Root);
671
 
672
         for J in  1 .. Leaks'Last loop
673
            Nb_Alloc_J := Nb_Alloc (Leaks (J));
674
            if Nb_Alloc_J >= Minimum_NB_Leaks then
675
               if Quiet_Mode then
676
                  if Nb_Alloc_J = 1 then
677
                     Put_Line (" 1 leak at :");
678
                  else
679
                     Put_Line (Integer'Image (Nb_Alloc_J) & " leaks at :");
680
                  end if;
681
 
682
               else
683
                  Put_Line ("Allocation Root #" & Integer'Image (J));
684
                  Put_Line ("-------------------");
685
 
686
                  Put      (" Number of non freed allocations    :");
687
                  Ada.Integer_Text_IO.Put (Nb_Alloc_J, 4);
688
                  New_Line;
689
 
690
                  Put_Line
691
                    (" Final Water Mark (non freed mem)   :"
692
                     & Mem_Image (Alloc_Size (Leaks (J))));
693
 
694
                  Put_Line
695
                    (" High Water Mark                    :"
696
                     & Mem_Image (High_Water_Mark (Leaks (J))));
697
 
698
                  Put_Line (" Backtrace                          :");
699
               end if;
700
 
701
               Print_BT (Leaks (J), Short => Quiet_Mode);
702
               New_Line;
703
            end if;
704
         end loop;
705
      end if;
706
   end Print_Back_Traces;
707
end Gnatmem;

powered by: WebSVN 2.1.0

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