首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在Windows中检测SSD

在Windows中检测SSD
EN

Stack Overflow用户
提问于 2014-04-29 19:15:53
回答 6查看 12.6K关注 0票数 21

我想根据系统驱动器是否是固态硬盘来更改我的C++应用程序的性能和行为。示例:

使用固态硬盘,我希望我的游戏服务器应用程序完全加载每个地图和所有对象为了最大化performance.

  • With

  • ,我希望我的游戏服务器应用程序只加载每个地图中的基本对象和实体,而不加载外部对象。

我见过http://msdn.microsoft.com/en-gb/library/windows/desktop/aa364939(v=vs.85).aspx,这是一种确定某个驱动器是否是硬盘、CD、DVD、可移动介质等的方法,但它仍然无法检测主系统驱动器是否是固态硬盘。我也见过Is there any way of detecting if a drive is a SSD?,但这个解决方案只适用于Linux。

我认为我可以以某种方式生成一个很大的罚款(500MB),然后对写入文件所需的时间进行计时,但其他系统变量很容易影响结果。

在Windows中,使用C++,有没有办法获取主系统驱动器是否是固态硬盘?

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2016-05-13 00:42:03

您可以使用Microsoft WMI Class MSFT_PhysicalDisk。4的媒体类型为固态硬盘,SpindleSpeed为0。

票数 15
EN

Stack Overflow用户

发布于 2015-10-27 10:46:50

在做了一些研究并使用了本页答案中的信息后,下面是我使用C WinAPI for Windows 7和更高版本的实现:

代码语言:javascript
复制
//Open drive as such: "\\?\PhysicalDriveX" where X is the drive number
//INFO: To get drive number from a logical drive letter, check this method:
//      (But keep in mind that a single logical drive, or a volume,
//       can span across several physical drives, as a "spanned volume.")
//       http://stackoverflow.com/a/11683906/843732

#include <WinIoCtl.h>
#include <Ntddscsi.h>

DWORD bytesReturned;

//As an example, let's test 1st physical drive
HANDLE hDevice = ::CreateFile(L"\\\\?\\PhysicalDrive0",
    GENERIC_READ | GENERIC_WRITE,       //We need write access to send ATA command to read RPMs
    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
    OPEN_EXISTING,  0, NULL);
if(hDevice != INVALID_HANDLE_VALUE)
{
    //Check TRIM -- should be Y for SSD
    _tprintf(L"TRIM=");

    STORAGE_PROPERTY_QUERY spqTrim;
    spqTrim.PropertyId = (STORAGE_PROPERTY_ID)StorageDeviceTrimProperty;
    spqTrim.QueryType = PropertyStandardQuery;

    bytesReturned = 0;
    DEVICE_TRIM_DESCRIPTOR dtd = {0};
    if(::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
        &spqTrim, sizeof(spqTrim), &dtd, sizeof(dtd), &bytesReturned, NULL) &&
        bytesReturned == sizeof(dtd))
    {
        //Got it
        _tprintf(L"%s", dtd.TrimEnabled ? L"Y" : L"N");
    }
    else
    {
        //Failed
        int err = ::GetLastError();
        _tprintf(L"?");
    }


    //Check the seek-penalty value -- should be N for SSD
    _tprintf(L", seekPenalty=");

    STORAGE_PROPERTY_QUERY spqSeekP;
    spqSeekP.PropertyId = (STORAGE_PROPERTY_ID)StorageDeviceSeekPenaltyProperty;
    spqSeekP.QueryType = PropertyStandardQuery;

    bytesReturned = 0;
    DEVICE_SEEK_PENALTY_DESCRIPTOR dspd = {0};
    if(::DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY,
        &spqSeekP, sizeof(spqSeekP), &dspd, sizeof(dspd), &bytesReturned, NULL) &&
        bytesReturned == sizeof(dspd))
    {
        //Got it
        _tprintf(L"%s", dspd.IncursSeekPenalty ? L"Y" : L"N");
    }
    else
    {
        //Failed
        int err = ::GetLastError();
        _tprintf(L"?");
    }


    //Get drive's RPMs reading -- should be 1 for SSD
    //CODE SOURCE: https://emoacht.wordpress.com/2012/11/06/csharp-ssd/
    _tprintf(L", RPM=");

    ATAIdentifyDeviceQuery id_query;
    memset(&id_query, 0, sizeof(id_query));

    id_query.header.Length = sizeof(id_query.header);
    id_query.header.AtaFlags = ATA_FLAGS_DATA_IN;
    id_query.header.DataTransferLength = sizeof(id_query.data);
    id_query.header.TimeOutValue = 5;   //Timeout in seconds
    id_query.header.DataBufferOffset = offsetof(ATAIdentifyDeviceQuery, data[0]);
    id_query.header.CurrentTaskFile[6] = 0xec; // ATA IDENTIFY DEVICE

    bytesReturned = 0;
    if(::DeviceIoControl(hDevice, IOCTL_ATA_PASS_THROUGH,
        &id_query, sizeof(id_query), &id_query, sizeof(id_query), &bytesReturned, NULL) &&
        bytesReturned == sizeof(id_query))
    {
        //Got it

        //Index of nominal media rotation rate
        //SOURCE: http://www.t13.org/documents/UploadedDocuments/docs2009/d2015r1a-ATAATAPI_Command_Set_-_2_ACS-2.pdf
        //          7.18.7.81 Word 217
        //QUOTE: Word 217 indicates the nominal media rotation rate of the device and is defined in table:
        //          Value           Description
        //          --------------------------------
        //          0000h           Rate not reported
        //          0001h           Non-rotating media (e.g., solid state device)
        //          0002h-0400h     Reserved
        //          0401h-FFFEh     Nominal media rotation rate in rotations per minute (rpm)
        //                                  (e.g., 7 200 rpm = 1C20h)
        //          FFFFh           Reserved
        #define kNominalMediaRotRateWordIndex 217
        _tprintf(L"%d", (UINT)id_query.data[kNominalMediaRotRateWordIndex]);
    }
    else
    {
        //Failed
        int err = ::GetLastError();
        _tprintf(L"?");
    }


    _tprintf(L"\n");
    ::CloseHandle(hDevice);
}

