[fpc-devel] Patch to speed up Uppercase/Lowercase functions

Michael Van Canneyt michael at freepascal.org
Sat Jun 11 13:33:57 CEST 2005



On Sat, 11 Jun 2005, Daniƫl Mantione wrote:

> 
> 
> Op Fri, 10 Jun 2005, schreef Florian Klaempfl:
> 
> > Joost van der Sluis wrote:
> >
> > > Hi all,
> > >
> > > I don't know if rtl-optimilisation patches have a large priority,
> >
> > It depends if someone does it ;)
> >
> > > but
> > > nevertheless this patch improves the speed of the sysutils.uppercase and
> > > lowercase functions.
> >
> > What about creating a table which does direct mapping? It's a lot faster.
> 
> It would be faster, but it would require two 256-byte tables, which'll
> help make people complain about code size even more. I would do it in an
> inner loop, but upper/lower case conversions are seldomly called in an
> inner loop. It also does some cache trashing, which is an often ignored
> speed issue in programming.

Well. Discussion is nice, but what does the real world show ?

To compare, I made 6 versions of Lowercase:
1 - Sysutils
2 - Sysutils with Joost's improvement.
3 - Sysutils with Joost's improvement, but forward loop.
4 - Using PChar.
5 - Using PChar with lookup table and if check
5 - Using Pchar with lookup table and no check.

Result on an AMD 64 3000:
Lowercase time to execute: 00:00:01.563
Lowercase2 Time to execute: 00:00:01.363
Lowercase3 Time to execute: 00:00:01.394
Lowercase4 Time to execute: 00:00:00.999
Lowercase5 Time to execute: 00:00:01.021
Lowercase6 Time to execute: 00:00:00.948

So, judge for yourself. I think this is worth the 256 byte lookup table.

Michael.

-----------------------------------------------------------------------
{$mode objfpc}
{$h+}
program testsp;


uses sysutils;

Function Lowercase2(Const S : String) : String;

Var
  i : Integer;

begin
  result := S;
  for i := Length(S) downto 1 do
    if (result[i] in ['A'..'Z']) then result[i] := char(byte(result[i]) + 32);
end;

Function Lowercase3(Const S : String) : String;

Var
  i : Integer;

begin
  result := S;
  for i := 1 to Length(S) do
    if (result[i] in ['A'..'Z']) then result[i] := char(byte(result[i]) + 32);
end;

Function Lowercase4(Const S : String) : String;

Var
  i : Integer;
  P : PChar;
  
begin
  result := S;
  UniqueString(Result);
  P:=Pchar(Result);
  for i := 1 to Length(Result) do
    begin
    if (P^ in ['A'..'Z']) then P^ := char(byte(p^) + 32);
    Inc(P);
    end;
end;

Var
  ConvertTable : Array[0..255] of char;

Function Lowercase5(Const S : String) : String;

Var
  i : Integer;
  P : PChar;
  
begin
  result := S;
  UniqueString(Result);
  P:=Pchar(Result);
  for i := 1 to Length(Result) do
    begin
    if (P^ in ['A'..'Z']) then P^ := ConvertTable[byte(p^)];
    Inc(P);
    end;
end;

Function Lowercase6(Const S : String) : String;

Var
  i : Integer;
  P : PChar;
  
begin
  result := S;
  UniqueString(Result); // Needed or S will be modified.
  P:=Pchar(Result);
  for i := 1 to Length(Result) do
    begin
    P^ := ConvertTable[byte(p^)];
    Inc(P);
    end;
end;

Const
  Count = 50000;
  
Var
  S,T : String;
  I : integer;
  Sa,Se : TDateTime;
  
begin
  For I:=0 to 256 do
    ConvertTable[i]:=LowerCase(Char(i));
  S:='Some Test string which I wouLD LiKE to Test With This RAther SpeedY routine';
  For I:=1 to 5 do
    S:=S+S;
  Sa:=Now;
  For I:=0 to Count do
    T:=LowerCase(S);
  Se:=Now;
  Writeln('Lowercase time to execute: ',FormatDateTime('hh:nn:ss.zzz',Se-SA));  
  Sa:=Now;
  For I:=0 to Count do
    T:=LowerCase2(S);
  Se:=Now;
  Writeln('Lowercase2 Time to execute: ',FormatDateTime('hh:nn:ss.zzz',Se-SA));  
  Sa:=Now;
  For I:=0 to Count do
    T:=LowerCase3(S);
  Se:=Now;
  Writeln('Lowercase3 Time to execute: ',FormatDateTime('hh:nn:ss.zzz',Se-SA));  
  Sa:=Now;
  For I:=0 to Count do
    T:=LowerCase4(S);
  Se:=Now;
  Writeln('Lowercase4 Time to execute: ',FormatDateTime('hh:nn:ss.zzz',Se-SA));  
  Sa:=Now;
  For I:=0 to Count do
    T:=LowerCase5(S);
  Se:=Now;
  Writeln('Lowercase5 Time to execute: ',FormatDateTime('hh:nn:ss.zzz',Se-SA));  
  Sa:=Now;
  For I:=0 to Count do
    T:=LowerCase6(S);
  Se:=Now;
  Writeln('Lowercase6 Time to execute: ',FormatDateTime('hh:nn:ss.zzz',Se-SA));  
end.


More information about the fpc-devel mailing list