Discussion:
segfault with large-ish array with GNAT
(too old to reply)
Jerry
2010-03-17 19:21:51 UTC
Permalink
The following program produces a segmentation fault when run with the
array size set to 1_048_343 but not when it is set to 1_048_342.
What's going on and how do I fix it? If I put in a bit of text IO the
allowed array size is some what smaller.

GNATMAKE 4.4.0 20080314 (experimental) [trunk revision 133226]
OS X 10.5.8
4 GB RAM



procedure bomb is
type Float_Array_Type is array (Integer range <>) of Long_Float;
-- 1_048_343 causes segmentation fault, 1_048_342 does not.
x : Float_Array_Type(1 .. 1_048_343);
begin
x(1) := 1.0;
end bomb;


Jerry
Gautier write-only
2010-03-17 19:36:33 UTC
Permalink
Perhaps you hit a stack limit (pure guess), or there is really a hole
in the memory :-).
In case of a stack issue you would have perhaps
raised STORAGE_ERROR : object too large
or
raised STORAGE_ERROR : EXCEPTION_STACK_OVERFLOW
(with -fstack-check)
G.
Georg Bauhaus
2010-03-17 19:58:13 UTC
Permalink
Post by Gautier write-only
Perhaps you hit a stack limit (pure guess), or there is really a hole
in the memory :-).
In case of a stack issue you would have perhaps
raised STORAGE_ERROR : object too large
or
raised STORAGE_ERROR : EXCEPTION_STACK_OVERFLOW
(with -fstack-check)
G.
Anything to do with
http://en.wikibooks.org/wiki/Ada_Programming/Tips#Stack_Size ?

Any news on GCC stack checking and page(?) size?
Trampolines, if applicable?
Jerry
2010-03-18 06:45:25 UTC
Permalink
Thanks for the helpful comments.

First,
ulimit -s unlimited
does not work on OS X:
-bash: ulimit: stack size: cannot modify limit: Operation not
permitted
but I understand that it works on Linux. And possibly the reason is
the difference in the way that Linux and OS X treat stack and heap
memory. (Don't be confused and think I know what I'm talking about but
I read that somewhere.)

ulimit allows querying the hard limit of stack space
ulimit -Hs
which on OS X reports 65532 = 2^16 -4 kilobytes, about 67 MB. The user
via ulimit can set the stack up to that size but not higher:
ulimit -s 65532
The default soft limit on OS X is 8192 kB, found by
ulimit -s

So here's me being naive: I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up. (Like not having to worry about whether arguments to
subprograms are passed by value or by reference--it just happens.)

But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?

In this context, is there any advantage to declaring the large object
inside a declare block? Would that force the memory to be allocated
from the heap?

Jerry
Ludovic Brenta
2010-03-18 07:52:55 UTC
Permalink
Post by Jerry
I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up. (Like not having to worry about whether arguments to
subprograms are passed by value or by reference--it just happens.)
So, you would like the Ada run-time to bypass the operating system-
enforced, administrator-approved stack limit? If userspace programs
could do that, what would be the point of having a stack limit in the
first place?

--
Ludovic Brenta.
Robert A Duff
2010-03-18 23:57:13 UTC
Permalink
Post by Ludovic Brenta
Post by Jerry
I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up. (Like not having to worry about whether arguments to
subprograms are passed by value or by reference--it just happens.)
So, you would like the Ada run-time to bypass the operating system-
enforced, administrator-approved stack limit? If userspace programs
could do that, what would be the point of having a stack limit in the
first place?
Well, yeah, but what IS the point of having a stack limit in the
first place? As opposed to a limit on virtual memory use,
whether it be stack or heap or whatever.

It's useful to limit a process to a certain amount of virtual address
space. It prevents that process from hogging the whole system. And
it prevents infinite-recursion bugs from causing thrashing. And it
prevents infinite-"new" bugs from causing the same.

It seems to me, a process should be allowed to allocate its
memory however it likes. If it is allowed to allocate (say)
2 gigabytes of address space, then it should be allowed to
allocate (say) half of that to the main thread's stack,
if it likes.

