Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2004-12

TList slowness in classes

25 messages · 9 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Ales Katona

I've read a complaint about TList being slow so I decided to give it a test. Quite frankly the test showed this is truth, but I couldn't find out why. I found out that if I copy the TList from classes "as-is" into my unit and use this
copy, it is about 3x faster in certain conditions. I have no idea why this is so but
I think there's something wrong...

I posted my test at http://members.chello.sk/ales/testlist.zip Just download, unzip and compile:
you'll get swap time and access time for the original TList uncomment {$DEFINE USEMYLIST} to get the times for my copy of TList

The copy there is unchanged.

Ales Katona

Reply by email

Michalis Kamburelis
to Ales Katona

Hi,

I tested your code and found that indeed version in ucopylist is slightly faster (by about 9.5 / 7 =~ 1.357). Two things:

1. Speedup is only 1.357x, not 3x, like you said. Are you sure that you're getting 3x speedup ? On what OS and with what FPC version are you testing this ? I was doing tests with Linux/i386 with FPC 1.9.4 and 1.9.5 (from CVS 2004-12-20).

2. Still, speedup 1.357x may be significant in some cases so I investigated what's the cause:

After many tests I found that this slight speedup is caused by the fact that in ucopylist you declared string constants SListIndexError, SListCapacityError and SListCountError as normal constants while with original Classes unit these constants are taken from RTLConst unit that defines them as resourcestrings.

Using resourcestrings in RTL is a must, since this allows to translate error messages without modifying unit Classes sources.

However in this case exceptions are not raised, so resourcestrings are not actually used. But it looks that any procedure that uses some resourcestring in implementation is doomed to be slower than the similar procedure that instead uses normal string consts, *even if this procedure doesn't actually access the string at runtime*. It seems that if some procedure uses resourcestring then upon entry it does some lengthy initialization of this resourcestring, even if it will not actually make use of that resourcestring.

I'm attaching a simple demo program that shows this. When compiled like fpc -OG -O2 -Op2 demo_resourcestring_slow.pas
(to get maximum optimizations) sample output of it is Time of Foo_Normal: 16
Time of Foo_ResourceString: 106
So time difference is really noticeable. Question goes to FPC developers, maybe such cases with using resourcestrings can be speed up ?

Regards,

Michalis Ales Katona wrote: > I've read a complaint about TList being slow so I decided to give it a > test. > Quite frankly the test showed this is truth, but I couldn't find out why. > I found out that if I copy the TList from classes "as-is" into my unit > and use this > copy, it is about 3x faster in certain conditions. I have no idea why > this is so but > I think there's something wrong... > > I posted my test at http://members.chello.sk/ales/testlist.zip > Just download, unzip and compile: > you'll get swap time and access time for the original TList > uncomment {$DEFINE USEMYLIST} to get the times for my copy of TList > > The copy there is unchanged. > > Ales Katona > > _______________________________________________ > fpc-devel maillist - > http://lists.freepascal.org/mailman/listinfo/fpc-devel >

Reply by email

Peter Vreman
to Michalis Kamburelis
Show quoted text 7 lines
I'm attaching a simple demo program that shows this. When compiled like fpc -OG -O2 -Op2 demo_resourcestring_slow.pas (to get maximum optimizations) sample output of it is Time of Foo_Normal: 16 Time of Foo_ResourceString: 106 So time difference is really noticeable. Question goes to FPC developers, maybe such cases with using resourcestrings can be speed up ?

You can compile with -al and run a diff between the generated .s files.

Reply by email

