为什么 Sysutils.RenameFile 是内联的?

Why is Sysutils.RenameFile inlined?

[dcc32 Hint] H2443 Inline function 'RenameFile' has not been expanded because unit 'Winapi.Windows' is not specified in USES list

我知道内联函数可以使代码更快。但我只在狭窄的地方看到了收获。例如在一个大循环中调用一个小函数。

但是内联一个IO函数如何提高速度呢?我的意思是通过内联 RenameFile 你可以获得几微秒。但是执行函数本身可能需要几毫秒,如果磁盘繁忙,甚至可能需要几十毫秒。

更重要的是,如果您使用的是 RenameFile,则您可能在执行其他 I/O 操作的代码块中。所以,这段代码会花费很多时间。所以,现在的收获就更加微不足道了。

RenameFile 是内联的,因为它是对另一个函数的简单调用。

这是它的样子:

function RenameFile(const OldName, NewName: string): Boolean;
{$IFDEF MSWINDOWS}
begin
  Result := MoveFile(PChar(OldName), PChar(NewName));
end;

通过内联此函数,对 SysUtils.RenameFile 的调用将替换为对 WinApi.Windows.MoveFile 的调用。

这样做有以下优点:

  • 您保存一个电话,而不是两个电话,您只有一个电话。
  • 您的调用代码大小完全相同。
  • CPU 保存一个return地址列表用于分支预测(return堆栈缓冲区);通过消除冗余调用,它将 space 保存在此缓冲区中,这可以防止调用堆栈太深时的错误预测。
  • 生成的代码更小,因为 RenameFile 本身被消除了。

所以内联非常值得麻烦,尤其是在调用堆栈可能很深的递归代码中,CPU 将开始错误预测 return,因为 return 堆栈缓冲区溢出(一些 CPU 只有 8 个条目,行首 CPU 有 24 个条目)。

通常,每个仅调用另一个例程的例程都应始终内联。

正确预测 return 花费一个周期,错误预测清空管道并花费 25 个周期或更多;增加了进一步的延迟,因为 return 地址需要从内存而不是缓冲区中获取。

你是对的,none 这些优势在磁盘 IO 代码中很重要,但这并不影响像这样的简单重定向函数应该始终内联的事实。