- Bob
Jeffrey Creem
2010-03-18 10:13:18 UTC
Permalink
Post by Jerry
Thanks for the helpful comments.
So here's me being naive: I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up. (Like not having to worry about whether arguments to
subprograms are passed by value or by reference--it just happens.)
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
In this context, is there any advantage to declaring the large object
inside a declare block? Would that force the memory to be allocated
from the heap?
Jerry
If you want the memory to come from the heap, you need to declare the
variables inside of packages instead of inside procedures. You can then
avoid using access types.

declare blocks will not help.

As for wishing that the compiler would automatically switch between heap
and stack, that would probably be a terrible idea and render the
language quite unsuitable for embedded systems.


-- warning, not even compiled early morning code example below

package do_stuff is
procedure no_bomb;
end do_stuff;

package body do_stuff is
type Float_Array_Type is array (Integer range <>) of Long_Float;
-- 1_048_343 causes segmentation fault, 1_048_342 does not.
x : Float_Array_Type(1 .. 1_048_343);

procedure No_bomb is

begin
x(1) := 1.0;
end No_bomb;
end do_stuff;


with do_stuff;
procedure stuff is

begin
do_stuff.No_Bomb;
end stuff;
Ludovic Brenta
2010-03-18 10:23:44 UTC
Permalink
Post by Jeffrey Creem
Post by Jerry
Thanks for the helpful comments.
So here's me being naive: I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up. (Like not having to worry about whether arguments to
subprograms are passed by value or by reference--it just happens.)
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
In this context, is there any advantage to declaring the large object
inside a declare block? Would that force the memory to be allocated
from the heap?
Jerry
If you want the memory to come from the heap, you need to declare the
variables inside of packages instead of inside procedures. You can then
avoid using access types.
declare blocks will not help.
As for wishing that the compiler would automatically switch between heap
and stack, that would probably be a terrible idea and render the
language quite unsuitable for embedded systems.
-- warning, not even compiled early morning code example below
package do_stuff is
    procedure no_bomb;
end do_stuff;
package body do_stuff is
      type Float_Array_Type is array (Integer range <>) of Long_Float;
      -- 1_048_343 causes segmentation fault, 1_048_342  does not.
      x : Float_Array_Type(1 .. 1_048_343);
     procedure No_bomb is
     begin
       x(1) := 1.0;
     end No_bomb;
end do_stuff;
with do_stuff;
procedure stuff is
begin
    do_stuff.No_Bomb;
end stuff;
No, the array is not in the heap in this case; it is in the executable
program's data segment. This may increase the size of the binary file.

To ensure that the array is on the heap, it is necessary to use an
access type and an allocator, e.g.:

type Float_Array_Access_Type is access Float_Array_Type;
x : Float_Array_Access_Type := new Float_Array_Type (1 .. 1_048_343);

--
Ludovic Brenta.
Jerry
2010-03-19 00:44:59 UTC
Permalink
<snip>
Post by Ludovic Brenta
Post by Jeffrey Creem
If you want the memory to come from the heap, you need to declare the
variables inside of packages instead of inside procedures. You can then
avoid using access types.
<snip>
Post by Ludovic Brenta
Post by Jeffrey Creem
package do_stuff is
    procedure no_bomb;
end do_stuff;
package body do_stuff is
      type Float_Array_Type is array (Integer range <>) of Long_Float;
      -- 1_048_343 causes segmentation fault, 1_048_342  does not.
      x : Float_Array_Type(1 .. 1_048_343);
     procedure No_bomb is
     begin
       x(1) := 1.0;
     end No_bomb;
end do_stuff;
with do_stuff;
procedure stuff is
begin
    do_stuff.No_Bomb;
end stuff;
No, the array is not in the heap in this case; it is in the executable
program's data segment. This may increase the size of the binary file.
To ensure that the array is on the heap, it is necessary to use an
type Float_Array_Access_Type is access Float_Array_Type;
x : Float_Array_Access_Type := new Float_Array_Type (1 .. 1_048_343);
--
Ludovic Brenta.
This (using a package) works. I made two Long_Float arrays of
100_000_000 length. The binary size is 292 KB (I included Text_IO)
regardless of the size of the arrays.

I'm not sure if I like the programming style better than using access
variables. I would have to essentially embed my entire program in a
package. And it seems to become impossible to selectively release
memory as is possible with access types. But it does solve my problem.

I programmed Pascal on Mac OS < 10 for years using pointers to arrays.
IIRC the stack was 32 KB.

