Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: Call from function is slow


This question is answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 3 - Last Post: Jan 3, 2017 12:39 PM Last Post By: Hafedh TRIMECHE
Hafedh TRIMECHE

Posts: 107
Registered: 12/29/06
Call from function is slow  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 29, 2016 2:04 PM
The first function took 570 ms to be executed (1000000 iterations)

  TDataMapItem=
  record
    Name   : RawByteString;
    Parent : RawByteString;
    Field  : RttiData;
    Index  : Integer;
    Level  : Integer;
    Size   : Integer;
    Offset : Integer;
  end;
  TDataMapItems=array[1..MaxDataMapItems] of TDataMapItem;
  TDataMap =
  record
  private
    FItems  : TDataMapItems;
    FParent : RawByteString;
    FCount  : Integer;
    function GetItems(Index:Integer):TDataMapItem;
  public
    procedure Add(Item:TDataMapItem;FieldName:RawByteString);
    property  Items[Index:Integer]:TDataMapItem read GetItems;default;
    property  Count:Integer read FCount;
    function  DataLength(const Data):Integer;
  end;


function TDataMap.DataLength(const Data):Integer;
var
  P      : Pointer;
  iField : Integer;
procedure Process(Item:TDataMapItem);
var
  DataLen : Integer;
begin
  if IsDynamic(Item.Field) then
  begin
    if IsBlob(Item.Field) then DataLen := Length(TBytes(P^)) else
    begin
      if IsWide(Item.Field) then DataLen := Length(UnicodeString(P^))*SizeOf(Char)
                            else DataLen := Length(RawByteString(P^));
    end;
    Inc(Result,SizeOf(Integer)+DataLen);
  end
  else Inc(Result,Item.Size);
  Inc(PByte(P),Item.Size);
end;
begin
  Result := 0;
  if FCount=0 then Exit;
  P := @Data;
  for iField:=1 to FCount do Process(FItems[iField]);
end;


But switching to this one took only 47 ms
function TDataMap.DataLength(const Data):Integer;
var
  P       : Pointer;
  iField  : Integer;
  DataLen : Integer;
begin
  Result := 0;
  if FCount=0 then Exit;
  P := @Data;
  for iField:=1 to FCount do
  begin
    with FItems[iField] do
    begin
      if IsDynamic(Field) then
      begin
        if IsBlob(Field) then DataLen := Length(TBytes(P^)) else
        begin
          if IsWide(Field) then DataLen := Length(UnicodeString(P^))*SizeOf(Char)
                           else DataLen := Length(RawByteString(P^));
        end;
        Inc(Result,SizeOf(Integer)+DataLen);
      end
      else Inc(Result,Size);
      Inc(PByte(P),Size);
    end;
  end;
end;


Is there a way to audit the entire project inspecting functions causing a such performance problem ?

Thanks.

Edited by: Hafedh TRIMECHE on Dec 29, 2016 2:50 PM

Edited by: Hafedh TRIMECHE on Dec 29, 2016 8:34 PM

Edited by: Hafedh TRIMECHE on Dec 29, 2016 8:34 PM
Hafedh TRIMECHE

Posts: 107
Registered: 12/29/06
Re: Call from function is slow  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Dec 29, 2016 11:58 PM   in response to: Hafedh TRIMECHE in response to: Hafedh TRIMECHE
Hafedh TRIMECHE wrote:
The first function took 570 ms to be executed (1000000 iterations)

  TDataMapItem=
  record
    Name   : RawByteString;
    Parent : RawByteString;
    Field  : RttiData;
    Index  : Integer;
    Level  : Integer;
    Size   : Integer;
    Offset : Integer;
  end;
  TDataMapItems=array[1..MaxDataMapItems] of TDataMapItem;
  TDataMap =
  record
  private
    FItems  : TDataMapItems;
    FParent : RawByteString;
    FCount  : Integer;
    function GetItems(Index:Integer):TDataMapItem;
  public
    procedure Add(Item:TDataMapItem;FieldName:RawByteString);
    property  Items[Index:Integer]:TDataMapItem read GetItems;default;
    property  Count:Integer read FCount;
    function  DataLength(const Data):Integer;
  end;


