Size and measure task stacks.

Choose a usable stack size, account for guard pages and pool classes, and measure the effective reservation.

STEP 05

Choose the requested size.

Ada Storage_Size controls stack size for native and lightweight tasks. Put the pragma in the task or task-type declaration. Use a named constant so reviewers can identify the selected size.

Size the stack for the deepest real call path. Include local objects, recursion, exception propagation, and foreign calls in the estimate.

a task type with a 64 KiB requested stack
Worker_Stack_Size : constant := 64 * 1_024;

task type Worker (Kind : Flyology.Execution_Model) is
   pragma Task_Info (Kind);
   pragma Storage_Size (Worker_Stack_Size);
end Worker;

The discriminant uses Flyology.Execution_Model so one task type can select either execution lane.

The requested value is neither the complete task memory footprint nor necessarily the final usable mapping size. The tasking runtime adds an allowance for the alternate signal stack. Flyology then rounds a lightweight stack to the host page size.

Flyology places lightweight stacks in guarded arenas. Each slot has at least 64 KiB of inaccessible guard address space. Native tasks retain the host pthread implementation and its platform minimums.

Flyology.Observability.Stack_Pool returns a Flyology.Observability.Stack_Pool_Snapshot with the effective lightweight stack values. Live_Usable_Bytes is the total usable size after runtime adjustment and page rounding, while Reserved_Bytes includes the virtual address space held by live arenas and their guards. Because reserved address space is not resident memory, measure process RSS separately.

inspect the lightweight stack pool
declare
   Pool : constant Flyology.Observability.Stack_Pool_Snapshot :=
     Flyology.Observability.Stack_Pool;
begin
   Ada.Text_IO.Put_Line
     ("live=" & Pool.Live_Stacks'Image
      & " usable bytes=" & Pool.Live_Usable_Bytes'Image
      & " reserved bytes=" & Pool.Reserved_Bytes'Image);
end;

If all sampled tasks use the same declaration, divide Live_Usable_Bytes by Live_Stacks. The result is the effective usable size for that declaration. With mixed task sizes, this calculation gives only an average.

The current structured-server generic owns its handler task type and uses the compiler runtime default stack size. Storage_Size applies directly to task types declared by the application.