Solved

Interfaces and performance

Posted on 2004-04-22
17
318 Views
Last Modified: 2010-04-05
I wonder if there is a performance penalty using interfaces instead of an abstract base class. I don't pass them around as parameters very much, just assign them in the beginning and then call procedures / functions.

TIA
0
Comment
Question by:__alex
  • 7
  • 6
  • 3
  • +1
17 Comments
 
LVL 11

Expert Comment

by:calinutz
ID: 10886350
I did not understand the question...
0
 
LVL 2

Author Comment

by:__alex
ID: 10886459
IFoo = interface
  procedure DoFoo;
end;

TMyFoo = class(TInterfacedObject, IFoo)
public
  procedure DoFoo; virtual;
end;

vs.

TFoo = class
public
  procedure DoFoo; virtual; abstract;
end;

TMyFoo = class(TFoo)
public
  procedure DoFoo; override;
end;

Which one is faster?
0
 
LVL 12

Accepted Solution

by:
Lee_Nover earned 125 total points
ID: 10886961
speed penalty is with referencing the interfaces because of ref. counting .. that counting is the performance hit
there might be something else I'm not aware of
0
 
LVL 3

Expert Comment

by:MikProg
ID: 10887247
Lee_Nover wrong. Delphi Interface definition is different thing than COM interfaces. Althought Delphi uses Interface definition for COM classes realization it is big difference among them. Delphi interfaces is a syntax tool to create multi inheritance (same to additional VTable). The havy things like ref. counting is introduced to you interfaced objects if  you make ineritance from base interfaces like IUnknown (it is intoduces functionality needed to COM realization). You can make simple experiment by creating multiple (count is depends on you machine speed) interfaced objects with and without IUnkniwn as ancestor.
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10887549
MikProg: care to explain on an example ?
0
 
LVL 3

Expert Comment

by:MikProg
ID: 10888115
Lee_Nover: Oh! Power of stereotypes! I'm understend where I put  you in confusion. My ordinary method to decalare interfaces

1.
    IO = Interface
    ...
    end;

When I intend no realize in descendants of ref. counting mechanizm (i.e. implementation of _AddRef, _Release, _QueryInterface have empty bodyes). I use such declaration when need in multi inheriteance only

2.    
    IO = Interface (IUnknown)
    ...
    end;

With full realization ref. counting. This declaration notifyes my that I intend to do.

I use this convention so long and forget that It is my own convension not more! Sorry me once more!

0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10888233
1 and 2 are same .. it's like with objects if you declare "TFoo = class" or "TFoo = class(TObject)"
IUnknown is declared as "IUnknown = IInterface"

ofcourse I might be wrong and delphi does somekind of internal checking for IUnknown .. but I doubt it
0
 
LVL 3

Expert Comment

by:MikProg
ID: 10888727
Lee_Nover> Yes! same! But image of "(IUknown)" is notification for ME! not to compiler!
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10892158
>>speed penalty is with referencing the interfaces because of ref. counting .. that counting is the performance hit
wheter you implement actual ref. counting or not delphi still calls _addref and _remove .. also if there's nothing in the functions they still do get compiled coz they're called
so ... interface performance is slower compared to a noninterfaced class - but you could say it's unnoticeable

any other Expert care to comment ? :)
0
 
LVL 3

Expert Comment

by:MikProg
ID: 10896489
Here it is code. Althought we can see blue dots against
begin
  // It is really empty function body
end;
NO CODE GENERATED. NO CODE CALLED AT OBJECT CREATION. You can trace code in CPU debug window and take you own look. I think you put together interface as syntax element and interface as interaction protocol. At the and of all GUID and QueryInterface are meant only in OLE environment. About my internal conventions at interface decalrations see above.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls;

type
  IHavyInterface = interface (IUnknown)
  end;

  TClassWithHavyInterface = class (TObject, IHavyInterface)
    FRefCount: integer;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    property RefCount: Integer read FRefCount;
  end;


  ILightInterface = interface
    procedure SomeEspecialProc;
  end;

  TClassWithLightInterface = class (TObject, ILightInterface)
    FRefCount: integer;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    property RefCount: Integer read FRefCount;
    procedure SomeEspecialProc;
  end;

  TClassToDescribe = class(TList, ILightInterface)
    FRefCount: integer;
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
    property RefCount: Integer read FRefCount;
    procedure SomeEspecialProc;
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    a: TClassWithHavyInterface;
    b: TClassWithLightInterface;
    c: TClassToDescribe;
  end;

var
  Form1: TForm1;

implementation
{$R *.dfm}

{ TClassWithLightInterface }

function TClassWithLightInterface.QueryInterface(const IID: TGUID;
  out Obj): HResult;
begin
  // It is really empty function body
end;

procedure TClassWithLightInterface.SomeEspecialProc;
begin
  Application.MessageBox('Here we are in TClassWithLightInterface','Get it',MB_OK);
end;

function TClassWithLightInterface._AddRef: Integer;
begin
  // It is really empty function body
end;

function TClassWithLightInterface._Release: Integer;
begin
  // It is really empty function body
end;

{ TClassWithHavyInterface }

function TClassWithHavyInterface._AddRef: Integer;
begin
  Inc(FRefCount);
  Result:=FRefCount;
end;

function TClassWithHavyInterface._Release: Integer;
begin
  Dec(FRefCount);
  Result:=FRefCount;
  If FRefCount=0 then
    Destroy;