Jerry
Adam Beneschan
2010-03-18 19:51:24 UTC
Permalink
Post by Jeffrey Creem
As for wishing that the compiler would automatically switch between heap
and stack, that would probably be a terrible idea and render the
language quite unsuitable for embedded systems.
Ummm, you're mixing two things there. The *language* is suitable for
embedded systems. The language does not dictate anything about where
things are stored, and nobody is asking for the Ada standard to
require that every Ada implementation be able to allocate every large
local array it sees. Not every compiler that compiles the language
will be suitable for embedded systems, but that's not a bad thing---
not everyone who uses an Ada compiler is using it for embedded
systems, and those that aren't shouldn't mind if their particular Ada
*implementation* does things in a way that's not suitable for embedded
systems.

I don't see a problem with a compiler generating code to allocate
arrays on the heap that it knows will be large, or supporting a pragma
that tells it to put arrays on the heap.

-- Adam
John B. Matthews
2010-03-18 14:44:21 UTC
Permalink
In article
Post by Jerry
Thanks for the helpful comments.
First,
ulimit -s unlimited
-bash: ulimit: stack size: cannot modify limit: Operation not
permitted but I understand that it works on Linux. And possibly the
reason is the difference in the way that Linux and OS X treat stack
and heap memory. (Don't be confused and think I know what I'm talking
about but I read that somewhere.)
ulimit allows querying the hard limit of stack space
ulimit -Hs
which on OS X reports 65532 = 2^16 -4 kilobytes, about 67 MB. The user
ulimit -s 65532
The default soft limit on OS X is 8192 kB, found by
ulimit -s
So here's me being naive: I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up. (Like not having to worry about whether arguments to
subprograms are passed by value or by reference--it just happens.)
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
I think so. When I ran into this some years ago, I was pleasantly
surprised at how easy it was to change over to heap allocation for my
largest data structure. Under Mac OS 9, such allocations fragmented the
heap, but Mac OS X behaves more reasonably.

The menace listed below allocates megabyte-sized blocks right up to the
limit of wired memory, as shown by top:

-----
with Ada.Text_IO;

procedure Heap_Test is

Megabyte : constant Positive := 1024 * 1024;
type Block is array (0 .. Megabyte - 1) of Character;
type Block_Ptr is access all Block;

BPtr : Block_Ptr;
N : Natural := 1;

begin
Ada.Text_IO.Put_Line("*** Heap test...");
while True loop
BPtr := new Block;
Ada.Text_IO.Put (N'Img);
N := N + 1;
end loop;
Ada.Text_IO.New_Line;
end Heap_Test;
-----

This horror raises STORAGE_ERROR at the `ulimit -s` you showed, but only
when compiled with -fstack-check:

-----
with Ada.Text_IO;

procedure Stack_Test is

Megabyte : constant Positive := 1024 * 1024;
type Block is array (0 .. Megabyte - 1) of Character;

procedure Allocate_Stack (N : Positive) is
Local : Block := (others => Character'Val(0));
begin
Ada.Text_IO.Put (N'Img);
Allocate_Stack(N + 1);
end;

begin
Ada.Text_IO.Put_Line("*** Stack test...");
Allocate_Stack(1);
Ada.Text_IO.New_Line;
end Stack_Test;
-----

For reference, ulimit is a bash built-in, so `man bash` for details:

<http://linux.die.net/man/1/bash>
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
Jeffrey R. Carter
2010-03-19 04:44:42 UTC
Permalink
Post by John B. Matthews
while True loop
...
end loop;
In Ada, we write infinite loops as

loop
...
end loop;
--
Jeff Carter
"Now go away or I shall taunt you a second time."
Monty Python & the Holy Grail
07
John B. Matthews
2010-03-19 08:14:44 UTC
Permalink
Post by Jeffrey R. Carter
Post by John B. Matthews
while True loop
...
end loop;
In Ada, we write infinite loops as
loop
...
end loop;
I suppose this is worse! ;-)

loop
...
exit when False;
end loop;
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
Gautier write-only
2010-03-18 15:36:48 UTC
Permalink
Post by Jerry
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
Seems so.
Funnily I had a similar surprise ~12 years ago.
It was with a reputable Ada 83 compiler (DEC Ada), on the university's
main server, with a very reputable system (OpenVMS).
I had declared: A: Matrix(m,n); somewhere, and the m's and n's were
enough for 500MB.
And told myself the system would be smart enough...
Build, run... oh, frozen - and everybody was going out of the offices:
"what happened with the mail ? what happened with... ?"

G.
t***@acm.org
2010-03-18 16:46:19 UTC
Permalink
Post by Jerry
So here's me being naive: I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up. (Like not having to worry about whether arguments to
subprograms are passed by value or by reference--it just happens.)
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
A couple of years ago I wrote some code to look at the (large) Netflix
data set. It used Janus Ada and ran in a 2 GB Windows system. I thought
about switching to Gnat (for faster floating point) but discovered that
would require changing all large arrays to heap allocation, so I dropped
that idea. IMO, that's a ridiculous limitation in this day and age.
Warren
2010-03-18 19:11:02 UTC
Permalink
Post by t***@acm.org
Post by Jerry
So here's me being naive: I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up. (Like not having to worry about whether arguments to
subprograms are passed by value or by reference--it just happens.)
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
A couple of years ago I wrote some code to look at the (large) Netflix
data set. It used Janus Ada and ran in a 2 GB Windows system. I thought
about switching to Gnat (for faster floating point) but discovered that
would require changing all large arrays to heap allocation, so I dropped
that idea. IMO, that's a ridiculous limitation in this day and age.
2gb is wayyy too small. ;-)

