How to detect SSD in Mac OS X?

Kor*_*nel 9 macos cocoa solid-state-drive iokit

Is there a reliable, quick, deterministic way (i.e. not a benchmark) to check whether the system drive Mac OS X is on is a Solid State Drive?

Is there any other indicator how well disk handles parallel access? I'm trying to adjust number of threads that my program is going to use for disk-bound operations.

I'm not interested in raw speed or seek time, only which type of access – serial or parallel – is faster for the drive. I don't expect users of my program to use iSCSI or RAID. SSD is my focus, anything else is nice-to-have.

Device Characteristics of IOAHCIBlockStorageDevice contains this information. How can I read it programmatically?


So far I've figured out it goes like this: (following is pseudocode)

match = IOBSDNameMatching(kIOMasterPortDefault,0,"disk0s2");
IOServiceGetMatchingServices(kIOMasterPortDefault, match, &iterator);
while(entry = IOIteratorNext(iterator)) {
   do {
     entry = IORegistryEntryGetParentEntry(nextMedia, kIOServicePlane, &entry);
     dict = IORegistryEntryCreateCFProperty(nextMedia, 
            CFSTR(kIOPropertyDeviceCharacteristicsKey), kCFAllocatorDefault, 0);
     [dict objectForKey:CFSTR(kIOPropertyMediumTypeKey)];
   } 
   while(!dict && entry); 
}
Run Code Online (Sandbox Code Playgroud)

Edit: Here's complete source code. I've verified it works with Intel SSD and OCZ Vertex.

Ana*_*tts 7

Actually, I think you should go the benchmarking route, because it more accurately answers your question - you don't really care that the disk happens to be an SSD, you just care that the disk is really fast. What if the user is using a fast RAID setup, or a Fiber Channel array, or is using iSCSI?

只需从底层/ dev/diskX中读取一堆随机扇区,如果它符合您的要求,您可以将其视为"快速"驱动器

  • 足够公平,但是我将告诉您,这是Windows操作系统采用的方法-如果您看到一些统计数据,将很容易看到;运行2个测试,一个测试具有向后顺序读取(即扇区5、4、3、2等),然后第二个测试具有随机扇区读取。如果差异基本相同,则说明您有一个SSD。在机械磁盘上​​,它们将大相径庭 (3认同)
  • 我没有"快速"的基线测量.我必须运行两个基准并进行比较.通过选择更好的策略,花费在可靠基准上的时间可能比节省时间更长.短基准测试将是不可靠的,考虑缓存,延迟等是很棘手的.我正在寻找快速,确定的解决方案.不需要支持除SSD之外的任何东西. (2认同)

Geo*_*lly 5

如果您正在尝试获取此类信息,那么最好的猜测是IOKit.

您可以使用ioreg命令行工具或IORegistryExplorer尝试其中的一些功能.


这里有一些可能对您有帮助的代码.它获取所有不是RAID且不是分区的硬盘驱动器.这不是你想要的,但它可能会让你开始.

#import "TWDevice.h"

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <paths.h>
#include <sys/param.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/IOBSD.h>
#include <IOKit/storage/IOMedia.h>
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/Kext/KextManager.h>


@implementation TWDevice

@synthesize name, devicePath, size, blockSize, writable, icon;

+ (NSArray *)allDevices {
    // create matching dictionary
    CFMutableDictionaryRef classesToMatch;
    classesToMatch = IOServiceMatching(kIOMediaClass);
    if (classesToMatch == NULL) {
        [NSException raise:@"TWError" format:@"Classes to match could not be created"];
    }

    // get iterator of matching services
    io_iterator_t mediaIterator;
    kern_return_t kernResult;
    kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault,
                                                                      classesToMatch,
                                                                      &mediaIterator);

    if (kernResult != KERN_SUCCESS) {
        [NSException raise:@"TWError" format:@"Matching services did not succed."];
    }

    // iterate over all found medias
    io_object_t nextMedia;
    NSMutableArray *detectedDevices = [NSMutableArray array];
    while (nextMedia = IOIteratorNext(mediaIterator)) {
        NSMutableDictionary *properties;
        kernResult = IORegistryEntryCreateCFProperties(nextMedia,
                                                                                  (CFMutableDictionaryRef *)&properties,
                                                                                  kCFAllocatorDefault, 0);

        if (kernResult != KERN_SUCCESS) {
            [NSException raise:@"TWError" format:@"Getting properties threw error."];
        }

        // is it a whole device or just a partition?
        if ([[properties valueForKey:@"Whole"] boolValue] &&
            ![[properties valueForKey:@"RAID"] boolValue]) {
            TWDevice *device = [[[TWDevice alloc] init] autorelease];

            device.devicePath = [NSString stringWithFormat:@"%sr%@", _PATH_DEV, [properties valueForKey:@"BSD Name"]];
            device.blockSize = [[properties valueForKey:@"Preferred Block Size"] unsignedLongLongValue];
            device.writable = [[properties valueForKey:@"Writable"] boolValue];
            device.size = [[properties valueForKey:@"Size"] unsignedLongLongValue];

            io_name_t name;
            IORegistryEntryGetName(nextMedia, name);
            device.name = [NSString stringWithCString:name encoding:NSASCIIStringEncoding];

            …

            [detectedDevices addObject:device];
        }

        // tidy up
        IOObjectRelease(nextMedia);
        CFRelease(properties);
    }
    IOObjectRelease(mediaIterator);

    return detectedDevices;
}

@end
Run Code Online (Sandbox Code Playgroud)