私のラップトップには、512 バイトの物理ディスク セクター サイズと 4,096 バイトの論理ディスク セクター サイズを持つ SSD ディスクがあります。すべての OS キャッシュをバイパスする必要がある ACID データベース システムで作業しているため、割り当てられた内部メモリ (RAM) から SSD ディスクに直接書き込みます。また、テストを実行する前にファイルを拡張し、テスト中にサイズを変更しません。
SSDベンチマークによると、ランダムな読み取りと書き込みはそれぞれ30 MB / sから90 MB / sの範囲内である必要があります。しかし、これは私の多数のパフォーマンス テストから得た (かなり恐ろしい) テレメトリです。
- ランダムな 512 バイト ブロック (物理セクター サイズ) を読み取る場合は 1.2 MB/秒
- ランダムな 512 バイト ブロック (物理セクター サイズ) を書き込む場合は 512 KB/秒
- ランダムな 4,096 バイト ブロック (論理セクター サイズ) を読み取る場合は 8.5 MB/秒
- ランダムな 4,096 バイト ブロック (論理セクター サイズ) を書き込む場合は 4.9 MB/秒
非同期 I/OI を使用するだけでなく、フラグFILE_SHARE_READ
とFILE_SHARE_WRITE
フラグを設定してすべての OS バッファリングを無効にします。データベースは ACID であるため、これを行う必要があります。これも試しFlushFileBuffers()
ましたが、パフォーマンスがさらに低下しました。また、一部のコードで要求されるように、各非同期 I/O 操作が完了するのを待ちます。
これが私のコードです。問題があるのでしょうか、それとも I/O パフォーマンスが悪いのでしょうか?
HANDLE OpenFile(const wchar_t *fileName)
{
// Set access method
DWORD desiredAccess = GENERIC_READ | GENERIC_WRITE ;
// Set file flags
DWORD fileFlags = FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING /*| FILE_FLAG_RANDOM_ACCESS*/;
//File or device is being opened or created for asynchronous I/O
fileFlags |= FILE_FLAG_OVERLAPPED ;
// Exlusive use (no share mode)
DWORD shareMode = 0;
HANDLE hOutputFile = CreateFile(
// File name
fileName,
// Requested access to the file
desiredAccess,
// Share mode. 0 equals exclusive lock by the process
shareMode,
// Pointer to a security attribute structure
NULL,
// Action to take on file
CREATE_NEW,
// File attributes and flags
fileFlags,
// Template file
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)
{
// Windows demand that you split the file byte locttion into high & low 32-bit addresses
overlappedPtr->Offset = (DWORD)_UINT64LO(location);
overlappedPtr->OffsetHigh = (DWORD)_UINT64HI(location);
// Should we use a callback function or a manual event
if (!completionRoutine && !overlappedPtr->hEvent)
{
// No manual event supplied, so create one. The caller must reset and close it themselves
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;
}