Of interest is the code that performs the actual measurements. Any other code (such as job implementation or dispatching) that is required to demonstrate the rate tracking is helpful, but not the focus.

Multiple approaches are allowed (even preferable), so long as they can accomplish these goals:

 Run N seconds worth of jobs and/or Y jobs.
 Report at least three distinct times.

Be aware of the precision and accuracy limitations of your timing mechanisms, and document them if you can.

See also: System time, Time a function

with System;                     use System;
with Ada.Text_IO;                use Ada.Text_IO;
with Ada.Calendar;               use Ada.Calendar;
with Ada.Unchecked_Deallocation; use Ada;
with Interfaces;
 
procedure Rate_Counter is
   pragma Priority (Max_Priority);
 
   package Duration_IO is new Fixed_IO (Duration);
 
   Job_Nbr : constant := 6; -- adjust to your need
   subtype Job_Index is Natural range 1 .. Job_Nbr;
 
   task type Job (ID : Job_Index) is
      pragma Priority (Default_Priority);
      entry Start;
   end Job;
 
   type Job_Ptr is access Job;
   procedure Free is new Unchecked_Deallocation (Job, Job_Ptr);
 
   Jobs : array (Job_Index) of Job_Ptr;
 
   Done      : Natural                      := 0;
   Completed : array (Job_Index) of Boolean := (others => False);
 
   type Timings is array (Job_Index) of Calendar.Time;
   Start_T, Stop_T : Timings;
 
   task body Job is
      Anchor : Interfaces.Integer_32;
      pragma Volatile (Anchor); -- necessary to avoid compiler optimization.
   begin
      accept Start;
 
      for I in Interfaces.Integer_32'Range loop      -- the job to do
         Anchor := I;
      end loop;
   end Job;
 
begin
   for J in Job_Index'Range loop
      Jobs (J) := new Job (ID => J); -- create the jobs first, sync later
   end loop;
   for J in Job_Index'Range loop -- launch the jobs in parallel
      Start_T (J) := Calendar.Clock; -- get the start time
      Jobs (J).Start; -- priority settings necessary to regain control.
   end loop;
   -- Polling for the results / also possible to use a protected type.
   while not (Done = Job_Nbr) loop
      for J in Job_Index'Range loop
         if not Completed (J) and then Jobs (J)'Terminated then
            Stop_T (J) := Calendar.Clock; -- get the end time
            Put ("Job #" & Job_Index'Image (J) & " is finished. It took ");
            Duration_IO.Put (Stop_T (J) - Start_T (J), Fore => 3, Aft => 2);
            Put_Line (" seconds.");
            Completed (J) := True;
            Done          := Done + 1;
         end if;
      end loop;
      delay System.Tick; -- according to the precision of the system clock
   end loop;
   Duration_IO.Put (System.Tick, Fore => 1, Aft => 6);
   Put_Line (" seconds is the precision of System clock.");
 
   for J in Job_Index'Range loop
      Free (Jobs (J)); -- no GC in Ada, clean-up is explicit
   end loop;
 
end Rate_Counter;