Tuesday 14 October 2008

Delphi 2009 string type performance benchmark

This code was run on a Intel Core 2 laptop, and shows the difference in performance very well. Compiler options used: Code optimization disabled, all checks on.


procedure TForm3.Button3Click(Sender: TObject);
var
a:ansistring;
r:rawbytestring;
u:string;
w:widestring;
i:integer;
s:shortstring;
c:char; // widechar
ac:ansichar;
begin
screen.Cursor:=crHourGlass;
try
// approx. 222 million iterations per second
s:='This is a test';
for i:=0 to 1000000000 do begin
ac:=s[4];
s[4]:=s[5];
s[5]:=ac;
end;

// approx. 43 million iterations per second
a:='This is a test';
for i:=0 to 1000000000 do begin
ac:=a[4];
a[4]:=a[5];
a[5]:=ac;
end;

// approx. 40 million iterations per second
u:='This is a test';
for i:=0 to 1000000000 do begin
c:=u[4];
u[4]:=u[5];
u[5]:=c;
end;

// approx. 71 million iterations per second
w:='This is a test';
for i:=0 to 1000000000 do begin
c:=w[4];
w[4]:=w[5];
w[5]:=c;
end;

// ****************************

// approx. 40 million iterations per second
for i:=0 to 100000000 do begin
u:='This is € test';
end;

// approx. 5.5 million iterations per second
for i:=0 to 100000000 do begin
a:='This is € test';
u:=a;
end;

// approx. 5.5 million iterations per second
for i:=0 to 100000000 do begin
u:='This is € test';
a:=u;
end;

// approx. 3.7 million iterations per second
for i:=0 to 100000000 do begin
u:='This is € test';
w:=u;
end;

// ****************************

// approx. 3.7 million iterations per second
s:='';
for i:=0 to 100000000 do begin
s:=copy(s+' ',1,50);
end;

// approx. 4.2 million iterations per second
a:='';
for i:=0 to 100000000 do begin
a:=copy(a+' ',1,50);
end;

// approx. 2.5 million iterations per second
u:='';
for i:=0 to 100000000 do begin
u:=copy(u+' ',1,50);
end;

// approx. 1.6 million iterations per second
w:='';
for i:=0 to 10000000 do begin
w:=copy(w+' ',1,50);
end;

// ****************************

// approx. 25 million iterations per second
r:='';
for i:=0 to 100000000 do begin
r:=r+' ';
end;

// approx. 25 million iterations per second
a:='';
for i:=0 to 100000000 do begin
a:=a+' ';
end;

// approx. 25 million iterations per second
u:='';
for i:=0 to 100000000 do begin
u:=u+' ';
end;

// approx. 0.0055 million iterations per second
w:='';
for i:=0 to 100000 do begin
w:=w+' ';
end;
finally
screen.Cursor:=crDefault;
end;
end;


Conclusion:
* Avoid widestring and shortstring.
* UnicodeString is a huge improvement to WideString.

7 comments:

Olaf Monien said...

You might test TStringBuilder as well ...

Olaf Monien said...

Actually, I just did a quick test:
http://www.monien.net/blog/index.php/2008/10/delphi-2009-tstringbuilder/

LachlanG said...

I don't understand how you've drawn your conclusions from those results.

In the two cases where you tested it shortstring came first and third (almost second).

WideString got a second, one last, a first, and another last. It was also faster than UnicodeString in two of the four cases.

How am I misreading your results?

Lars D said...

Widestring is 5000 times slower than the other string types in one of the benchmarks, and that's enough for me to avoid that type, where possible.

With regard to shortstring: It has limitations (max length) and doesn't provide any benefits for normal string handling. I don't consider the first benchmark to be important enough, because just a few extra instructions inside the loop would make the advantage much smaller.

However, both string types still make sense in some cases. Widestring is necessary for COM compatibility, and shortstring is good when you need to control the binary layout of your data.

LachlanG said...

Which benchmark are you referring to that is 5000 times slower?

According to your code comments the biggest difference is the second benchmark with 2.5 seconds for unicodestring and 27 seconds for widestring which is only about 10 times slower.

In the third benchmark you state that WideString is fastest by a similar margin completing in 6 seconds vs 24, 27 and 39 seconds for the other string types.

Actually looking at the code comments for that third benchmark again it looks like the 6 seconds is a typo, it doesn't correlate with the number of iterations per second written next to it.

Lars D said...

Do not compare the total time spent, since the number of iteration differs from each block to the next. In order to avoid further confusion, I have removed the time measurements from the post.

The two relevant benchmarks are these:

// 25 million iterations per second:
u:=u+' ';

// 0.0055 million iterations per second:
w:=w+' ';

As you can see, the unicodestring is 25/0.0055=4545 times faster than widestring.

LachlanG said...

OK thanks, now I see my mistake. You were right I didn't look closely enough at the loop limits instead I just assumed that you repeating the exact same test for each string type.