使用局部函数和全局函数哪个更优化?

2024-04-27

我想知道使用 a 是否更优化局部功能(在下面的例子中_drawBitmap)只需要3个参数 and 无法内联因为该函数访问一些所有者过程变量,或者使用可以内联的全局函数(但它真的会内联吗?)这需要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;  

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
...

并具有全局功能:

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;  

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
...

在这里,相对于使用 VCL 而言,调用该函数将是立即的TCanvas。所以这显然是不成熟的优化,两者在实践中没有性能差异。全局函数可能更难以维护(除非它是一些实际上可以在单元中其他地方重用的代码)。无论如何,即使是全局函数也不是一个好主意:如果您有一些特定的可重用过程,请定义一个class相反:它将更干净、更容易调试/扩展/测试。

仅对于不调用任何其他函数的非常小的函数,内联可能会带来一些性能优势。例如:

function Add(n1,n2: integer): integer; inline;
begin
  result := n1 + n2;
end;

但就你而言,这没有任何意义。

而且,正如您所说,是否实际内联汇编取决于编译器。如果它声明内联不会带来任何好处(它甚至可能比子函数慢),则它不会内联该函数。

为了完整性,在低汇编级别,当您在另一个函数中调用本地函数时,对作用域中的变量的访问是通过添加调用者“堆栈帧”指针作为附加参数来完成的。

用伪代码来说,是这样的:

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));
  ...

尽量避免过早优化:

程序员浪费大量时间思考或担心 关于,他们程序的非关键部分的速度,以及这些 尝试提高效率实际上会产生强烈的负面影响 考虑了调试和维护。我们应该忘记小事 效率,大约 97% 的时间:过早优化是 万恶之源。然而我们不应该放弃这方面的机会 临界3%。Knuth 的变体,“使用 Goto 语句进行结构化编程”。计算调查 6:4(1974 年 12 月),第 261–301 页,§1。

为了避免浪费您的时间(和金钱),请使用分析器 - 例如Eric 的采样分析器 https://www.delphitools.info/samplingprofiler/- 找出代码的哪一部分实际上需要优化。