Michael Van Canneyt
to Michalis Kamburelis: I tested your code and found that indeed version in ucopylist is slightly faster (by…
Michalis Kamburelis wrote 30 lines
Hi, I tested your code and found that indeed version in ucopylist is slightly faster (by about 9.5 / 7 =~ 1.357). Two things: 1. Speedup is only 1.357x, not 3x, like you said. Are you sure that you're getting 3x speedup ? On what OS and with what FPC version are you testing this ? I was doing tests with Linux/i386 with FPC 1.9.4 and 1.9.5 (from CVS 2004-12-20). 2. Still, speedup 1.357x may be significant in some cases so I investigated what's the cause: After many tests I found that this slight speedup is caused by the fact that in ucopylist you declared string constants SListIndexError, SListCapacityError and SListCountError as normal constants while with original Classes unit these constants are taken from RTLConst unit that defines them as resourcestrings. Using resourcestrings in RTL is a must, since this allows to translate error messages without modifying unit Classes sources. However in this case exceptions are not raised, so resourcestrings are not actually used. But it looks that any procedure that uses some resourcestring in implementation is doomed to be slower than the similar procedure that instead uses normal string consts, *even if this procedure doesn't actually access the string at runtime*. It seems that if some procedure uses resourcestring then upon entry it does some lengthy initialization of this resourcestring, even if it will not actually make use of that resourcestring.

This is because there is an extra (implicit) Try/Finally block.

Michael.

Reply by email

Michalis Kamburelis
to Michael Van Canneyt
Michael Van Canneyt wrote 40 lines
On Fri, 24 Dec 2004, Michalis Kamburelis wrote: >Hi, > >I tested your code and found that indeed version in ucopylist is >slightly faster (by about 9.5 / 7 =~ 1.357). Two things: > >1. Speedup is only 1.357x, not 3x, like you said. Are you sure that >you're getting 3x speedup ? On what OS and with what FPC version are you >testing this ? I was doing tests with Linux/i386 with FPC 1.9.4 and >1.9.5 (from CVS 2004-12-20). > >2. Still, speedup 1.357x may be significant in some cases so I >investigated what's the cause: > >After many tests I found that this slight speedup is caused by the fact >that in ucopylist you declared string constants SListIndexError, >SListCapacityError and SListCountError as normal constants while with >original Classes unit these constants are taken from RTLConst unit that >defines them as resourcestrings. > >Using resourcestrings in RTL is a must, since this allows to translate >error messages without modifying unit Classes sources. > >However in this case exceptions are not raised, so resourcestrings are >not actually used. But it looks that any procedure that uses some >resourcestring in implementation is doomed to be slower than the similar >procedure that instead uses normal string consts, *even if this >procedure doesn't actually access the string at runtime*. It seems that >if some procedure uses resourcestring then upon entry it does some >lengthy initialization of this resourcestring, even if it will not >actually make use of that resourcestring. This is because there is an extra (implicit) Try/Finally block. Michael.

Thank you and Peter for answers. This way I was able to see how try...finally section looks in assembler :) Anyway, I understand that the answer is "can't be speed up". OK, I can live with that.

Michalis

Reply by email

Peter Vreman
to Michalis Kamburelis
Show quoted text 5 lines
> This is because there is an extra (implicit) Try/Finally block. Thank you and Peter for answers. This way I was able to see how try...finally section looks in assembler :) Anyway, I understand that the answer is "can't be speed up". OK, I can live with that.

That is not correct. For your own code you can disable the implicit exception frame with a directive:

{$IMPLICITEXCEPTIONS OFF}

Reply by email

Michalis Kamburelis
to Peter Vreman
Peter Vreman wrote 12 lines
>>This is because there is an extra (implicit) Try/Finally block. > >Thank you and Peter for answers. This way I was able to see how >try...finally section looks in assembler :) Anyway, I understand that >the answer is "can't be speed up". OK, I can live with that. That is not correct. For your own code you can disable the implicit exception frame with a directive: {$IMPLICITEXCEPTIONS OFF}

Indeed when I put {$IMPLICITEXCEPTIONS OFF} at the beginning of demo_resourcestring_slow.pas, Foo_Normal and Foo_ResourceString work equally fast. Nice, that's a solution in cases when I know that some code will not exit with exception.

But I risk that if I ever call Foo_ResourceString(-1) that will raise exception from Foo_ResourceString, I can get memory leaks, right ? Or can I predict in certain cases that using {$IMPLICITEXCEPTIONS OFF} is safe (no memory leaks) even when procedure will raise some exceptions ? If the answer is yes, then maybe it's safe to compile parts of FPC sources in lists.inc (like TList.Get) inside {$IMPLICITEXCEPTIONS OFF} ?

Michalis

Reply by email

