Board index » delphi » Stack manipulation and local variables

Stack manipulation and local variables


2006-08-11 02:19:23 AM
delphi205
Hi all,
I have a performance critical routine in which I need to use a temporary
buffer. The size of the buffer can vary, so it would make sense to use a
dynamic array. However, by using a dynamic array, memory would have to be
allocated/deallocated within the routine itself (and consequently it would
degrade performance).
One option would be to preallocate the memory in a global variable. This
would, however, cause problems in multithreaded applications, since multiple
threads could then update the same memory. I need to ensure that the routine
is thread-safe, so I want to avoid this kind of memory conflicts. Also I
don't want to use critical sections, since that would degrade performance as
well.
A possible solution would be to dynamically grow the stack upon entering the
procedure. We could then use the extra stack space to store the buffer.
I considered the following implementation:
procedure Test(Size: Integer);
var
I: Integer;
P: PByteArray; // temporary buffer
begin
asm
SUB ESP,Size
MOV P,ESP
end;
...
for I := 0 to Size - 1 do P[I] := I;
...
end;
This seems to work well (assuming the stack is decreased by a multiple of
4).
Does anyone know if this approach is reliable? Could it have any undesirable
side-effects?
TIA,
Mattias
 
 

Re:Stack manipulation and local variables

Mattias Andersson a écrit :
Quote
One option would be to preallocate the memory in a global variable. This
would, however, cause problems in multithreaded applications, since multiple
threads could then update the same memory. I need to ensure that the routine
is thread-safe, so I want to avoid this kind of memory conflicts. Also I
don't want to use critical sections, since that would degrade performance as
well.
The keyword "threadvar" will allocate a new variable for each thread.
--
Florent Ouchet
 

Re:Stack manipulation and local variables

Hi Mattias,
Quote
Does anyone know if this approach is reliable? Could it have any
undesirable side-effects?
As long as the size of the buffer is less than 4K then it is safe. If it is
greater than 4K then you must make sure that you "touch" every 4K page from
the end of the buffer down to the top, otherwise you may skip over the stack
guard page, causing the stack to not grow as it should and thus an A/V. You
can have a look at the code that the Delphi compiler generates to safely use
local variables>4K for ideas. Just write a routine with a local variable
static array>4K that actually uses the array and put a breakpoint in there
to see what the code looks like. Also remember that the stack size is
limited, so this approach is not a good idea for nested calls.
What I usually do is to have a fixed size local buffer of just under 4K. If
the routine finds that the buffer is sufficient then it uses it, otherwise
it allocates one through GetMem. If most of the data that will be processed
is under 4K, then this works very well.
Regards,
Pierre
 

Re:Stack manipulation and local variables

Hi,
Borland has done this at VCL unit Grids.pas. Search for function
StackAlloc on that unit.
Best regards
Marcelo Rocha
 

Re:Stack manipulation and local variables

Quote

end;

This seems to work well (assuming the stack is decreased by a multiple of
4).

Does anyone know if this approach is reliable? Could it have any undesirable
side-effects?

Umm.. I am guessing that this is OK, since, in effect, you are just
allocating space for a local var in the same way as the compiler does.
The stack should be corrected before the return because, IIRC, the
compiler reloads ESP from EBP before returning & so dumps your buffer
along with all the other locals.
I've usually just dodged this issue, if it came up, by declaring a large
enough local array to hold the biggest block possible and just used a
bit of it if required.
If your buffer context has to be preserved across calls, then that is a
whole new area, but it seems that is not the case for your requirement.
Rgds,
Martin
 

Re:Stack manipulation and local variables

Marcelo Campos Rocha writes:
Quote
Borland has done this at VCL unit Grids.pas. Search for function
StackAlloc on that unit.
Thanks Marcelo. This is exactly what I was looking for. I wonder why they
didn't put this in SysUtils.pas instead.
--Mattias
 

Re:Stack manipulation and local variables

Thanks everyone for the great response! I think I have some different ideas
of how to approach this now.
Regards,
Mattias