It Is Nice To Be At The Top Of The Food Chain

The Back Story

A very long time ago, maybe it was even as much as 2 years ago now, I wanted to answer the question 'Just how much overhead is there using one API call compared to another API call?'.  This question came to mind after I realized just how many ways there was to move a file.  So I wrote a simple command line application to track just that.  

The application moved a file back and fourth 5000 times using a certain method, and I recorded the results' averages(excluding times when the disk cache caused really bad results):

Slowest 2230ms
Slow 1540ms
Fast 1240ms
Fastest 1060ms

 

Why does this happen?

Well there is a lot of overhead in just the functions calling other functions further up the chain, and converting the text to unicode in some cases.  If I had to take a guess, the call stack would look something like this from the slowest method:

  • NtSetInformationFile
  • MoveFileWithProgressW
  • MoveFileExW
  • MoveFileW
  • wrename
  • rename

 

Show Me The Code

Part of the source code was written by Alex Ionescu and I have removed a few parts of the code because it used undocumented behavior in the 'Fastest' method.  This code was compiled without optimization(turning them on may even fix this problem for you) using the mingw compiler.  

 CALLBACK
WinMain(__in HINSTANCE hInstance,
        __in_opt HINSTANCE hPrevInstance,
        __in_opt LPSTR lpCmdLine,
        __in int nShowCmd)
{
    MSG Msg;
 
    int i;
    DWORD Start, End;
 
    Start = GetTickCount();
 
    for(i = 0; i < 5000; i++)
    {
#ifdef SLOWEST
        rename("C:\\Temp\\foo.exe","C:\\Temp\\bar.exe");
        rename("C:\\Temp\\bar.exe","C:\\Temp\\foo.exe");
#endif /* SLOWEST */
 
#ifdef SLOW
        MoveFileA("C:\\Temp\\foo.exe","C:\\Temp\\bar.exe");
        MoveFileA("C:\\Temp\\bar.exe","C:\\Temp\\foo.exe");
#endif /* SLOW */
 
#ifdef FAST
        MoveFileWithProgressW(L"C:\\Temp\\foo.exe",L"C:\\Temp\\bar.exe", NULL, NULL, MOVEFILE_COPY_ALLOWED);
        MoveFileWithProgressW(L"C:\\Temp\\bar.exe",L"C:\\Temp\\foo.exe", NULL, NULL, MOVEFILE_COPY_ALLOWED);
#endif /* FAST */
 
#ifdef FASTEST
        {
        // Shared Variables
        NTSTATUS Status;
        IO_STATUS_BLOCK IoStatusBlock;
        HANDLE Handle;
 
        // Open the old file and tell NT we plan to delete it
        Status = NtOpenFile(/* Remove */);
 
        // Do the first rename
        Status = NtSetInformationFile(/* Remove */);
 
        // Close the handle
        NtClose(Handle);

        // Open the new file and tell NT we plan to delete it
        Status = NtOpenFile(/* Remove */);
 
        // Do the 2nd rename
        Status = NtSetInformationFile(/* Remove */);
 
        NtClose(Handle);
        }
#endif /* FASTEST */
    }
 
    End = GetTickCount();
 
    printf("%d -- %d\n",(End - Start),GetLastError());

    system("pause");
    return 0;
    }