我想根据系统驱动器是否是固态硬盘来更改我的C++应用程序的性能和行为。示例:
使用固态硬盘,我希望我的游戏服务器应用程序完全加载每个地图和所有对象为了最大化performance.
我见过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++,有没有办法获取主系统驱动器是否是固态硬盘?
发布于 2016-05-13 00:42:03
您可以使用Microsoft WMI Class MSFT_PhysicalDisk
。4的媒体类型为固态硬盘,SpindleSpeed为0。
发布于 2015-10-27 10:46:50
在做了一些研究并使用了本页答案中的信息后,下面是我使用C WinAPI for Windows 7和更高版本的实现:
//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线连接的三星固态硬盘,以及一个使用PCIe插槽直接连接到逻辑板的PCIe固态硬盘驱动器。我还有一个大型的内部西部数据硬盘(旋转驱动器),它也是通过SATA电缆连接的,还有几个外部旋转硬盘。
这是我从他们那里得到的:
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。我并不是说你的情况也会如此。这只是我对我自己的硬盘的发现。
发布于 2014-04-29 19:25:25
我相信你用错了工具。而不是假设驱动器是SSD,你应该让你的代码在慢速和快速驱动器上都能很好地工作,例如,首先加载基本对象,然后再加载其他对象。在三年内发明了……可能会使常规硬盘比SSD更快,这会破坏您的代码。纯粹基于速度也适用于RAM磁盘,NFS,USB3.0-sticks和其他你没有或不能考虑的东西。
编辑:硬盘实际上并不等同于慢速固态硬盘。虽然它们在读取和写入方面都很快,但硬盘需要大量的时间来查找。因此,使用两种不同的访问策略是有意义的:通过随机访问SSD和顺序读取HDD来挑选重要数据。您可能只需要实现顺序策略就可以了,因为SSD应该仍然可以正常工作。不过,检查硬盘而不是固态硬盘更有意义,因为您需要特殊对待硬盘,而固态硬盘、RAMdisc、NFS等不应该受到寻道时间的影响,因此可以被同等对待。
https://stackoverflow.com/questions/23363115
复制相似问题