如果你没有驱动程序DDK包含,这里有一些定义:

代码语言:javascript
复制
#ifndef StorageDeviceTrimProperty
#define StorageDeviceTrimProperty 8
#endif

#ifndef DEVICE_TRIM_DESCRIPTOR
typedef struct _DEVICE_TRIM_DESCRIPTOR {
  DWORD   Version;
  DWORD   Size;
  BOOLEAN TrimEnabled;
} DEVICE_TRIM_DESCRIPTOR, *PDEVICE_TRIM_DESCRIPTOR;
#endif


#ifndef StorageDeviceSeekPenaltyProperty
#define StorageDeviceSeekPenaltyProperty 7
#endif

#ifndef DEVICE_SEEK_PENALTY_DESCRIPTOR
typedef struct _DEVICE_SEEK_PENALTY_DESCRIPTOR {
  DWORD   Version;
  DWORD   Size;
  BOOLEAN IncursSeekPenalty;
} DEVICE_SEEK_PENALTY_DESCRIPTOR, *PDEVICE_SEEK_PENALTY_DESCRIPTOR;
#endif


struct ATAIdentifyDeviceQuery
{
    ATA_PASS_THROUGH_EX header;
    WORD data[256];
};

最后,我的测试的结论。

我有几个通过SATA线连接的三星固态硬盘,以及一个使用PCIe插槽直接连接到逻辑板的PCIe固态硬盘驱动器。我还有一个大型的内部西部数据硬盘(旋转驱动器),它也是通过SATA电缆连接的,还有几个外部旋转硬盘。

这是我从他们那里得到的:

代码语言:javascript
复制
Samsung SSD 256GB:     TRIM=Y, seekPenalty=N, RPM=1
Samsung SSD 500GB:     TRIM=Y, seekPenalty=N, RPM=1
PCIs SSD:              TRIM=Y, seekPenalty=?, RPM=0
Internal WD HDD:       TRIM=N, seekPenalty=?, RPM=0
External WD HDD:       TRIM=?, seekPenalty=?, RPM=?
External Cavalry HDD:  TRIM=?, seekPenalty=Y, RPM=?

如你所见,在我的例子中,对于所有6个驱动器来说,唯一正确的参数是TRIM。我并不是说你的情况也会如此。这只是我对我自己的硬盘的发现。

票数 24
EN

Stack Overflow用户

发布于 2014-04-29 19:25:25

我相信你用错了工具。而不是假设驱动器是SSD,你应该让你的代码在慢速和快速驱动器上都能很好地工作,例如,首先加载基本对象,然后再加载其他对象。在三年内发明了……可能会使常规硬盘比SSD更快,这会破坏您的代码。纯粹基于速度也适用于RAM磁盘,NFS,USB3.0-sticks和其他你没有或不能考虑的东西。

编辑:硬盘实际上并不等同于慢速固态硬盘。虽然它们在读取和写入方面都很快,但硬盘需要大量的时间来查找。因此,使用两种不同的访问策略是有意义的:通过随机访问SSD和顺序读取HDD来挑选重要数据。您可能只需要实现顺序策略就可以了,因为SSD应该仍然可以正常工作。不过,检查硬盘而不是固态硬盘更有意义,因为您需要特殊对待硬盘,而固态硬盘、RAMdisc、NFS等不应该受到寻道时间的影响,因此可以被同等对待。

票数 17
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23363115

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档