hik*_*ari 25 delphi 64-bit delphi-xe2
我正在移植一些32到64位delphi的应用程序,它们进行了大量的文本处理,并注意到处理速度的极端变化.例如,使用一些程序进行了一些测试,这比64位的时间已经超过200%,而编译为32(2000 + ms与~900相比)
这是正常的吗?
function IsStrANumber(const S: AnsiString): Boolean;
var P: PAnsiChar;
begin
Result := False;
P := PAnsiChar(S);
while P^ <> #0 do begin
if not (P^ in ['0'..'9']) then Exit;
Inc(P);
end;
Result := True;
end;
procedure TForm11.Button1Click(Sender: TObject);
Const x = '1234567890';
Var a,y,z: Integer;
begin
z := GetTickCount;
for a := 1 to 99999999 do begin
if IsStrANumber(x) then y := 0;//StrToInt(x);
end;
Caption := IntToStr(GetTickCount-z);
end;
Run Code Online (Sandbox Code Playgroud)
Rud*_*uis 34
目前还没有解决方案,因为它是由64位的大多数字符串例程的代码用已PUREPASCAL定义的IOW 编译的事实引起的,它是普通的Delphi,没有汇编程序,而许多重要的代码32位的字符串例程由FastCode项目和汇编程序完成.
目前,64位中没有FastCode等价物,我认为开发人员团队无论如何都会尝试消除汇编程序,特别是因为他们正在转向更多平台.
这意味着生成的代码的优化变得越来越重要.我希望宣布转移到LLVM后端将大大加快代码的大部分代码,因此纯Delphi代码不再是这样的问题了.
很抱歉,没有解决方案,但也许是一个解释.
从XE4开始,相当多的FastCode例程已经取代了我在上面段落中谈到的未经优化的例程.它们通常仍然存在PUREPASCAL,但它们代表了一种很好的优化.所以情况并不像以前那么糟糕.在TStringHelper与普通字符串程序仍然显示了一些错误,并在一些极其缓慢的代码OS X(尤其是从Unicode转换为ANSI或反之而言),但Win64中的RTL的一部分似乎是好了很多.
尽量避免循环中的任何字符串分配.
在您的情况下,可能涉及x64调用约定的堆栈准备.你试图IsStrANumber宣布为inline?
我想这会让它更快.
function IsStrANumber(P: PAnsiChar): Boolean; inline;
begin
Result := False;
if P=nil then exit;
while P^ <> #0 do
if not (P^ in ['0'..'9']) then
Exit else
Inc(P);
Result := True;
end;
procedure TForm11.Button1Click(Sender: TObject);
Const x = '1234567890';
Var a,y,z: Integer;
s: AnsiString;
begin
z := GetTickCount;
s := x;
for a := 1 to 99999999 do begin
if IsStrANumber(pointer(s)) then y := 0;//StrToInt(x);
end;
Caption := IntToStr(GetTickCount-z);
end;
Run Code Online (Sandbox Code Playgroud)
RTL的"纯粹帕斯卡"版本确实是这里缓慢的原因......
请注意,与32位版本相比,FPC 64位编译器更糟糕......听起来Delphi编译器不是唯一的编译器!无论市场营销如何,64位并不意味着"更快"!有时甚至相反(例如,已知JRE在64位上较慢,并且当涉及指针大小时,将在Linux中引入新的x32模型).
代码可以像这样编写,具有良好的性能结果:
function IsStrANumber(const S: AnsiString): Boolean; inline;
var
P: PAnsiChar;
begin
Result := False;
P := PAnsiChar(S);
while True do
begin
case PByte(P)^ of
0: Break;
$30..$39: Inc(P);
else
Exit;
end;
end;
Result := True;
end;
Run Code Online (Sandbox Code Playgroud)
Intel(R)Core(TM)2 CPU T5600 @ 1.83GHz
英特尔(R)奔腾(R)D CPU 3.40GHz
展开上述循环可以加快执行速度:
function IsStrANumber(const S: AnsiString): Boolean; inline;
type
TStrData = packed record
A: Byte;
B: Byte;
C: Byte;
D: Byte;
E: Byte;
F: Byte;
G: Byte;
H: Byte;
end;
PStrData = ^TStrData;
var
P: PStrData;
begin
Result := False;
P := PStrData(PAnsiChar(S));
while True do
begin
case P^.A of
0: Break;
$30..$39:
case P^.B of
0: Break;
$30..$39:
case P^.C of
0: Break;
$30..$39:
case P^.D of
0: Break;
$30..$39:
case P^.E of
0: Break;
$30..$39:
case P^.F of
0: Break;
$30..$39:
case P^.G of
0: Break;
$30..$39:
case P^.H of
0: Break;
$30..$39: Inc(P);
else
Exit;
end;
else
Exit;
end;
else
Exit;
end;
else
Exit;
end;
else
Exit;
end;
else
Exit;
end;
else
Exit;
end;
else
Exit;
end;
end;
Result := True;
end;
Run Code Online (Sandbox Code Playgroud)
Intel(R)Core(TM)2 CPU T5600 @ 1.83GHz
英特尔(R)奔腾(R)D CPU 3.40GHz
如果你也应用了Arnaud Bouchez所说的你可以让它更快.
p^ in ['0'..'9']64 位测试速度很慢。
添加了一个内联函数,其中包含下边界/上边界测试而不是in []测试,以及空字符串测试。
function IsStrANumber(const S: AnsiString): Boolean; inline;
var
P: PAnsiChar;
begin
Result := False;
P := Pointer(S);
if (P = nil) then
Exit;
while P^ <> #0 do begin
if (P^ < '0') then Exit;
if (P^ > '9') then Exit;
Inc(P);
end;
Result := True;
end;
Run Code Online (Sandbox Code Playgroud)
基准测试结果:
x32 x64
--------------------
hikari 1420 3963
LU RD 1029 1060
Run Code Online (Sandbox Code Playgroud)
在 32 位中,主要的速度差异是内联,它P := PAnsiChar(S);会在分配指针值之前调用外部 RTL 例程进行 nil 检查,而P := Pointer(S);只是分配指针。
观察到这里的目标是测试字符串是否是数字,然后将其转换,为什么不使用 RTL TryStrToInt(),它一步完成所有操作并处理符号、空格。
通常,在分析和优化例程时,最重要的是找到解决问题的正确方法。
| 归档时间: |
|
| 查看次数: |
3884 次 |
| 最近记录: |