Warren
Warren
2010-03-18 17:03:19 UTC
Permalink
Jerry expounded in news:ac4bed10-f655-4fa5-8891-2967ba4388a0
@k6g2000prg.googlegroups.com:
..
Post by Jerry
So here's me being naive: I would have thought that Ada (or GNAT
specifically) would be smart enough to allocate memory for large
objects such as my long array in a transparent way so that I don't
have to worry about it, thus (in the Ada spirit) making it harder to
screw up.
Programmer's do still have some responsibility in
design, Ada or otherwise. ;-)
Post by Jerry
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
..
Post by Jerry
Jerry
The stack is a valuable resource and sometimes you need to
be careful with allocation. I forget how gnat implements
tasks (threads) precisely, but they too require a stack. So
your virtual address space for stack must also be carved up
for each additional task. A 2G address space seemed huge 20
years ago, but it seems rather small these days.

With the new focus on parallel cores etc., I've often pondered
what a future CPU without a stack might look like. Imagine
a CPU that somehow in microcode was able to do a fast-malloc
of a stack frame (as part of a call), linking the new
frame back to the calling frame. Then you could eliminate
the need for a "linear virtual stack region" altogether. This
would allow code to freely fork into many parallel
threads without the issue of pre-allocating stack [address]
space to each new thread. When the called procedure executed
a "return", it would (in microcode) free the current stack
frame and return to the prior one. The "call" allocate/free's
could be constrained to one general "stack heap".

[..back from the day-dream..]

Generally speaking, large objects are best allocated
from the heap. But don't forget to release them once
finished. Otherwise you'll only feed from that trough
a few times also. ;-)

Warren
Maciej Sobczak
2010-03-18 20:38:41 UTC
Permalink
Post by Warren
With the new focus on parallel cores etc., I've often pondered
what a future CPU without a stack might look like. Imagine
a CPU that somehow in microcode was able to do a fast-malloc
of a stack frame
There is no need to do that in microcode - the compiler decides what
does it mean to call a subprogram and what does it mean to allocate
the "frame", so you might simply have a compiler that implements these
concepts in terms of a dynamically allocated linked list.
I vaguely remember reading about a C compiler that did exactly that a
while ago - but I fail to find it in Google due to the noise from
billions of tutorials with stacks and lists. :-)

Today you might find this idea implemented in just about any
*interpreter*.

--
Maciej Sobczak * www.inspirel.com

