I’m trying to compile a simple program that uses a very large data structure, but I don’t usually get into any exotic options to gnatmake, so I don’t know how to tell it to reserve more space. As it stands, the program can only throw Storage_Error and exit.
could it be you need to increase the stack? that wouldn’t be a compiler issue, but i’ve had that happen to me before.
Yes, that’s exactly what I need to do, but I don’t know how to do it.
I figured it out. Under a UNIX-like system, this works:
ulimit -s unlimited
You should avoid very big objects on the stack. Can’t you declare the very big object at package level ?
Maybe the aliased
keyword would help here? AFAIK, that forces Ada to give the data an address, and maybe that forces the heap to be used?
This is a comment from someone with little Ada experience
Best regards,
Fer
No, “aliased” does not force use of the heap. It merely ensures the object is on an appropriate stoage boundary so it can be the target of an access value. It also notifies the reader and the compiler that there might be multiple access paths to the object, so caveat emptor!
Putting a large object into the global data space by declaring it in a library-level package is one approach. The other is to explicitly create the object using an allocator rather than declaring it as a local variable of a subprogram, and point to it from a local pointer. You can reclaim the storage when done with the object, if appropriate, using an instance of Unchecked_Deallocation.
Here’s that program, in any case:
http://verisimilitudes.net/2024-06-28
I may switch out Ada.Text_IO for Ada.Sequential_IO in the file writing later, since an unnecessary and unwanted newline is placed at the end of the file with the current program. It’s always so tempting to use Ada.Text_IO, but then issues like this always pop up.
For very-big data-sets, one possibility that allows avoiding tweaking with stack-sizes (which you might not have access to on a controlled setting) is using an access-type for data-acquisition [and possibly initial processing].
In certain scientific setups, the raw-data (as seen/captured by the instrument) is actually far more compact, and thus might have some processing to take advantage of that and “compress” it to a more manageable level— Level 0 (raw) and Level 1 (some lossless “compression” or format), respectively.
For Ada, something like:
Type Pixel_32 is record
A, B, G, R : Interfaces.Unsigned_8:= 0;
end record
with Size => 32;
Subtype Index is Integer range 1..Integer'Last;
Type Raw_Data is Array (Index range <>) of Pixel_32;
You quickly run out of storage-space, and if querying from a single camera, you’re not using the A-channel, so that’s a wasted byte for every pixel.
So, let’s say that you’ve got some process or set-up where, if you didn’t have the alpha-channel, you could pass the data around on the stack just fine.
To do this you would “stash” the incoming raw-data in the access type, then return the conversion, all within the local-scope of your acquisition subprogram, allowing it to clean-up the heap when finished:
Type Pixel_24 is record
B, G, R : Interfaces.Unsigned_8:= 0;
end record;
Type Data is Array (Index range <>) of Pixel_32;
Function Get_Data return Data is
Type Raw_Chunk is not null access Raw_Data;
Blank : Constant Raw_Chunk:= New Raw_Data'( 2..1 => <> );
Function Get_Chunk( Input : Raw_Chunk:= Blank ) return Raw_Chunk is
Function Acquire return Raw_Data is
Begin
-- STUB!!
Return Blank; -- Here is where you would get a chunk of data.
End Acquire;
Temp : Raw_Data renames Acquire;
Begin
if Temp'Length not in Positive then
Return Input;
else
Return new Raw_Data'( Input.All & Temp.All );
end if;
End Get_Chunk;
Data_Set : Raw_Chunk renames Get_Chunk;
Begin
Return Result : Data(Data_Set'Range) do
For X in Data_Set'Range loop
Result(X).R:= Data_Set(X).R;
Result(X).G:= Data_Set(X).G;
Result(X).B:= Data_Set(X).B;
end loop;
end return;
-- And the compiler is free to return everything from the heap that Raw_Chunk used.
End Get_Data;
You might even be able to do it directly, skipping the access-type and constructing it by-parts as in the Reading Long Strings example from AdaPower:
-- Reading Long Strings Using Recursion (Martin C. Carlisle)
function Next_Line(File : in Ada.Text_IO.File_Type :=
Ada.Text_Io.Standard_Input) return String is
Answer : String(1..256);
Last : Natural;
begin
Ada.Text_IO.Get_Line(File => File,
Item => Answer,
Last => Last);
if Last = Answer'Last then
return Answer & Next_Line(File);
else
return Answer(1..Last);
end if;
end Next_Line;