gpt4 book ai didi

c++ - 在 Windows 中检测 SSD

转载 作者:IT老高 更新时间:2023-10-28 22:31:30 26 4
gpt4 key购买 nike

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

  • 使用 SSD,我希望我的游戏服务器应用程序能够完全加载每个 map 和所有对象,以最大限度地提高性能。
  • 使用 HDD,我希望我的游戏服务器应用程序仅加载每个 map 中的基本对象和实体,而不加载外部对象。

我见过 http://msdn.microsoft.com/en-gb/library/windows/desktop/aa364939(v=vs.85).aspx ,这是一种判断某个驱动器是否是HDD、CD ROM、DVD ROM、Removable Media等的方法,但它仍然无法检测到主系统驱动器是否是SSD。我也看过Is there any way of detecting if a drive is a SSD? ,但该解决方案仅适用于 Linux。

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

在 Windows 中,使用 C++,有什么方法可以获取主系统驱动器是否为 SSD?

最佳答案

在完成一些研究并使用此页面上的答案信息后,这是我在 Windows 7 及更高版本中使用 C WinAPI 的实现:

//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,这里有一些定义:

#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 电缆连接的三星 SSD,以及一个使用 PCIe 插槽直接连接到逻辑板的 PCIe SSD 驱动器。我还有一个也通过 SATA 电缆连接的大型内部 Western Digital HDD(旋转驱动器)和几个外部旋转 HDD。

这是我为他们准备的:

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。我并不是说你的情况也会如此。这只是我对我拥有的驱动器的发现。

关于c++ - 在 Windows 中检测 SSD,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23363115/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com