How to locate waste of CPU?

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,