我的笔记本电脑有一个SSD磁盘,其物理磁盘扇区大小为512字节,逻辑磁盘扇区大小为4,096字节.我正在研究一个必须绕过所有操作系统缓存的ACID数据库系统,所以我直接从分配的内部存储器(RAM)写入SSD磁盘.我还在运行测试之前扩展文件,并且在测试期间不调整大小.
现在这是我的问题,根据SSD benchmarks随机阅读& write应分别在30 MB / s到90 MB / s的范围内.但这是我的(相当可怕的)遥测我的众多性能测试:
读取随机512字节块(物理扇区大小)时> 1.2 MB / s
写入随机512字节块时的> 512 KB / s(物理扇区大小)
读取随机4,096字节块(逻辑扇区大小)时> 8.5 MB / s
写入随机4,096字节块(逻辑扇区大小)时> 4.9 MB / s
除了使用异步I / O之外,我还设置了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;
}
最佳答案 无差别地测量随机IO性能,单位为MB /秒.它以IOPS衡量. “读取随机512字节块时为1.2 MB / s”=> 20000 IOPS.不错.块大小加倍,你将获得199%的MB /秒和99%的IOPS,因为读取512字节所需的时间几乎与读取1024字节相同(几乎没有时间). SSD有时会被错误地假设,而不是寻求成本.
所以数字实际上并不坏.
SSD受益于高队列深度.尝试一次发出多个IO,并始终保持该号码的优秀.最佳并发性将在1-32的范围内.
由于SSD具有硬件并发性,因此您可以期望单线程性能的一小部分.例如,我的SSD有4个并行的“库”.
使用FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING是实现直接写入硬件所需的全部内容.如果这些标志不起作用,您的硬件不会尊重这些标志,您无法对此做任何事情.所有服务器硬件都尊重这些标志,我没有看到没有的消费者磁盘.
在此上下文中,共享标志没有意义.
代码很好,虽然我不明白为什么你使用异步IO,然后等待事件等待完成.这是没有意义的.使用同步IO(将执行与async IO大致相同)或使用具有完成端口的异步IO并且无需等待.