Board index » delphi » How to expand high-level inline functions???? <<<<<<<<

How to expand high-level inline functions???? <<<<<<<<

I am working on a real-time data processing application which is
sensitive to runtime code performance.  I am willing to trade runtime
code size to gain any addition performance.  To help minimize needless
stack loading/unloading, stack frame management, and other misc
call/return overhead, the same key inner loop of approx 10-15 lines
of code has been replicated rather than coded as a function call.
An example is given below:

for i:=1 to 100 do
begin
   z:=sqrt( sqr(apple[i].x) + sqr(apple[i].y) );
   apple[i].x:=1200+x/z*500;
   apple[i].y:=1500+y/z*600;
end;

{still elsewhere in the code}
for i:=1 to 2 do
begin
   z:=sqrt( sqr(orange[i].x) + sqr(orange[i].y) );
   orange[i].x:=1200+x/z*500;
   orange[i].y:=1500+y/z*600;
end;

{elsewhere in the code another billion times later}
for i:=1 to 10 do
   for j:=20 to 30 do
   begin
      z:=sqrt( sqr(banana[i,j].x) + sqr(banana[i,j].y) );
      banana[i,j].x:=1200+x/z*500;
      banana[i,j].y:=1500+y/z*600;
   end;

==================================================

To assist in the management of the software, I would like to define a
transform function once and inline expand each occurrence.  The code
given above would then be compatible with:

{define generic transform function}
function transform(argument:fruit_type):fruit_type;
cool_inline_expand_directive;         {<<<<<<<<<<<<<<<<<<<<<<<<<<<<}
var
   temp : real;
begin
   temp:=sqrt( sqr(argument.x) + sqr(argument.y) );
   transform.x:=1200+x/z*500;
   transform.y:=1500+y/z*600;
end;

for i:=1 to 100 do
   apple[i]:=transform(apple[i]);

{still elsewhere in the code}
for i:=1 to 2 do
   orange[i]:=transform(orange[i]);

{elsewhere in the code another billion times}
for i:=1 to 10 do
   for j:=20 to 30 do
      banana[i,j]:=transform(banana[i,j]);

=========================================================

Any thoughts would be surely welcomed.  Please limit responses to solutions
were the transform function can be managed using high-level entry, I already
understand how to function/procedure inline assembly expansion.  Rest
assured, you wouldn't want to support all the future changes to the
application code were these kind of "tricks" are defined using machine code.

Thank you for your patience and help,
   m...@procyon.cdev.com

P.S.  Please don't correct any syntax errors I may have made representing
my problem.  The code given above should only be used as a rough guide to
help understand the problem better.  :^)

 

Re:How to expand high-level inline functions???? <<<<<<<<


Hi Mike!

MEx> I am working on a real-time data processing application which is
MEx> sensitive to runtime code performance.  I am willing to trade runtime
MEx> code size to gain any addition performance.

Maybe you don't need outright code size explosions (that is, by inlining) to
gain performance.

One thing first: try reordering your variables in a var-block such that first
are 32bit variables (longint, pointers etc), then 16bit variables (integer,
word), then 8bit (boolean, char, enums), and last variables with other sizes
(records) and finally standard strings (256 bytes each). Inside procedures and
functions that reduces the stack offset needed for most variables to smaller
size (8bit) which operates faster than 16bit offsets, while arranging the
smaller variables so that they are optimally aligned (each var-block starts out
with optimal alignment).

Like:

procedure foobar;
var
  p_mystuff: pointer;
  l: longint;
  w: word;
  i: integer;
  c: char;
  b: boolean;

MEx> An example is given below:

MEx> for i:=1 to 10 do
MEx>    for j:=20 to 30 do
MEx>    begin
MEx>       z:=sqrt( sqr(banana[i,j].x) + sqr(banana[i,j].y) );
MEx>       banana[i,j].x:=1200+x/z*500;
MEx>       banana[i,j].y:=1500+y/z*600;
MEx>    end;

Either declare pointers or use with statements here (the pointer solution has
the advantage of not opening a new namespace). Then use real constants if this
here is a real expression, to make clear what it is (AFAIK the BP7 is smart
enough to convert the integer consts at compile time, but it makes interpreting
the code with the eye easier); another possibility is to define constants for
special values, like offsets and multipliers.

var
  p_cur_banana: tp_banana; (* pointer to current banana record (tr_banana) *)

...
p_cur_banana:=nil;
for i := 1 to 10 do begin
  for j := 20 to 30 do begin
    p_cur_banana := @banana[i,j];
    z := sqrt( sqr(p_cur_banana^.x) + sqr(p_cur_banana^.y) );
    p_cur_banana^.x := 1200.0+x/z*500.0;  (* real constants used here *)
    p_cur_banana^.y := 1500.0+y/z*500.0;
(*  p_cur_banana^.x := x_ofs_banana + x/z*x_mul_banana;  -- constants defined
    p_cur_banana^.y := y_ofs_banana + y/z*y_mul_banana; *)
    end;
  end;

Or, you go one step further and get pointers for both x and y of banana[i,j].
The other array calculations (single dimension arrays) can be done analogous.
This should already be faster than the original, while being shorter (the array
element lookup is simplified into a stack pointer lookup).

If it is still too slow, maybe you use a de{*word*81} to analyse the Pascal code
and hand-optimize it, run it through an assembler, then use inline() in the
interface of a unit to make it an inline function.

CU
    Mike =8-#)

2:2452/108.348 - msie...@yftn.fido.de

Other Threads