Ales Katona
to Michalis Kamburelis: I tested your code and found that indeed version in ucopylist is slightly faster (by…
Michalis Kamburelis wrote 101 lines
Hi, I tested your code and found that indeed version in ucopylist is slightly faster (by about 9.5 / 7 =~ 1.357). Two things: 1. Speedup is only 1.357x, not 3x, like you said. Are you sure that you're getting 3x speedup ? On what OS and with what FPC version are you testing this ? I was doing tests with Linux/i386 with FPC 1.9.4 and 1.9.5 (from CVS 2004-12-20). 2. Still, speedup 1.357x may be significant in some cases so I investigated what's the cause: After many tests I found that this slight speedup is caused by the fact that in ucopylist you declared string constants SListIndexError, SListCapacityError and SListCountError as normal constants while with original Classes unit these constants are taken from RTLConst unit that defines them as resourcestrings. Using resourcestrings in RTL is a must, since this allows to translate error messages without modifying unit Classes sources. However in this case exceptions are not raised, so resourcestrings are not actually used. But it looks that any procedure that uses some resourcestring in implementation is doomed to be slower than the similar procedure that instead uses normal string consts, *even if this procedure doesn't actually access the string at runtime*. It seems that if some procedure uses resourcestring then upon entry it does some lengthy initialization of this resourcestring, even if it will not actually make use of that resourcestring. I'm attaching a simple demo program that shows this. When compiled like fpc -OG -O2 -Op2 demo_resourcestring_slow.pas (to get maximum optimizations) sample output of it is Time of Foo_Normal: 16 Time of Foo_ResourceString: 106 So time difference is really noticeable. Question goes to FPC developers, maybe such cases with using resourcestrings can be speed up ? Regards, ------------------------------------------------------------------------ {$mode objfpc}{$H+} uses {BaseUnix, Unix needed only to implement Clock} BaseUnix, Unix, SysUtils; function Clock: Int64; var Dummy: tms; begin Clock := FpTimes(Dummy); end; const SNormal = 'blah blah blah blah blah blah blah blah blah blah'; resourcestring SResString = 'blah blah blah blah blah blah blah blah blah blah'; { Foo_Normal and Foo_ResourceString do the same thing, but Foo_Normal uses normal string constant while Foo_ResourceString uses resourcestring. } procedure Foo_Normal(i: Integer); begin if i = -1 then raise Exception.Create(SNormal); end; procedure Foo_ResourceString(i: Integer); begin if i = -1 then raise Exception.Create(SResString); end; { Note that when I call Foo_Normal and Foo_ResourceString i is always >= 0 so Exception is never actually raised. So string constants SNormal and SResString are not really used. } const TestCount = 10000000; var i: Integer; Start: Int64; begin Start := Clock; for i := 0 to TestCount do Foo_Normal(i); Writeln('Time of Foo_Normal: ', Clock - Start); Start := Clock; for i := 0 to TestCount do Foo_ResourceString(i); Writeln('Time of Foo_ResourceString: ', Clock - Start); end. ------------------------------------------------------------------------ _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

The slowness 3x I ment was not between atomics like get/put but when I tested a bigger(10000x10000) bubblesort with the copy and original. The times back then I got were about:
Original: ~28seconds
Copy: ~6seconds

This is even more than 3x.(ups ;-) ) In any case the point is in critical operations these things can be real problematic. Another interresting fact is that ListArray from java(almost same thing as our TList) was about 8 seconds with same test.

Don't get me wrong, I'm not trying to reasure myself here, it's just that I think it can be made faster nothing else.

The resourcestrings are interresting. I'd look at the code but I'm afraid that's a bit too deep RTL for me...

Ales

Reply by email

Michael Van Canneyt
to Michalis Kamburelis: Indeed when I put {$IMPLICITEXCEPTIONS OFF} at the beginning of…
Michalis Kamburelis wrote 21 lines
Peter Vreman wrote: >>>This is because there is an extra (implicit) Try/Finally block. >> >>Thank you and Peter for answers. This way I was able to see how >>try...finally section looks in assembler :) Anyway, I understand that >>the answer is "can't be speed up". OK, I can live with that. > > > That is not correct. For your own code you can disable the implicit > exception frame with a directive: > > {$IMPLICITEXCEPTIONS OFF} > Indeed when I put {$IMPLICITEXCEPTIONS OFF} at the beginning of demo_resourcestring_slow.pas, Foo_Normal and Foo_ResourceString work equally fast. Nice, that's a solution in cases when I know that some code will not exit with exception. But I risk that if I ever call Foo_ResourceString(-1) that will raise exception from Foo_ResourceString, I can get memory leaks, right ?