YAMI4 - Messaging Solution for Distributed Systems
http://www.inspirel.com/yami4/
Charmed Snark
2010-03-19 13:26:31 UTC
Permalink
Maciej Sobczak expounded in news:6b9abbbd-2d5e-4e80-b353-fc4d1ccd2963
Post by Maciej Sobczak
Post by Warren
With the new focus on parallel cores etc., I've often pondered
what a future CPU without a stack might look like. Imagine
a CPU that somehow in microcode was able to do a fast-malloc
of a stack frame
There is no need to do that in microcode - the compiler decides what
does it mean to call a subprogram and what does it mean to allocate
the "frame", so you might simply have a compiler that implements these
concepts in terms of a dynamically allocated linked list.
True enough..
Post by Maciej Sobczak
I vaguely remember reading about a C compiler that did exactly that a
while ago - but I fail to find it in Google due to the noise from
billions of tutorials with stacks and lists. :-)
Interesting. Do you recall the time frame? Was it DOS era
or post Win95?
Post by Maciej Sobczak
Today you might find this idea implemented in just about any
*interpreter*.
Maciej Sobczak * www.inspirel.com
Even interpreters use stacks. A basic interpreter needs to
allocate a stack for each thread of control. However, as
you say, it could be implemented differently as a linked
list of "frames".

Warren
t***@acm.org
2010-03-19 17:27:22 UTC
Permalink
IIRC, the Burroughs 6500 had what they called a "cactus stack" where
branching would occur for new threads. And there was a Texas Instruments
microprocessor that had no real stack, but rather a set of registers
that could be saved to RAM on a subroutine call.
These preceded DOS.
Simon Wright
2010-03-19 18:02:42 UTC
Permalink
Post by t***@acm.org
IIRC, the Burroughs 6500 had what they called a "cactus stack" where
branching would occur for new threads. And there was a Texas Instruments
microprocessor that had no real stack, but rather a set of registers
that could be saved to RAM on a subroutine call.
These preceded DOS.
The PDP-8 worked like that; the JMS instruction stored the return
address in the first word of the subroutine, execution started at the
next word.

JMS FOO / CALL SUBROUTINE FOO


FOO, +0 / STORED RETURN ADDRESS
...
JMP I FOO / RETURN

(we only had capitals)

--S
Warren
2010-03-19 20:10:14 UTC
Permalink
Post by Simon Wright
Post by t***@acm.org
IIRC, the Burroughs 6500 had what they called a "cactus stack" where
branching would occur for new threads. And there was a Texas
Instruments microprocessor that had no real stack, but rather a set
of registers that could be saved to RAM on a subroutine call.
These preceded DOS.
The PDP-8 worked like that; the JMS instruction stored the return
address in the first word of the subroutine, execution started at the
next word.
That was the way with the IBM-1130 as well. Not too
good for recursive calls though.

Warren
Adam Beneschan
2010-03-19 21:50:20 UTC
Permalink
Post by Simon Wright
Post by t***@acm.org
IIRC, the Burroughs 6500 had what they called a "cactus stack" where
branching would occur for new threads.  And there was a Texas Instruments
microprocessor that had no real stack, but rather a set of registers
that could be saved to RAM on a subroutine call.
These preceded DOS.
The PDP-8 worked like that; the JMS instruction stored the return
address in the first word of the subroutine, execution started at the
next word.
   JMS FOO    / CALL SUBROUTINE FOO
   FOO, +0    / STORED RETURN ADDRESS
   ...
   JMP I FOO  / RETURN
(we only had capitals)
--S
Isn't that approximately how all computers used to work? Or at least
a lot of them? When I was first learning how computers ran, it seemed
like the common thing was for jump instructions to save the address of
the next instruction in a register, and then the subroutine code would
store the register somewhere---perhaps in the location containing the
return jump, since I don't remember those computers having "indirect
jump" instructions either. It was a few years before I encountered a
machine that automatically saved return addresses on a stack---or even
had a concept of a stack built into it.

One thing I remember was a particular computer's implementation of
COBOL (Honeywell 200/2000 series---my dad used to work for Honeywell
so those were some of the computers I was most familiar with). COBOL
used PERFORM statements for subroutine calls, and since you could have
PERFORM A in one part of the program and PERFORM A THROUGH B in
another part, or you could just fall into A without a PERFORM, the
paragraph A couldn't tell whether it was supposed to return to the
caller at the end of the paragraph. So the code, before it did a
PERFORM A, would do a "move" to move a branch instruction into a
location at the end of A that would branch back to the caller. Then,
after it returned, it would do another "move" to move a no-op to that
location.

Of course, none of these were good with recursion but I don't think
the experts understood the importance of recursion back then.

