My laptop has an SSD with a physical disk sector size of 512 bytes and a disk size of 4096 bytes. I am working on an ACID database system that should bypass all OS caches, so I write directly from the allocated internal memory (RAM) to the SSD. I also expand the files before running the tests and do not change their size during the tests.
Now here is my problem, according to the SSD tests, random read and write should be in the range from 30 MB / s to 90 MB / s, respectively. But here is my (rather awful) telemetry from my many checks:
- 1.2 MB / s when reading random 512 byte blocks (physical sector size)
- 512 KB / s for writing arbitrary 512 byte blocks (physical sector size)
- 8.5 MB / s when reading random 4,096 byte blocks (logical sector size)
- 4.9 MB / s when writing random 4,096 byte blocks (logical sector size)
In addition to using asynchronous I / OI, also set the flags FILE_SHARE_READand FILE_SHARE_WRITEto disable all OS buffering - because our database is ACID, I have to do this, I also tried FlushFileBuffers(), but this is even worse than me. I also expect each async I / O to complete, as required by some of our code.
Here is my code, is there a problem with it, or am I sticking to this poor I / O performance?
HANDLE OpenFile(const wchar_t *fileName)
{
DWORD desiredAccess = GENERIC_READ | GENERIC_WRITE ;
DWORD fileFlags = FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING ;
fileFlags |= FILE_FLAG_OVERLAPPED ;
DWORD shareMode = 0;
HANDLE hOutputFile = CreateFile(
fileName,
desiredAccess,
shareMode,
NULL,
CREATE_NEW,
fileFlags,
NULL
);
if (hOutputFile == INVALID_HANDLE_VALUE)
{
int lastError = GetLastError();
std::cerr << "Unable to create the file '" << fileName << "'. [CreateFile] error #" << lastError << "." << std::endl;
}
return hOutputFile;
}
DWORD ReadFromFile(HANDLE hFile, void *outData, _UINT64 bytesToRead, _UINT64 location, OVERLAPPED *overlappedPtr,
asyncIoCompletionRoutine_t completionRoutine)
{
DWORD bytesRead = 0;
if (overlappedPtr)
{
overlappedPtr->Offset = (DWORD)_UINT64LO(location);
overlappedPtr->OffsetHigh = (DWORD)_UINT64HI(location);
if (!completionRoutine && !overlappedPtr->hEvent)
{
overlappedPtr->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!overlappedPtr->hEvent)
{
DWORD errNumber = GetLastError();
std::wcerr << L"Could not create a new event. [CreateEvent] error #" << errNumber << L".";
}
}
}
BOOL result = completionRoutine ?
ReadFileEx(hFile, outData, (DWORD)(bytesToRead), overlappedPtr, completionRoutine) :
ReadFile(hFile, outData, (DWORD)(bytesToRead), &bytesRead, overlappedPtr);
if (result == FALSE)
{
DWORD errorCode = GetLastError();
if (errorCode != ERROR_IO_PENDING)
{
std::wcerr << L"Can't read sectors from file. [ReadFile] error #" << errorCode << L".";
}
}
return bytesRead;
}