Yes

Or can I predict in certain cases that using {$IMPLICITEXCEPTIONS OFF} is safe (no memory leaks) even when procedure will raise some exceptions ?

In this particular case you will get memory leaks. As soon as an ansistring is used, you will have problems.

If the answer is yes, then maybe it's safe to compile parts of FPC sources in lists.inc (like TList.Get) inside {$IMPLICITEXCEPTIONS OFF} ?

Normally not.

Michael.

Reply by email

Mattias Gaertner
to Michael Van Canneyt
> If the answer is yes, then maybe it's safe to compile parts of FPC > sources in lists.inc (like TList.Get) inside {$IMPLICITEXCEPTIONS OFF} ?

Why not put it into a sub proc:

function TList.Get(Index: Integer): Pointer;
  procedure RaiseIndexError;
  begin
    Error(SListIndexError,Index);
  end;
begin
  If (Index<0) or (Index>=FCount) then
    RaiseIndexError;
  Result:=FList^[Index];
end;

?

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 21 lines
On Fri, 24 Dec 2004 10:56:24 +0100 (W. Europe Standard Time) Michael Van Canneyt wrote: > > If the answer is yes, then maybe it's safe to compile parts of FPC > > sources in lists.inc (like TList.Get) inside {$IMPLICITEXCEPTIONS OFF} ? Why not put it into a sub proc: function TList.Get(Index: Integer): Pointer; procedure RaiseIndexError; begin Error(SListIndexError,Index); end; begin If (Index<0) or (Index>=FCount) then RaiseIndexError; Result:=FList^[Index]; end;

The compiler detects that the sub can raise an exception.

Michael.

Reply by email

Vincent Snijders
to Michael Van Canneyt
Michael Van Canneyt wrote 30 lines
On Fri, 24 Dec 2004, Mattias Gaertner wrote: >On Fri, 24 Dec 2004 10:56:24 +0100 (W. Europe Standard Time) >Michael Van Canneyt wrote: > > >>>If the answer is yes, then maybe it's safe to compile parts of FPC >>>sources in lists.inc (like TList.Get) inside {$IMPLICITEXCEPTIONS OFF} ? > >Why not put it into a sub proc: > >function TList.Get(Index: Integer): Pointer; > > procedure RaiseIndexError; > begin > Error(SListIndexError,Index); > end; > >begin > If (Index<0) or (Index>=FCount) then > RaiseIndexError; > Result:=FList^[Index]; >end; > The compiler detects that the sub can raise an exception.

But in the main procedure there is no need for an implicit try..finally block, is there?

Vincent.

Reply by email

Mattias Gaertner
to Michael Van Canneyt: The compiler detects that the sub can raise an exception. Michael.
Show quoted text 27 lines
On Fri, 24 Dec 2004, Mattias Gaertner wrote: > On Fri, 24 Dec 2004 10:56:24 +0100 (W. Europe Standard Time) > Michael Van Canneyt wrote: > > > > If the answer is yes, then maybe it's safe to compile parts of FPC > > > sources in lists.inc (like TList.Get) inside {$IMPLICITEXCEPTIONS OFF} ? > > Why not put it into a sub proc: > > function TList.Get(Index: Integer): Pointer; > > procedure RaiseIndexError; > begin > Error(SListIndexError,Index); > end; > > begin > If (Index<0) or (Index>=FCount) then > RaiseIndexError; > Result:=FList^[Index]; > end; > The compiler detects that the sub can raise an exception.