-- Adam
Warren
2010-03-19 20:24:29 UTC
Permalink
Post by t***@acm.org
IIRC, the Burroughs 6500 had what they called a "cactus stack" where
branching would occur for new threads.
Looking up "cactus threads" reveals that it is also
known as a "spaghetti stack". Looking at the picture on
wikipedia seems to suggest exactly what I envisioned.

http://en.wikipedia.org/wiki/Spaghetti_stack
Post by t***@acm.org
And there was a Texas Instruments
microprocessor that had no real stack, but rather a set of registers
that could be saved to RAM on a subroutine call.
These preceded DOS.
Wasn't that the TMS9900? It also had this neat X instruction,
that could execute one instruction pointed by another register,
but control returned to the instruction following the X instruction
itself. Effectively execute and return from an arbitrary instruction.
I'm not sure what happens if X invoked a "call" instruction of
some sort.

Thanks for the lead on "cactus threads".

Warren
Warren
2010-03-19 20:38:49 UTC
Permalink
Maciej Sobczak expounded in news:6b9abbbd-2d5e-4e80-b353-fc4d1ccd2963
Post by Maciej Sobczak
Post by Warren
With the new focus on parallel cores etc., I've often pondered
what a future CPU without a stack might look like. Imagine
a CPU that somehow in microcode was able to do a fast-malloc
of a stack frame
There is no need to do that in microcode - the compiler decides what
does it mean to call a subprogram and what does it mean to allocate
the "frame", so you might simply have a compiler that implements these
concepts in terms of a dynamically allocated linked list.
I vaguely remember reading about a C compiler that did exactly that a
while ago - but I fail to find it in Google due to the noise from
billions of tutorials with stacks and lists. :-)
Maciej Sobczak * www.inspirel.com
Were you thinking Cilk (or Cilk++)? I saw this in passing this
afternoon. One reference indicates a Cilk project existing since
'94 using gcc. Looks like good reading material for this weekend.

Warren
Ludovic Brenta
2010-03-19 08:31:27 UTC
Permalink
Post by Warren
Imagine
a CPU that somehow in microcode was able to do a fast-malloc
of a stack frame (as part of a call), linking the new
frame back to the calling frame. Then you could eliminate
the need for a "linear virtual stack region" altogether. This
would allow code to freely fork into many parallel
threads without the issue of pre-allocating stack [address]
space to each new thread. When the called procedure executed
a "return", it would (in microcode) free the current stack
frame and return to the prior one.  The "call" allocate/free's
could be constrained to one general "stack heap".
I wonder how that would work with processors that have register
windows specifically to reduce the need for a memory-based stack (i.e.
SPARC, IA64 and maybe others).

--
Ludovic Brenta.
Warren
2010-03-19 13:20:19 UTC
Permalink
Ludovic Brenta expounded in news:bce19c00-0599-4ff6-a5cf-16bb3d742373
Post by Ludovic Brenta
Post by Warren
Imagine
a CPU that somehow in microcode was able to do a fast-malloc
of a stack frame (as part of a call), linking the new
frame back to the calling frame. Then you could eliminate
the need for a "linear virtual stack region" altogether. This
would allow code to freely fork into many parallel
threads without the issue of pre-allocating stack [address]
space to each new thread. When the called procedure executed
a "return", it would (in microcode) free the current stack
frame and return to the prior one.  The "call" allocate/free's
could be constrained to one general "stack heap".
I wonder how that would work with processors that have register
windows specifically to reduce the need for a memory-based stack (i.e.
SPARC, IA64 and maybe others).
--
Ludovic Brenta.
I'm not sure I follow, but objects like small buffers would
presumably still occupy the current stack frame.

Warren
Brian Drummond
2010-03-19 12:04:36 UTC
Permalink
Post by Jerry
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
I believe so.
But code using the array can be written as normal, with a "my_array ... renames
my_array_ptr.all" clause to hide the pointer.

- Brian
Jerry
2010-03-19 19:22:35 UTC
Permalink
Post by Brian Drummond
Post by Jerry
But it seems that I will have to allocate memory for large objects
using pointers (and thus take the memory from the heap). Is that
right?
I believe so.
But code using the array can be written as normal, with a "my_array ... renames
my_array_ptr.all" clause to hide the pointer.
- Brian
Cool tip. Thanks.
Jerry
Jeffrey R. Carter
2010-03-19 20:22:44 UTC
Permalink
Post by Brian Drummond
But code using the array can be written as normal, with a "my_array ... renames
my_array_ptr.all" clause to hide the pointer.
Generally, after something like