做得对,然后做得快。并使其始终可读且可维护。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用局部函数和全局函数哪个更优化? 的相关文章

  • 德尔福数据结构

    我可能需要在 Delphi 中做一个项目 并且是该领域的初学者 目前 我正在网上搜索资源 但由于资源站点太少而感到困惑 首先 你能给我一些好的网站 其中包含我迄今为止错过的 Delphi 资源吗 我也在 Delphi 中搜索数据结构 想知道
  • Delphi 返回 TList 时出错

    我做了一个非常简单的应用程序 但我有一个我真的无法理解的问题 看一下这个基本代码 unit Unit1 interface uses Winapi Windows Winapi Messages System SysUtils System
  • 以编程方式重新启动 Delphi 应用程序

    应该不可能运行我的应用程序的多个实例 因此项目源码包含 CreateMutex nil False PChar ID if GetLastError ERROR ALREADY EXISTS then Halt 现在我想以编程方式重新启动我
  • 为什么未初始化的指针会导致内存访问冲突接近 0?

    据说often 但并非总是如此 当你在接近于零的内存位置 比如 89 美元 获得 AV 时 你就有了一个未初始化的指针 但我也在 Delphi 书籍中看到了这一点 嗯 或者它们都是由同一作者写的 Update 引自 Bob Swart 等人
  • 在 Delphi 中使用 XML(将特定数据返回到变量)

    过去几天我一直在尝试使用 Delphi 2010 和 MSXML 我是一个极端的新手 需要一点指导 var MemoryStream TMemoryStream XMLPath String sName String XMLDoc vari
  • 石和磅的格式正确吗?

    我有一个图表 用于显示重量 以英石和磅 lbs 为单位 该图表由记录中的数据填充 对于权重 数据类型为 Double 记录数据是在运行时编辑的 我需要知道一种正确格式化输入数据的方法 为了更好地理解 首先看一下这些示例值 它们表示为石和磅
  • 每次 TDbGrid 的选定位置更改时都会触发什么事件?

    我的项目中有一个 TDbGrid 每次更改所选行时我都试图触发一个事件 行中的任何更改都已经更新了链接到同一数据源的所有数据感知控件 但还需要进行其他更改 我需要一个事件处理程序 我认为 OnColEnter 会起作用 根据帮助文件 它在以
  • 将数据从一个数据集结构移动到另一个数据集结构的更快方法(在 TDatasetProvider 中)

    我有一个自定义的 TDatasetProvider 它允许为其提供的任何数据创建新字段 因此 假设您在原始数据集上获得了以下字段 客户ID Name Age 您需要使用显示位图在 DBGrid 上选择它 好吧 你可以 因为我的 DSP 可以
  • 如何在运行时(Delphi/Windows)程序中添加代码?

    我正在Windows XP Delphi 7上工作 我需要在正在运行的程序中添加一些过程 或函数 并且我不想在完成后再次重新编译它 我只有一个具有 5 个功能的主机应用程序来发送不同类型的警报 但是还有其他新的警报类型 所以我必须执行新的功
  • 为什么 Delphi 变体不能保存对象?

    为什么 Delphi 变体不能保存对象 更重要的是 这种限制背后的原因是什么 你绝对可以storeVariant 变量中的对象 只需将其转换为 NativeUInt 无论如何 对象只是一个指针 obj TObject Create v Na
  • 将delphi stringgrid导出到excel

    我正在尝试将数据从delphi 7 中的stringgrid 导出到microsoft excel 我一直在使用这段代码来做到这一点 objExcel TExcelApplication Create nil objExcel Visibl
  • TThread.resume 在 Delphi-2010 中已弃用,应该在什么地方使用?

    在我的多线程应用程序中 I use TThread 挂起 and TThread resume 自从将我的应用程序移至 Delphi 2010 后 我收到以下警告消息 DCC 警告 xxx pas 277 W1000 符号 Resume 已
  • Delphi XE2,vcl样式重新创建窗口句柄

    在运行时应用新样式后 我的应用程序的 MainForm 创建一个新的窗口句柄 有什么方法可以阻止此操作或重新分配句柄 因为我收到了大量以下错误 系统错误 代码 1400 无效的窗口句柄 有什么方法可以操纵强制分配新句柄的进程吗 我通过执行以
  • Writeln 能够支持 Unicode 吗?

    考虑这个程序 APPTYPE CONSOLE begin Writeln Z end 使用 Consolas 字体的控制台上的输出是 Z Windows 控制台非常有能力支持 Unicode 如该程序所示 APPTYPE CONSOLE u
  • 如何制作自定义组件属性?

    我需要帮助来制作一个控件属性 当您单击它时 它会弹出一个自定义对话框 例如设置 就像 TPicture 一样 有什么想法或建议吗 如果您的类用作其他组件的属性 并且您想使用对象检查器来调用对话框 那么您必须实现并注册一个自定义属性编辑器 例
  • 如何隐藏主窗体而不是关闭它?

    如果用户点击X在我的主窗体上 我希望窗体隐藏 而不是关闭 这听起来像是一份工作OnClose表单事件 http docs embarcadero com products rad studio delphiAndcpp2009 HelpUp
  • Delphi TTask - PPL 中匿名函数中的变量捕获如何工作?

    我开始深入研究 Delphi D11 PPL 并编写了这个小例子 procedure TForm2 LaunchTasks const cmax 5 Var ltask ITask i j Integer begin for i 1 to
  • 控制台应用程序比 GUI 应用程序运行得更快吗? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我对编程世界比较陌生 我有几个性能问
  • 当应用程序最小化时隐藏表单

    我有一个主表单和一个状态表单 当我的应用程序中的工作正在进行时 我会显示它们 如果工作完成我就打电话Hide状态表上出现 状态表消失 当我最小化主窗体而等待窗体可见时 就会出现问题 然后两种形式都被隐藏 这就是我想要的 但是 如果工作完成时
  • 应用程序需要很长时间才能同步线程(或根本不同步)

    我在 Delphi XE5 iOS 和 Android 中使用 REST 组件 我目前正在通过 iOS 模拟器进行测试 我的应用程序often挂在我的代码中的以下行 R Request Execute 经过一些调试后 我发现它特别挂在 RE

随机推荐