And creates the implicit exception frame only in RaiseIndexError.

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 32 lines
On Fri, 24 Dec 2004 11:49:10 +0100 (W. Europe Standard Time) Michael Van Canneyt wrote: > > > On Fri, 24 Dec 2004, Mattias Gaertner wrote: > > > On Fri, 24 Dec 2004 10:56:24 +0100 (W. Europe Standard Time) > > Michael Van Canneyt wrote: > > > > > > If the answer is yes, then maybe it's safe to compile parts of FPC > > > > sources in lists.inc (like TList.Get) inside {$IMPLICITEXCEPTIONS OFF} ? > > > > Why not put it into a sub proc: > > > > function TList.Get(Index: Integer): Pointer; > > > > procedure RaiseIndexError; > > begin > > Error(SListIndexError,Index); > > end; > > > > begin > > If (Index<0) or (Index>=FCount) then > > RaiseIndexError; > > Result:=FList^[Index]; > > end; > > > > The compiler detects that the sub can raise an exception. And creates the implicit exception frame only in RaiseIndexError.

I have changed the procedure.

Michael.

Reply by email

Mattias Gaertner
to Michael Van Canneyt
Show quoted text 5 lines
On Fri, 24 Dec 2004, Mattias Gaertner wrote: [...] > And creates the implicit exception frame only in RaiseIndexError. I have changed the procedure.

Talking about TList slowness:
In the last years TList and TStringList became slower and slower. Are there any alternatives in classes.pp? A simple TList providing only the very basics, less checks, no notifications, less virtuals, reordered IFs ... ? If this TBaseList (or TSimpleList or TQuickList or THumbleList) would be the ancestor of TList, existing code could easily be improved - the user only needs to rename his TList to TBaseList. Or maybe give this base thing the correct name. I never understood, why Borland named it 'list'. AFAIK in computer science a list is a linked chain of elements. While TList is an dynamic array with some methods.

Mattias

Reply by email

Michael Van Canneyt
to Mattias Gaertner
Mattias Gaertner wrote 13 lines
On Fri, 24 Dec 2004 12:13:15 +0100 (W. Europe Standard Time) Michael Van Canneyt wrote: > On Fri, 24 Dec 2004, Mattias Gaertner wrote: >[...] > > And creates the implicit exception frame only in RaiseIndexError. > > I have changed the procedure. Talking about TList slowness: In the last years TList and TStringList became slower and slower. Are there any alternatives in classes.pp? A simple TList providing only the very basics, less checks, no notifications, less virtuals, reordered IFs ... ?

TList has almost no virtuals, so I doubt you will find anything to change there. The notifications can be optimized, Dean Zobec wanted to try this. This is as far as I'm concerned the biggest showstopper.

If you want to make an ancestor, make it TAbstractList. But to make this work, you'll need a virtual Get() method, which is more or less what you wanted to avoid in the first place.

Show quoted text 6 lines
If this TBaseList (or TSimpleList or TQuickList or THumbleList) would be the ancestor of TList, existing code could easily be improved - the user only needs to rename his TList to TBaseList. Or maybe give this base thing the correct name. I never understood, why Borland named it 'list'. AFAIK in computer science a list is a linked chain of elements. While TList is an dynamic array with some methods.

It is.

I suspect that TList is also often used in the wrong way. The basic methods (get/set) are quite small and fast. Only the growing mechanism is slow. People should set the capacity before adding anything to the list. If you don't do this, then each N calls to add() will need to do a reallocation of the whole list...

Michael.

Reply by email

Michalis Kamburelis
to Michael Van Canneyt: I have changed the procedure. Michael.

I felt that results of this discussion are so important that I created a page in FPC wiki about it:

http://www.freepascal.org/wiki/index.php/Avoiding_implicit_try_finally_section

There's an URL to mail archives of this discussion, and a small demo program that shows trick proposed by Mattias how to avoid this implicit try...finally block.

(I also created Writing_efficient_code page, that links between FPC page and Avoiding_implicit_try_finally_section page).

Michalis.

Michael Van Canneyt wrote 48 lines
On Fri, 24 Dec 2004, Mattias Gaertner wrote: >On Fri, 24 Dec 2004 11:49:10 +0100 (W. Europe Standard Time) >Michael Van Canneyt wrote: > > >> >>On Fri, 24 Dec 2004, Mattias Gaertner wrote: >> >> >>>On Fri, 24 Dec 2004 10:56:24 +0100 (W. Europe Standard Time) >>>Michael Van Canneyt wrote: >>> >>> >>>>>If the answer is yes, then maybe it's safe to compile parts of FPC >>>>>sources in lists.inc (like TList.Get) inside {$IMPLICITEXCEPTIONS OFF} ? >>> >>>Why not put it into a sub proc: >>> >>>function TList.Get(Index: Integer): Pointer; >>> >>> procedure RaiseIndexError; >>> begin >>> Error(SListIndexError,Index); >>> end; >>> >>>begin >>> If (Index<0) or (Index>=FCount) then >>> RaiseIndexError; >>> Result:=FList^[Index]; >>>end; >>> >> >>The compiler detects that the sub can raise an exception. > >And creates the implicit exception frame only in RaiseIndexError. I have changed the procedure. Michael. _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