A : constant Array_Ptr := new Array_Type [(Low .. High)];

You can use A just as if it were the array itself:

B := A (A'First);
A (A'First) := A (A'Last);
A (A'Last) := B;
--
Jeff Carter
"If you think you got a nasty taunting this time,
you ain't heard nothing yet!"
Monty Python and the Holy Grail
23
Jerry
2010-03-19 23:24:41 UTC
Permalink
On Mar 19, 1:22 pm, "Jeffrey R. Carter"
Post by Jeffrey R. Carter
Post by Brian Drummond
But code using the array can be written as normal, with a "my_array ... renames
my_array_ptr.all" clause to hide the pointer.
Generally, after something like
A : constant Array_Ptr := new Array_Type [(Low .. High)];
B := A (A'First);
A (A'First) := A (A'Last);
A (A'Last) := B;
--
Jeff Carter
That is true when accessing array elements and slices but not for
indicating the entire array as a single entity such as in a subroutine
argument, e.g.

y := cos(x);

or

z := x + y;

with

function "+" (Left, Right : Real_Vector) return Real_Vector;

which is from ARM G.3.1.

Using access variables without renaming, the above line would have to
be written

y := cos(x.all);

and

z.all := x.all + y.all;

and in the algebraic-like calculations that are possible using
overloads the .all's clutter up the equation a bit. It's just a matter
of where you want to put the eye pollution. I have an extensive
library of subroutines including overloads that work with Real_Vector
and Complex_Vector from G.3 and either way (renaming or .all-ing)
works fine but on balance I think renaming is easier to read (and
probably easier to forget to release memory 8^( .)

Jerry
Jeffrey R. Carter
2010-03-20 00:25:30 UTC
Permalink
Post by Jerry
That is true when accessing array elements and slices but not for
indicating the entire array as a single entity such as in a subroutine
argument, e.g.
y := cos(x);
or
z := x + y;
That's true. I haven't done a lot of code like that recently, so not doing a
renames tends to work fine for me; hence "generally". (Also, I haven't messed
with big arrays much recently, either.) If you do reference the whole array
frequently, it's a different story.
--
Jeff Carter
"I wave my private parts at your aunties."
Monty Python & the Holy Grail
13
Björn Persson
2010-05-07 21:58:13 UTC
Permalink
Post by Jerry
ulimit allows querying the hard limit of stack space
ulimit -Hs
which on OS X reports 65532 = 2^16 -4 kilobytes, about 67 MB. The user
ulimit -s 65532
The default soft limit on OS X is 8192 kB, found by
ulimit -s
I read this discussion as it happened, and thought it should be possible for
a program to raise its own soft stack limit up to the hard limit, without a
shell script wrapper. Today I stumbled on it. The POSIX system calls are
getrlimit and setrlimit. It should be possible to import them with the usual
methods for interfacing to C. Try "man 2 setrlimit" on any Unix-like system.
Maybe this helps someone.
--
Björn Persson
PGP key A88682FD
jonathan
2010-03-17 19:57:12 UTC
Permalink
Post by Jerry
The following program produces a segmentation fault when run with the
array size set to 1_048_343 but not when it is set to 1_048_342.
What's going on and how do I fix it? If I put in a bit of text IO the
allowed array size is some what smaller.
GNATMAKE 4.4.0 20080314 (experimental) [trunk revision 133226]
OS X 10.5.8
4 GB RAM
procedure bomb is
    type Float_Array_Type is array (Integer range <>) of Long_Float;
    -- 1_048_343 causes segmentation fault, 1_048_342  does not.
    x : Float_Array_Type(1 .. 1_048_343);
begin
    x(1) := 1.0;
end bomb;
Jerry
Have you tried setting the stacksize in your shell. In bash the
command is

ulimit -s unlimited

in csh, (I seem to recall):

limit stacksize unlimited

Type ulimit or limit to see what the defaults are.
When I do it on Debian Linux, your program I get arrays up to
2 Gigabyte in size.

HTH ...

Jonathan
Loading...