我想知道是否更优化使用本地函数(在下面的例子中_drawBitmap)只需要3个参数而不能内联,因为函数访问一些所有者过程变量,或者使用可以内联的全局函数(但是它会真正内联吗?)并且需要5个参数.
也不知道它是否重要,但这段代码主要用于android/ios编译
代码具有本地功能:
procedure TMyObject.onPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
function _drawBitmap(const aBitmap: {$IFDEF _USE_TEXTURE}TTexture{$ELSE}Tbitmap{$ENDIF}; const aTopLeft: TpointF; Const aOpacity: Single): boolean;
var aDestRect: TrectF;
begin
Result := False;
if aBitmap <> nil then begin
//calculate aDestRect
aDestRect := canvas.AlignToPixel(
TRectF.Create(
aTopLeft,
aBitmap.Width/ScreenScale,
aBitmap.Height/ScreenScale));
//if the aBitmap is visible
if ARect.IntersectsWith(aDestRect) then begin
Result := True;
{$IFDEF _USE_TEXTURE}
TCustomCanvasGpu(Canvas).DrawTexture(aDestRect, // ATexRect
TRectF.Create(0,
0,
aBitmap.Width,
aBitmap.Height), // ARect
ALPrepareColor(TCustomCanvasGpu.ModulateColor, aOpacity * AbsoluteOpacity), // https://quality.embarcadero.com/browse/RSP-15432
aBitmap);
{$ELSE}
Canvas.DrawBitmap(aBitmap, // ABitmap
TRectF.Create(0,
0,
aBitmap.Width,
aBitmap.Height), // SrcRect
aDestRect, // DstRect
aOpacity * AbsoluteOpacity, // AOpacity
samevalue(aDestRect.Width, aBitmap.Width, Tepsilon.Position) and
samevalue(aDestRect.height, aBitmap.height, Tepsilon.Position)); // HighSpeed - set interpolation to none
{$ENDIF};
end;
end;
end;
begin
_drawBitmap(aBitmap, aPos, 1);
end;
Run Code Online (Sandbox Code Playgroud)
ASM:
MyObject.pas.2632: _drawBitmap(fBtnFilterBitmap, // aBitmap
00B97511 55 push ebp
00B97512 680000803F push $3f800000
00B97517 8B45F8 mov eax,[ebp-$08]
00B9751A 8D90C4050000 lea edx,[eax+$000005c4]
00B97520 8B45F8 mov eax,[ebp-$08]
00B97523 8B80A8040000 mov eax,[eax+$000004a8]
00B97529 E882FDFFFF call _drawBitmap
00B9752E 59 pop ecx
MyObject.pas.2562: begin
00B972B0 55 push ebp
00B972B1 8BEC mov ebp,esp
00B972B3 83C4A0 add esp,-$60
00B972B6 53 push ebx
00B972B7 56 push esi
00B972B8 57 push edi
00B972B9 8955FC mov [ebp-$04],edx
00B972BC 8BF0 mov esi,eax
MyObject.pas.2563: Result := False;
00B972BE 33DB xor ebx,ebx
MyObject.pas.2564: if aBitmap <> nil then begin
00B972C0 85F6 test esi,esi
00B972C2 0F84B4010000 jz $00b9747c
MyObject.pas.2567: aDestRect := canvas.AlignToPixel(
00B972C8 8B450C mov eax,[ebp+$0c]
00B972CB 8B78FC mov edi,[eax-$04]
00B972CE 8BC6 mov eax,esi
00B972D0 E88F559BFF call TBitmap.GetWidth
...
Run Code Online (Sandbox Code Playgroud)
并具有全球功能:
function drawBitmap(const Canvas: TCanvas; const ARect: TRectF; const aBitmap: {$IFDEF _USE_TEXTURE}TTexture{$ELSE}Tbitmap{$ENDIF}; const aTopLeft: TpointF; Const aOpacity: Single): boolean; inline;
var aDestRect: TrectF;
begin
Result := False;
if aBitmap <> nil then begin
//calculate aDestRect
aDestRect := canvas.AlignToPixel(
TRectF.Create(
aTopLeft,
aBitmap.Width/ScreenScale,
aBitmap.Height/ScreenScale));
//if the aBitmap is visible
if ARect.IntersectsWith(aDestRect) then begin
Result := True;
{$IFDEF _USE_TEXTURE}
TCustomCanvasGpu(Canvas).DrawTexture(aDestRect, // ATexRect
TRectF.Create(0,
0,
aBitmap.Width,
aBitmap.Height), // ARect
ALPrepareColor(TCustomCanvasGpu.ModulateColor, aOpacity * AbsoluteOpacity), // https://quality.embarcadero.com/browse/RSP-15432
aBitmap);
{$ELSE}
Canvas.DrawBitmap(aBitmap, // ABitmap
TRectF.Create(0,
0,
aBitmap.Width,
aBitmap.Height), // SrcRect
aDestRect, // DstRect
aOpacity * AbsoluteOpacity, // AOpacity
samevalue(aDestRect.Width, aBitmap.Width, Tepsilon.Position) and
samevalue(aDestRect.height, aBitmap.height, Tepsilon.Position)); // HighSpeed - set interpolation to none
{$ENDIF};
end;
end;
end;
procedure TMyObject.onPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
begin
drawBitmap(aBitmap, aPos, 1);
end;
Run Code Online (Sandbox Code Playgroud)
ASM:
MyObject.pas.2636: drawBitmap(Canvas, aRect, fBtnFilterBitmap, // aBitmap
00B98F6D 8BFB mov edi,ebx
00B98F6F 8B83A8040000 mov eax,[ebx+$000004a8]
00B98F75 8945F0 mov [ebp-$10],eax
00B98F78 8D83C4050000 lea eax,[ebx+$000005c4]
00B98F7E 8945EC mov [ebp-$14],eax
00B98F81 C645EB00 mov byte ptr [ebp-$15],$00
00B98F85 8B75F0 mov esi,[ebp-$10]
00B98F88 85F6 test esi,esi
00B98F8A 0F840A020000 jz $00b9919a
00B98F90 8BC6 mov eax,esi
00B98F92 E8CD389BFF call TBitmap.GetWidth
...
Run Code Online (Sandbox Code Playgroud)
在这里,关于使用VCL,立即调用该函数TCanvas.因此,显然过早优化,两者之间在实践中没有性能差异.全局函数可能更难维护(除非它是一些可以在单元中的其他地方实际重用的代码).无论如何,即使是全局函数也不是一个好主意:如果你有一些特定的可重用过程,那么定义一个class:它将更干净,更容易调试/扩展/测试.
仅适用于不调用任何其他功能的非常小的功能,内联可能会带来一些性能优势.例如:
function Add(n1,n2: integer): integer; inline;
begin
result := n1 + n2;
end;
Run Code Online (Sandbox Code Playgroud)
但在你的情况下,它没有任何意义.
并且,正如您所说,编译器实际上是否内联asm.如果它声明内联不会带来任何好处(它甚至可能比子函数慢),它将不会内联函数.
为了完整性,在低组合级别,当您在另一个函数中调用本地函数时,访问范围中的变量将添加调用者"堆栈帧"指针作为附加参数.
在伪代码中,它是这样的:
function _drawBitmap(const stackframe: TLocalStackRecord; const aBitmap: {$IFDEF _USE_TEXTURE}TTexture{$ELSE}Tbitmap{$ENDIF}; const aTopLeft: TpointF; Const aOpacity: Single): boolean;
var aDestRect: TrectF;
begin
Result := False;
if aBitmap <> nil then begin
//calculate aDestRect
aDestRect := stackframe.canvas.AlignToPixel(
TRectF.Create(
aTopLeft,
aBitmap.Width/ScreenScale,
aBitmap.Height/ScreenScale));
...
Run Code Online (Sandbox Code Playgroud)
尽量避免过早优化:
程序员浪费了大量时间来思考或担心程序中非关键部分的速度,而这些效率尝试实际上在考虑调试和维护时会产生很大的负面影响.我们应该忘记小的效率,大约97%的时间说:过早的优化是所有邪恶的根源.然而,我们不应该放弃那个关键的3%的机会. Knuth中的变体,"使用Goto语句进行结构化编程".计算机调查6:4(1974年12月),第261-301页,§1.
为避免浪费您的时间(和金钱),请使用分析器(例如Eric的采样分析器)来确定实际需要优化代码的哪一部分.
做对,然后快点.并使其始终可重复和可维护.
唯一可以确定的方法是分析两种变体的性能.
也就是说,看着代码,我的直觉告诉我,你将无法衡量两种变体之间的任何显着差异.性能将由调用的系统函数决定,而不是由高级代码决定.但是,这只是一个有根据的猜测.比较两者并测量.
至于你对inline的使用,我在这里有点怀疑.这是一个相当大的功能,内联往往是最有效的短叶功能.同样,我怀疑这里的内联会改变一切,但我的直觉说,如果有的话,在这里内联更有可能阻碍性能而不是帮助.
另一件需要强调的是,您应该首先集中精力优化瓶颈.您是否检查过此功能是否存在瓶颈?如果不是,则浪费任何优化工作.
| 归档时间: |
|
| 查看次数: |
217 次 |
| 最近记录: |