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;
}
Comments
- Anonymous
June 18, 2009
PingBack from http://barstoolsite.info/story.php?id=1870