8

How to programmatically determine in C or C++ whether a specified path is on a flash (SSD) drive or a magnetic hard drive? I'm only interested in fixed drives, not removable ones, although it will be nice to determine the type of a removable drive as well.

I'm looking for a solution that queries what Windows thinks of the specified path and the physical drive it's on. No benchmarking! Also note that looking for TRIM support is not a valid approach thanks to the SMR HDDs.

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
  • https://stackoverflow.com/questions/1712642/how-to-determine-storage-type-ssd-drive-or-hhd-mechanical-drive-using-c-lang – stark Jun 20 '18 at 11:30
  • @David Heffernan: the suggested answer points in the right direction, but is very rudimentary. It doesn't show how to query the required class, let alone - how to do it for a specific drive, let alone - how to associate a file system path with a WMI drive info. At least reopen the question so I could answer it myself if or when I figure it out. – Violet Giraffe Jun 20 '18 at 13:00
  • 1
    If you want to post an answer, post one at the dupe – David Heffernan Jun 20 '18 at 14:41
  • 1
    The "dupe" is tagged 'C', not 'C++'. This question is also Windows API-specific. – jonspaceharper Jun 20 '18 at 16:37
  • @VioletGiraffe _Why_ do you feel the need to know this? If you can share that with us you might find you get some helpful insights on how to achieve whatever it is that underlies this question. – Paul Sanders Jun 21 '18 at 05:28
  • @PaulSanders: I have an image processing software that reads a bunch of image files and merges them. We've recently made changes to read and unpack several source images in parallel, it gives a serious performance boost. But only if the drive can handle multiple read queries efficiently. Turns out, while the new feature is 2x boost for SSDs and a slower boost for USB flash drives, it's 10x slow down for HDDs. So I need to detect the drive type to enable or disable parallel access. I thought or doing it by running a micro benchmark, but don't have any good ideas of how it can be done reliably. – Violet Giraffe Jun 21 '18 at 07:30
  • David provided you with an excellent duplicate. Nobody is going to show you how to write a WMI query in C++ code, that is already covered extensively in the MSDN documentation. And Google, search for "c++ wmi query". First hit is good. – Hans Passant Jun 21 '18 at 10:47
  • @HansPassant: I didn't say I can't do it, nor did I imply that I require someone else to do it for me. But calling the answers in the alleged dupe "excellent" suggests a pretty low quality of content on SO - lower than what we're accustomed to giving and receiving. Surprised to hear it from you of all people, I only remember you providing top-notch answers and comments. – Violet Giraffe Jun 21 '18 at 11:00
  • 1
    Hmya, users that can't be bothered to research their question is a significant problem lately. Nothing I can do about that of course. The dup tells you *exactly* what to do, google tells you how to do it. Take that ball and run with it. – Hans Passant Jun 21 '18 at 11:07
  • Why did you remove the context from your question? There was a reason we'd asked for it! – Lightness Races in Orbit Jan 14 '19 at 11:33
  • @LightnessRacesinOrbit: because it's not relevant to the question itself, and it turns the question into an unreadable wall of text. Better keep it simple and to the point. – Violet Giraffe Jan 14 '19 at 12:06
  • I disagree. It's relevant (which is why it was requested) and not too long. – Lightness Races in Orbit Jan 14 '19 at 12:06
  • https://stackoverflow.com/q/23363115 – Robert Harvey Nov 15 '21 at 22:45
  • 1
    More specifically, [this](https://stackoverflow.com/a/33359142). – Robert Harvey Nov 15 '21 at 22:47
  • 1
    See also this article [The Old New Thing](https://devblogs.microsoft.com/oldnewthing/20201023-00/?p=104395) *"How can I tell whether a file is on an SSD"* It checks for seek penalty. It works for both my HDD and SSD. – Barmak Shemirani Nov 16 '21 at 02:37
  • @BarmakShemirani: That looks like the actual answer, thank you. Please post it as such so that I can accept it. – Violet Giraffe Nov 18 '21 at 17:25

2 Answers2

5

From Old New Thing article: How can I tell whether a file is on an SSD?

This takes advantage of the trick we learned last time where you can make a storage query against a volume, and it will report the answer if the volume has a single extent.

We aren’t so much checking whether it’s on an SSD drive as we are checking whether seeks are free. That is true for SSDs, but it’s also true for RAM drives. But RAM drives are even faster than SSDs, so I think it’s okay to treat them as “super-awesome SSDs”...

This is a slightly modified version which doesn't need wil::unique_hfile class in the original article.

This implementation does not throw if path is invalid, it will report non-SSD for invalid path or network path.

#include <iostream>
#include <Windows.h>

HANDLE GetVolumeHandleForFile(const wchar_t* filePath)
{
    wchar_t volume_path[MAX_PATH];
    if (!GetVolumePathName(filePath, volume_path, ARRAYSIZE(volume_path)))
        return nullptr;

    wchar_t volume_name[MAX_PATH];
    if (!GetVolumeNameForVolumeMountPoint(volume_path,
        volume_name, ARRAYSIZE(volume_name)))
        return nullptr;

    auto length = wcslen(volume_name);
    if (length && volume_name[length - 1] == L'\\')
        volume_name[length - 1] = L'\0';

    return CreateFile(volume_name, 0,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
        nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
}

bool IsFileOnSsd(const wchar_t* file_path)
{
    bool is_ssd{ false };
    HANDLE volume = GetVolumeHandleForFile(file_path);
    if (volume == INVALID_HANDLE_VALUE)
    { return false; /*invalid path! throw?*/ }

    STORAGE_PROPERTY_QUERY query{};
    query.PropertyId = StorageDeviceSeekPenaltyProperty;
    query.QueryType = PropertyStandardQuery;
    DWORD count;
    DEVICE_SEEK_PENALTY_DESCRIPTOR result{};
    if (DeviceIoControl(volume, IOCTL_STORAGE_QUERY_PROPERTY,
        &query, sizeof(query), &result, sizeof(result), &count, nullptr))
    { is_ssd = !result.IncursSeekPenalty; }
    else { /*fails for network path, etc*/ }
    CloseHandle(volume);
    return is_ssd;
}

int main()
{
    std::wcout << IsFileOnSsd(L"C:\\") << "\n";
    std::wcout << IsFileOnSsd(L"D:\\") << "\n";
    return 0;
}
Barmak Shemirani
  • 30,904
  • 6
  • 40
  • 77
0

Long comment:

You don't have to benchmark. You can have a dynamic load-balance between all N worker threads.

Take run-time of each task of each thread. Also take amount of work each had done. Then compute the normalized performance of each thread such that 0.5 means half of whole work in a batch of tasks.

After each completion of batch of tasks, do the same computation and adjust the work distribution ratios of threads accordingly with their normalized performances.

If its an SSD then all threads should converge to equal partition of tasks. If its an HDD then one of the threads should converge to 1.0 normalized performance and other threads to zero.

Since this is performance-aware, it should not make 10x slowdown on SSD when other applications(such as antivirus or another image processing app) use it at the same time (Assuming that the SSD becomes the HDD under heavy random-access usage from many apps) and be future-proof for any asymmetric cpu design with different performances on cores.

huseyin tugrul buyukisik
  • 11,469
  • 4
  • 45
  • 97
  • Thank you for your input, but this is not an answer to the question. You're proposing an interesting method, but it is only applicable to a small subset of all the problems where my initial question is relevant. Usually you don't have enough small sub-tasks to do the balancing. – Violet Giraffe Nov 16 '21 at 12:32
  • If you take image reading + image processing as a single task, this method also optimizes overlapping of file read of a task with image processsing of another task which should make up to 2x further performance on top of parallelism on reading hdd/ssd. – huseyin tugrul buyukisik Nov 16 '21 at 16:56
  • You're not wrong, but our code is already highly pipelined. Which is why it's so easy to push an HDD over the edge and make everything 2x-4x slower. – Violet Giraffe Nov 16 '21 at 17:56