end;

function TClassWithHavyInterface.QueryInterface(const IID: TGUID; out Obj): HResult;
begin
// Here it is out of view
end;

{ TClassToDescribe }

function TClassToDescribe._AddRef: Integer;
begin
  // It is really empty function body
end;

function TClassToDescribe._Release: Integer;
begin
  // It is really empty function body
end;

function TClassToDescribe.QueryInterface(const IID: TGUID;
  out Obj): HResult;
begin
 // It is really empty function body
end;

procedure TClassToDescribe.SomeEspecialProc;
begin
  Application.MessageBox('Here we are in TClassToDescribe','Get it',MB_OK);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  z: ILightInterface;
begin
  a:=TClassWithHavyInterface.Create;
  b:=TClassWithLightInterface.Create;
  c:=TClassToDescribe.Create;
  z:=b;
  z.SomeEspecialProc;
  z:=c;
  z.SomeEspecialProc;
end;

end.
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10896809
sorry but I don't see your point
0
 
LVL 3

Expert Comment

by:MikProg
ID: 10897639
__alex>> ... performance penalty ...
Lee_Nover>> ... because of ref. counting  ...
MikProg>> ... Delphi Interface definition is different thing than COM interfaces ...  
havy things like ref. counting is introduced to you interfaced objects if  you make ineritance from base interfaces like
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
IUnknown
^^^^^^ From this point we in confusion in terminology.
I state that usage interfaces in decalration of class does not introduces any additional functionality (no additional compiled instructions), but allows to make multiple definitions. Interface methods called _AddRef, _Release, QueryInterface is part of COM objects interaction protocol. In ordinary way  interaction protocol we call "interface".
Additional confusion invoked: Delphi IInterface and IUnknown is the same.
First.
I think logic is simple. We (delphi authors) want to introduce in Delphi COM support
  IInterface = interface; // like TObject = class It is in Delphi style

  IUnknown = IInterface; // This COM protocol interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; // This COM protocol
    function _AddRef: Integer; stdcall; // This COM protocol
    function _Release: Integer; stdcall; // This COM protocol
end;
but IInterface realisation is also possible in COM environment, then
  IInterface = interface
    ['{00000000-0000-0000-C000-000000000046}']
    function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
    function _AddRef: Integer; stdcall;
    function _Release: Integer; stdcall;
  end;

  IUnknown = IInterface;
This decalaration requires that we introduce realization of QueryInterface, _AddRef, _Release in class that uses descendants of (IInterface i.e. any interface). But stop here. These methods needed for COM protocol but not for us It is needed for COM ref.count our objects. If we want to use only anything like
  z:=b;
  z.SomeEspecialProc;
  z:=c;
  z.SomeEspecialProc;
i.e. need to call methods decalred in our own classes with different ancestors we can make them interfaced and never again write like this
   if b is TClassToDescribe then
     TClassToDescribe(b).SomeEspecialProc
   else if b is TClassWithLightInterface then
     TClassWithLightInterface(b).SomeEspecialProc;
      ....
but like
   ILightInterface(b).SomeEspecialProc;
How about this
   procedure WorkWithInterface(Super: ILightInterface)
      Super.SomeEspecialProc;
Nobody can't make us to implement things we not need (in this case it is COM conventions).
Second
There is one underwater rock that need to now. When you :
assign interfaced objects to interfaced type variable,
   z:=b;
pass them as interfaced type parameters
   WorkWithInterface(Super: ILightInterface)
the Delphi runtime some sort of runtime code (porcs @IntfCopy or @IntfAddRef) is called BUT they are do nothing except call to empty (in owr case) realizations of _AddRef, _Release. These @IntfCopy or @IntfAddRef can by substituted with dummyes but it is another story.

Actually using math approach in common case Delphi interfaces does not affect perfomance. Althought using interfaces in manner of "Quick start guide" can (but not always) hit perfomance.

Oufff! I need a cup of coffee! :)
0
 
LVL 2

Author Comment

by:__alex
ID: 10897993
As said above: I don' assign interfaces (except at the start of my app), hence no reference counting.

myInterface.MyProcedure; ->
        mov eax, edx
        mov edx, [eax]
        call dword ptr [edx + $OFFSET_OF_ MYPROCEDURE]
-> Performance like a virtual procedure.
0
 
LVL 2

Author Comment

by:__alex
ID: 10898013
BTW

procedure Foo(const myIfc: IMyInterface);
begin
  ...
end;

No reference counting either because of the const declaration of the argument.
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10898050
mikprog: mhm ... but still calling an 'empty' method is a call and a waste of cpu cycles
and this is always the case with assigning interfaces ... and that's what I mentioned in the first place


__alex: yep .. and tnx
0
 
LVL 3

Expert Comment

by:MikProg
ID: 10898701
Lee_Nover>>When I become programer I need to be balanced between speed and amount of memory (Such a hard work write math modelling programs for 2Mhz processor with 4K of memory). Today I need be balanced between production cost and "cost of owning". Some bad things I now but still use :( becose Delphi have no proper implementation of some things (like C++ multi inheriteance).
0
 
LVL 12

Expert Comment

by:Lee_Nover
ID: 10898739
I know .. I use interfaces a lot myself
I just answered to the question :)
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
This video discusses moving either the default database or any database to a new volume.

706 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now