function TDataMap.DataLength(const Data):Integer;
var
  P      : Pointer;
  iField : Integer;
procedure Process(Item:TDataMapItem);
var
  DataLen : Integer;
begin
  if IsDynamic(Item.Field) then
  begin
    if IsBlob(Item.Field) then DataLen := Length(TBytes(P^)) else
    begin
      if IsWide(Item.Field) then DataLen := Length(UnicodeString(P^))*SizeOf(Char)
                            else DataLen := Length(RawByteString(P^));
    end;
    Inc(Result,SizeOf(Integer)+DataLen);
  end
  else Inc(Result,Item.Size);
  Inc(PByte(P),Item.Size);
end;
begin
  Result := 0;
  if FCount=0 then Exit;
  P := @Data;
  for iField:=1 to FCount do Process(FItems[iField]);
end;


But switching to this one took only 47 ms
function TDataMap.DataLength(const Data):Integer;
var
  P       : Pointer;
  iField  : Integer;
  DataLen : Integer;
begin
  Result := 0;
  if FCount=0 then Exit;
  P := @Data;
  for iField:=1 to FCount do
  begin
    with FItems[iField] do
    begin
      if IsDynamic(Field) then
      begin
        if IsBlob(Field) then DataLen := Length(TBytes(P^)) else
        begin
          if IsWide(Field) then DataLen := Length(UnicodeString(P^))*SizeOf(Char)
                           else DataLen := Length(RawByteString(P^));
        end;
        Inc(Result,SizeOf(Integer)+DataLen);
      end
      else Inc(Result,Size);
      Inc(PByte(P),Size);
    end;
  end;
end;


Is there a way to audit the entire project inspecting functions causing a such performance problem ?

Thanks.

Edited by: Hafedh TRIMECHE on Dec 29, 2016 2:50 PM

Edited by: Hafedh TRIMECHE on Dec 29, 2016 8:34 PM

Edited by: Hafedh TRIMECHE on Dec 29, 2016 8:34 PM

The problem is caused by setting the Items property as default !!!
property  Items[Index:Integer]:TDataMapItem read GetItems;default;

How this functionality can impact performance in this manner ?

Regards.
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Call from function is slow [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 3, 2017 12:09 PM   in response to: Hafedh TRIMECHE in response to: Hafedh TRIMECHE
Hafedh wrote:

The first function took 570 ms to be executed (1000000 iterations)

But switching to this one took only 47 ms

The first version is calling an (inner) procedure on each loop iterator.
There is some small overhead in performing such a call - setting up parameters
and the call stack, and then cleaning up on exit. The second version is
not doing that procedure call, so it is not invoking that extra overhead.

You should also consider passing the TDataMapItem to the procedure by 'var'
or 'const' reference.

Is there a way to audit the entire project inspecting functions
causing a such performance problem ?

Use a profiler, such as AQTime, to see where your code is actually spending
its time.

--
Remy Lebeau (TeamB)
Hafedh TRIMECHE

Posts: 107
Registered: 12/29/06
Re: Call from function is slow [Edit]  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jan 3, 2017 12:39 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Remy Lebeau (TeamB) wrote:
Hafedh wrote:

The first function took 570 ms to be executed (1000000 iterations)

But switching to this one took only 47 ms

The first version is calling an (inner) procedure on each loop iterator.
There is some small overhead in performing such a call - setting up parameters
and the call stack, and then cleaning up on exit. The second version is
not doing that procedure call, so it is not invoking that extra overhead.

You should also consider passing the TDataMapItem to the procedure by 'var'
or 'const' reference.

Is there a way to audit the entire project inspecting functions
causing a such performance problem ?

Use a profiler, such as AQTime, to see where your code is actually spending
its time.

--
Remy Lebeau (TeamB)

Thank you Remy.

I did not think it could impact performance in this way.
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02