Reply by email

Yakov Sudeikin
Talking about TList slowness: In the last years TList and TStringList became slower and slower. Are there any alternatives in classes.pp? A simple TList providing only the very basics, less checks, no notifications, less virtuals, reordered IFs ... ?

I think dynamic arrays are just what you are looking for.

var
     ii: array of integer;
     ss: array of string;

yakov

Reply by email

Vincent Snijders
to Michalis Kamburelis: I felt that results of this discussion are so important that I created a page in FPC wiki…
Michalis Kamburelis wrote 15 lines
I felt that results of this discussion are so important that I created a page in FPC wiki about it: http://www.freepascal.org/wiki/index.php/Avoiding_implicit_try_finally_section There's an URL to mail archives of this discussion, and a small demo program that shows trick proposed by Mattias how to avoid this implicit try...finally block. (I also created Writing_efficient_code page, that links between FPC page and Avoiding_implicit_try_finally_section page). Michalis.

Did you try this with today compiler?

I think Peter Vreman turned of implicit try finally for resource strings.

Vincent.

Reply by email

Michalis Kamburelis
to Vincent Snijders
Vincent Snijders wrote 24 lines
Michalis Kamburelis wrote: > I felt that results of this discussion are so important that I created > a page in FPC wiki about it: > > http://www.freepascal.org/wiki/index.php/Avoiding_implicit_try_finally_section > > > There's an URL to mail archives of this discussion, and a small demo > program that shows trick proposed by Mattias how to avoid this > implicit try...finally block. > > (I also created Writing_efficient_code page, that links between FPC > page and Avoiding_implicit_try_finally_section page). > > Michalis. > Did you try this with today compiler? I think Peter Vreman turned of implicit try finally for resource strings. Vincent.

I just updated from CVS and rebuild FPC, and indeed, timings of my test program are now
Time of Foo_ResourceString: 18
Time of Foo_ResourceString_Faster: 16
So it's fixed in compiler. Great!

Are there any other cases where this issue may be significant ? If no, I'll mark this wiki page clearly as "only for FPC earlier than 2004-12-28" (to-be-removed when 2.0 comes in), else I will update it.

(Note: we can continue this talk on wiki page
http://www.freepascal.org/wiki/index.php/Talk:Avoiding_implicit_try_finally_section already started by Vincent with that question)

Thanks!

Michalis

Reply by email

Ales Katona
to Vincent Snijders: Did you try this with today compiler? I think Peter Vreman turned of implicit try finally…
Vincent Snijders wrote 28 lines
Michalis Kamburelis wrote: > I felt that results of this discussion are so important that I > created a page in FPC wiki about it: > > http://www.freepascal.org/wiki/index.php/Avoiding_implicit_try_finally_section > > > There's an URL to mail archives of this discussion, and a small demo > program that shows trick proposed by Mattias how to avoid this > implicit try...finally block. > > (I also created Writing_efficient_code page, that links between FPC > page and Avoiding_implicit_try_finally_section page). > > Michalis. > Did you try this with today compiler? I think Peter Vreman turned of implicit try finally for resource strings. Vincent. _______________________________________________ fpc-devel maillist - http://lists.freepascal.org/mailman/listinfo/fpc-devel

I can confirm that since the new CVS version TList is much faster than before. Also it seems arrays got faster but I'm unsure as I deleted my old benchmarks.

Reply by email

Dean Zobec
to Michael Van Canneyt: TList has almost no virtuals, so I doubt you will find anything to change there. The…
Show quoted text 9 lines
> Talking about TList slowness: > In the last years TList and TStringList became slower and slower. > Are there any alternatives in classes.pp? A simple TList providing only > the very basics, less checks, no notifications, less virtuals, reordered > IFs ... ? TList has almost no virtuals, so I doubt you will find anything to change there. The notifications can be optimized, Dean Zobec wanted to try this. This is as far as I'm concerned the biggest showstopper.

unnecessary things have been added to TList to
accomodate descendants (very bad OOP design decision IMHO), like the notification to be used in the only descendant, TObjectList, that transformed the Clear operation from an O(1) to an O(n) operation. Here is what Delphi designer Danny Thorpe says about TList in his book Delphi component design (1997):
"You'll almost always wind up using a TList in a component, but you'll never create descendants of TList.  TList is a worker drone, not a promiscuous ancestor class."
Unfortunately the programmers of Delphi 5 seem not to have read his book :-)

