Asynchronous (overlapping) file access
Hi all!
I have a question concerning the asynchronous file access when using the
Platform SDK functions CreateFile/WriteFile. I am not completely sure what
"asynchronous" means. I thought, that the function WriteFile would return as
soon as possible after calling, and the file system does the job of writing
the data to disk in the background. But when I did some benchmarking, I
realized that synchronous and asynchronous file access are equally fast, when
measuring the time it takes for the WriteFile function to return. It could
well be, that I messed up some flags at the CreateFile / WriteFile
functions... Maybe some code is helpful to describe my benchmarking:
void AsynchronousFileAccess()
{
LPVOID buffer_address;
// Can only write in sizes of a multiple of this value to disk.
DWORD bytes_per_sector;
int bytes_to_write = 150000000;
SIZE_T bytes_to_write_aligned;
DWORD bytes_written;
HANDLE h_event;
HANDLE h_file;
int mod_result;
DWORD number_of_free_clusters;
// Overlapped structure
OVERLAPPED overlapped;
BOOL result;
DWORD sectors_per_cluster;
SYSTEM_INFO system_info;
PerfTimer timer_1;
PerfTimer timer_2;
DWORD total_number_of_clusters;
GetSystemInfo( &system_info );
result = GetDiskFreeSpace( L"C:\\", §ors_per_cluster, &bytes_per_sector,
&number_of_free_clusters, &total_number_of_clusters );
if (system_info.dwPageSize != bytes_per_sector)
{
cout << "Ohohhhh system_info.dwPageSize (" << system_info.dwPageSize << ")
!= bytes_per_sector (" << bytes_per_sector << ")\n";
}
// Unbuffered file access needs bytes read / written to be a multiple
// of the volume sector size.
(mod_result = bytes_to_write % bytes_per_sector) == 0 ?
bytes_to_write_aligned = bytes_to_write :
bytes_to_write_aligned = bytes_to_write + (bytes_per_sector - mod_result);
// The buffer needs to be aligned to addresses in memory that are a multiple
// of the volume sector size.
buffer_address = VirtualAlloc( NULL, bytes_to_write_aligned, MEM_COMMIT,
PAGE_READWRITE );
timer_1.Entry();
timer_2.Entry();
h_file = CreateFileA( "test_out", GENERIC_WRITE, NULL, NULL,
TRUNCATE_EXISTING,
//FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING, NULL);
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_NO_BUFFERING|FILE_FLAG_OVERLAPPED, NULL);
if (h_file == INVALID_HANDLE_VALUE)
{
cout << "Could not open file (error " << GetLastError() << ")\n";
_getch();
exit( 1 );
}
h_event = CreateEvent( NULL, TRUE, TRUE, NULL );
if (h_event == NULL)
{
cout << "CreateEvent failed (error " << GetLastError() << ")\n";
_getch();
exit( 1 );
}
// Don't use an event to signal completed operation,
// but use HasOverlappedIoCompleted() for this purpose.
overlapped.hEvent = h_event;
// Startposition in the file.
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
// Attempt a synchronous write operation.
//result = WriteFile( h_file, buffer_address,
(DWORD)bytes_to_write_aligned, &bytes_written, NULL );
// Attempt an asynchronous write operation.
result = WriteFile( h_file, buffer_address, (DWORD)bytes_to_write_aligned,
&bytes_written, &overlapped );
//result = WriteFileEx( h_file, buffer_address,
(DWORD)bytes_to_write_aligned, &overlapped, NULL );
timer_2.Exit();
// Wait till write is completed.
while (!HasOverlappedIoCompleted( &overlapped ));
result = CloseHandle( h_file );
timer_1.Exit();
VirtualFree( buffer_address, NULL, MEM_RELEASE );
cout << "All write time: " << timer_1.TotalCount() << "\n";
cout << "Until ready time: " << timer_2.TotalCount() << "\n";
_getch();
exit( 0 );
}
Right now the code is for asynchronous IO. When benchmarking synchronous IO
I also comment out the "HasOverlappedIoCompleted" line.
The thing is, that timer_1 and timer_2 show almost identical results, only 2
milliseconds or so apart. The filesize is 150MB which takes (about) 0.85
seconds. Both timers show this result (only 2 ms difference). There is also
no difference in using WriteFileEx instead of WriteFile, or if I use
"overlapped.hEvent = NULL;" instead of "overlapped.hEvent = h_event;"
Is my understanding of asynchronous IO wrong, or is there a bug in my code?
Regards,
Claus