具有随机读/写功能的SSD原始I / O基准测试

时间:2014-05-05 09:43:30

标签: c++ asynchronous io hard-drive ssd

我的笔记本电脑有一块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 / OI还设置FILE_SHARE_READFILE_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;
}

2 个答案:

答案 0 :(得分:2)

无法以MB /秒的速度很好地测量随机IO性能。它以IOPS衡量。 &#34;读取随机512字节块时的1.2 MB / s&#34; =&GT; 20000 IOPS。不错。块大小加倍,你将获得199%的MB /秒和99%的IOPS,因为读取512字节所需的时间几乎与读取1024字节相同(几乎没有时间)。固态硬盘并非无需寻找成本,有时会被误认为是这样。

所以这些数字实际上并不是很糟糕。

SSD受益于高队列深度。尝试一次发出多个IO,并始终保持该号码的优秀。最佳并发性将在1-32范围内。

由于SSD具有硬件并发性,因此您可以期望单线程性能的一小部分。我的SSD有4个并行&#34;银行&#34;例如。

使用FILE_FLAG_WRITE_THROUGH | FILE_FLAG_NO_BUFFERING是实现直接写入硬件所需的全部内容。如果这些标志不起作用,您的硬件不会尊重这些标志,您无法对其进行任何操作。所有服务器硬件都尊重这些标志,我没有看到没有消费者的磁盘。

在此上下文中,共享标志没有意义。

代码很好,虽然我不明白为什么你使用异步IO,然后等待事件等待完成。这是没有意义的。使用同步IO(执行与async IO大致相同)或使用async IO和完成端口,无需等待。

答案 1 :(得分:0)

使用hdparm -I / dev / sdx检查逻辑和物理块大小。大多数现代SSD具有4096字节的物理块大小,但也支持512字节块,以便与旧驱动器向后兼容。 OS软件。这是通过&#34; 512字节仿真&#34; A.K.A 512e。如果您的驱动器是进行512字节仿真的驱动器之一,则512字节访问实际上是读取修改写入操作。 SSD将尝试将顺序访问转换为4k块写入。

如果您可以切换到4k块写入,您(可能)会看到更好的IOPS数量和带宽,因为这样可以减少SSD的工作量。随着写入放大的增加,随机512块写入对长期性能也有很大影响。