OK, here is how I do this, which is pretty common when implementing numeric stuff.
The first step. I do not use any tools. They are too coarse to be useful. You would get a heap of useless information to browse through, while what you need is a focused analysis of suspicious pieces of code, usually executed in a loop. So I start with a broad scope and then iteratively narrow it around the offending part(s). What I use is rather simple Ada code that I insert at the places I suspect.
Here it is (it uses Simple Components, but you could rewrite it of course):
with Ada.Calendar; use Ada.Calendar;
with Tables;
package Profiler is
type Element is record
Total : Duration := 0.0;
Count : Natural := 0;
Start : Time;
end record;
package Element_Tables is new Tables (Element);
use Element_Tables;
Statistics : Table;
procedure Enter (Item : String);
procedure Leave (Item : String);
procedure Reset (Item : String);
procedure Report;
pragma Inline (Enter);
pragma Inline (Leave);
end Profiler;
The implementation:
with Ada.Text_IO; use Ada.Text_IO;
with Strings_Edit; use Strings_Edit;
with Strings_Edit.Integers; use Strings_Edit.Integers;
package body Profiler is
procedure Enter (Item : String) is
Offset : Integer := Locate (Statistics, Item);
begin
if Offset > 0 then
declare
This : Element := GetTag (Statistics, Offset);
begin
This.Start := Clock;
Replace (Statistics, Offset, This);
end;
else
declare
This : Element;
begin
This.Start := Clock;
Replace (Statistics, Item, This);
end;
end if;
end Enter;
procedure Leave (Item : String) is
Offset : Integer := Locate (Statistics, Item);
begin
if Offset > 0 then
declare
This : Element := GetTag (Statistics, Offset);
begin
This.Total := This.Total + (Clock - This.Start);
This.Count := This.Count + 1;
Replace (Statistics, Offset, This);
end;
end if;
end Leave;
procedure Reset (Item : String) is
Offset : Integer := Locate (Statistics, Item);
begin
if Offset > 0 then
declare
This : Element := GetTag (Statistics, Offset);
begin
This.Total := 0.0;
This.Count := 0;
Replace (Statistics, Offset, This);
end;
end if;
end Reset;
procedure Report is
Line : String (1..120);
Pointer : Integer := 1;
begin
Put (Line, Pointer, " Called");
Put (Line, Pointer, " Average, s");
Put (Line, Pointer, " Times");
Put (Line, Pointer, " Total, s");
Put_Line (Line (1..Pointer - 1));
for Item in 1..GetSize (Statistics) loop
Pointer := 1;
declare
This : Element := GetTag (Statistics, Item);
begin
Put
( Destination => Line,
Pointer => Pointer,
Value => GetName (Statistics, Item),
Field => 30,
Justify => Right
);
if This.Count = 0 then
Put (Line, Pointer, " -");
else
Put
( Destination => Line,
Pointer => Pointer,
Value => Duration'Image
(This.Total / This.Count),
Field => 15,
Justify => Right
);
Put
( Destination => Line,
Pointer => Pointer,
Value => This.Count,
Field => 10,
Justify => Right
);
Put
( Destination => Line,
Pointer => Pointer,
Value => Duration'Image (This.Total),
Field => 15,
Justify => Right
);
end if;
Put_Line (Line (1..Pointer - 1));
end;
end loop;
end Report;
end Profiler;
The usage is straightforward:
...
Enter ("Suspect 1");
... -- The code I suspect
Leave ("Suspect 1");
...
and before exiting the program you call Report,