another explanation from Danny:
"If you want to create a list of a particular kind of item and that list is used only in the private or protected sections of your component implementation, then just use a plain TList and typecast the list's raw pointers into the type you put into the list to begin with.

If the list is exposed in the public interface of your component, typecasting is not an option.  You cannot require a component user to typecast a list item appropriately in order to access it.  You should create a simple wrapper class (derived from TObject, not TList) that exposes only the property and function equivalents of TList that you need and whose function and whose function return types and method parameter types match the type of data that the list contains. The wrapper class then contains a TList instance internally and uses that for actual storage."

So TObjectList should have been designed as a wrapper around TList, with no need to add the notification mechanisms in TList. I've began writing a tutorial for fpcunit and have chosen this refactoring of TList and TObjectList as a subject of unit testing for my tutorial. Hope to finish it in the next two weeks.

Show quoted text 5 lines
> Are there > any alternatives in classes.pp? A simple TList providing only the very > basics, less checks, no notifications, less virtuals, reordered IFs ... ? > If this TBaseList (or TSimpleList or TQuickList or THumbleList) would be > the ancestor of TList,

see above, composition  is a better solution then inheritance in this case IMHO
Ciao, Dean

Reply by email

Vincent Snijders
to Michalis Kamburelis: I just updated from CVS and rebuild FPC, and indeed, timings of my test program are now…
Michalis Kamburelis wrote 10 lines
Are there any other cases where this issue may be significant ? If no, I'll mark this wiki page clearly as "only for FPC earlier than 2004-12-28" (to-be-removed when 2.0 comes in), else I will update it. (Note: we can continue this talk on wiki page http://www.freepascal.org/wiki/index.php/Talk:Avoiding_implicit_try_finally_section already started by Vincent with that question) Thanks!

I haven't tested it, but I have this hunch.
Ansistrings (not constant) also require implicit try finally. If you use ansi strings only in a seldom used if-branch in a procedure, you could extract the procedure too, just like you did for the resource string.

for example:
If (i>0) then
'do something but not with ansistrings
else

   writeln('Invalid value: '+IntToStr(i));

Regards,
Vincent.

Reply by email

Michalis Kamburelis
to Vincent Snijders
Vincent Snijders wrote 29 lines
Michalis Kamburelis wrote: > Are there any other cases where this issue may be significant ? If no, > I'll mark this wiki page clearly as "only for FPC earlier than > 2004-12-28" (to-be-removed when 2.0 comes in), else I will update it. > > (Note: we can continue this talk on wiki page > http://www.freepascal.org/wiki/index.php/Talk:Avoiding_implicit_try_finally_section > > already started by Vincent with that question) > > Thanks! I haven't tested it, but I have this hunch. Ansistrings (not constant) also require implicit try finally. If you use ansi strings only in a seldom used if-branch in a procedure, you could extract the procedure too, just like you did for the resource string. for example: If (i>0) then 'do something but not with ansistrings else writeln('Invalid value: '+IntToStr(i)); Regards, Vincent.

I suspected that every type that needs to be initialized/finalized creates such try...finally block, but didn't have time to check. But I checked it now. OK, page in wiki is changed, and demo program there is changed.

Michalis

Reply by email

Florian Klaempfl
to Michalis Kamburelis
Michalis Kamburelis wrote
I suspected that every type that needs to be initialized/finalized creates such try...finally block,

Yes, it does.

but didn't have time to check. But I checked it now. OK, page in wiki is changed, and demo program there is changed.

Reply by email