RenameFile
是内联的,因为它是对另一个函数的简单调用。
这里是什么样子:
function RenameFile(const OldName, NewName: string): Boolean;
{$IFDEF MSWINDOWS}
begin
Result := MoveFile(PChar(OldName), PChar(NewName));
end;
通过内联这个函数调用SysUtils.RenameFile
得到通过调用替换为WinApi.Windows.MoveFile
。
这具有以下优点:
- 你保存在呼叫,而不是两个电话,你只需要一个电话。
- 您的调用代码大小完全相同。
- CPU保留分支预测(返回堆栈缓冲区)的返回地址列表;通过消除冗余调用,可以节省此缓冲区中的空间,从而防止调用堆栈变得太深时发生预测失误。
- 生成的代码较小,因为
RenameFile
本身被取消。
所以内联是非常值得的麻烦,尤其是在递归代码在调用堆栈可以得到深层的CPU将开始mispredicting的回报,因为返回堆栈缓冲区溢出(一些CPU的只有8项,顶部线CPU有24个条目)。
通常,每个调用另一个例程的例程都应该内联。
一个正确的预测回报需要花费一个周期,一个错误预测会清空管道,花费25个周期或更多;由于返回地址需要从存储器而不是缓冲区中获取,所以会增加进一步的延迟。
你是正确的,这些优点都不会影响磁盘IO代码,但这并没有减少这样的简单重定向函数应该总是内联的事实。
出于同样的原因,他们宣布它的参数“const”......性能增益可能不是那么有意义,但它或多或少是免费的。 (如果你不知道,当它传递给一个函数时,声明一个字符串参数'const'去掉引用计数的Inc/dec)。 –
@ KenBourassa-CONST实际上做的不仅仅是这些,而且在某些条件下(经常遇到)速度增益很大。 – Ampere
以及它在字符串的上下文中还做了什么?对于一个记录,它将通过地址传递,而不是复制其内容,所以当然,速度增益可能相当大。但是在字符串参数的上下文中,引用计数(和所有相关的)是AFAIK的唯一区别。 –