12

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

I understand that inlining a function makes the code faster. But I see the gain only in tight places. For example calling a small function in a big loop.

But how can inlining an IO function can improve speed? I mean by inlining RenameFile you gain few microseconds. But executing the function itself may take milliseconds, maybe even tens of ms if the disk is busy.

Even more, if you are using RenameFile, you are probably in a block of code where you are doing other I/O operations. So, this block of code will take a lot of time. So, the gain is even more insignificant now.

Johan
  • 74,508
  • 24
  • 191
  • 319
Gabriel
  • 20,797
  • 27
  • 159
  • 293
  • For the same reason they declared its parameter `const`... the performance gain might not be that significative, but it's more or less free. (If you didn't know, declaring a string parameter `const` remove the Inc/dec of its reference count when it is passed to a function). – Ken Bourassa Apr 28 '16 at 16:20
  • 1
    @KenBourassa-CONSTactually does more than that and in certain conditions (met quite often) the speed gain is big. – Gabriel Apr 29 '16 at 09:04
  • and what else does it do in the context of a string? For a record, it will be passed by address instead of copying its content so yeah, sure, the speed gain can be pretty big. But in the context of a string parameter, the reference count (and everything related) is the only difference AFAIK. – Ken Bourassa Apr 29 '16 at 13:49
  • 1
    When you don't use CONST a copy of the string may be created. This never happen with CONST. In a loop, if the passed parameter is a long string, then the speed impact can be huge. – Gabriel Apr 30 '16 at 17:07
  • any sources? I could see that happening for widestring and shortstring... But for string, I don't remember seeing or hearing about any situation that would cause a copy of the string to be created. (That is, in all the cases where you *can* declare the parameter `const`) – Ken Bourassa May 01 '16 at 03:11
  • is is not that difficult to make a google search on this theme. the results are http://stackoverflow.com/questions/1951192/delphi-performance-of-passing-const-strings-versus-passing-var-strings : "To sum it up, const is always the most efficient way to pass parameter of any type, but..." – Gabriel May 02 '16 at 16:12
  • It seems you didn't understand my point... I never challenged the fact that using `const` *may* make things faster, I challenged your assertion that a copy of a string may be made if a string parameter is not declared `const`. Actually, Johan's answer to the question you are linking to contradict your claim. So unless you can explain or reference which situation can cause that, I'll just assume you are wrong about it. – Ken Bourassa May 02 '16 at 17:27
  • Please see @François 's answer. – Gabriel May 03 '16 at 12:51
  • also Johan's answer: "When the string gets changed (and only then) Delphi makes a copy of the string" – Gabriel May 03 '16 at 12:54
  • also The_Fox's answer: "The compiler won't make a copy of the string when using const afaik" – Gabriel May 03 '16 at 12:55
  • also Deltic's comment... and so on – Gabriel May 03 '16 at 12:56
  • François's answer doesn't show any situation where it can occurs. While it's true that for const records, it will (usually) pass a reference instead of a copy, I don't believe he's right in saying it's the same for string (well... Shortstring yes, string no). In the situation Johan's refer, you can *not* declare the parameter const because you modify the variable. Also, the copy is not done when the call is made, it is done just before modying the string (Copy-on-write). If the string modification is conditional, no copy is made if the condition is not met. – Ken Bourassa May 03 '16 at 14:30
  • And the other side of what you said: If the string is modified a copy is made. Hence, performance penalty. – Gabriel May 04 '16 at 07:58
  • @KenBourassa- I don't believe he's right in saying.... Please leave him a comment. – Gabriel May 04 '16 at 07:58
  • Modifying a string that has a reference count > 1 creates a copy of the string. It's the well-known "copy-on-write" mechanism that strings have in Delphi. That is something that is not related to declaring a parameter as `const`. Declaring a string as `const` only prevent you from modifying it. Like I said already, in every instance where you *can* declare a string param `const`, no copy is ever made. If you can find a single case where it is not true, I'd be glad to learn about it, but I doubt such a situation exists. – Ken Bourassa May 04 '16 at 16:01

1 Answers1

18

RenameFile is inlined because it is a simple call to another function.

Here's what it looks like:

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

By inlining this function the call to SysUtils.RenameFile gets replaced by a call to WinApi.Windows.MoveFile.

This has the following advantages:

  • You save a call, instead of two calls you only have one call.
  • Your calling code is exactly the same size.
  • The CPU keeps a list of return addresses for branch prediction (return stack buffer); by eliminating the redundant call it saves space in this buffer this prevents misprediction if the call stack gets too deep.
  • The generated code is smaller, because RenameFile itself gets eliminated.

So the inlining is very much worth the trouble, especially in recursive code where the call stack can get deep the CPU will start mispredicting the returns because the return stack buffer overflows (some CPU's have only 8 entries, top of the line CPU's have 24 entries).

As a rule every routine that simply calls another routine should always be inlined.

A correctly predicted return costs a single cycle, a mispredict empties the pipeline and costs 25 cycles or more; further delays are added because the return address needs to be fetched from memory rather than the buffer.

You are correct that none of these advantages are going to matter in disk IO code, but that does not detract from the fact that simple redirect functions like this should always be inlined.

Johan
  • 74,508
  • 24
  • 191
  • 319