2010-01-17 36 views
7

Esiste un modo affidabile, rapido e deterministico (ad esempio non un punto di riferimento) per verificare se l'unità di sistema in cui è installato Mac OS X è un'unità a stato solido?Come rilevare SSD in Mac OS X?

C'è qualche altro indicatore di come il disco gestisce l'accesso parallelo? Sto provando ad aggiustare il numero di thread che il mio programma userà per le operazioni legate al disco.

Non sono interessato alla velocità raw o al tempo di ricerca, solo quale tipo di accesso, seriale o parallelo, è più veloce per l'unità. Non mi aspetto che gli utenti del mio programma usino iSCSI o RAID. SSD è il mio obiettivo, tutto il resto è bello da avere.

Device Characteristics di IOAHCIBlockStorageDevice contiene queste informazioni. Come posso leggerlo a livello di programmazione?


Finora ho capito va in questo modo: (segue è pseudocodice)

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); 
} 

Edit: Here's complete source code. Ho verificato che funzioni con Intel SSD e OCZ Vertex.

+0

Vedere anche http://stackoverflow.com/q/908188/545127 – Raedwald

risposta

5

Se si sta cercando di ottenere quel tipo di informazioni, è meglio supporre che sia IOKit.

È possibile provare alcuni dei suoi funzionalità utilizzando lo strumento da riga di comandoioreg o IORegistryExplorer.


Ecco un codice che potrebbe essere di aiuto. Raccoglie tutti i dischi rigidi che non sono RAID e non sono partizioni. Questo non è quello che vuoi, ma potrebbe farti iniziare.

#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 
+0

@porneL: ho aggiunto del codice che potrebbe aiutarti. –

+0

Grazie. È stato molto utile Senza di esso sarei inutilmente in grado di utilizzare l'API IOKit C++. – Kornel

+0

@porneL: sembra che tu l'abbia capito da solo. Suppongo che non ti serva più aiuto su questa domanda, vero? –

6

In realtà, penso che dovresti fare il percorso di benchmarking, perché risponde in modo più preciso alla tua domanda - non ti importa davvero che il disco sia un SSD, ti interessa solo che il disco sia veramente veloce. Cosa succede se l'utente utilizza una configurazione RAID veloce o un array Fibre Channel o utilizza iSCSI?

Basta leggere un po 'di settori casuali dalla sottostante/dev/diskX e se soddisfa le vostre esigenze è possibile trattarlo come un "Fast" drive

+2

Non ho alcuna misurazione della linea di base di "veloce". Dovrei eseguire due benchmark e confrontare. Il tempo speso per un benchmark affidabile potrebbe essere più lungo del tempo risparmiato scegliendo una strategia migliore. Un benchmark breve sarà inaffidabile, ed è difficile prendere in considerazione cache, latenza, ecc. Sto cercando una soluzione rapida e deterministica. Non ha bisogno di supportare altro che SSD. – Kornel

+1

Abbastanza corretto ma ti dirò questo, che questo è l'approccio che il sistema operativo di Windows assume: se vedi un po 'di statistiche, sarà molto facile da vedere; eseguire 2 test, uno con una lettura sequenziale all'indietro (ad esempio il settore 5,4,3,2, ecc.), quindi un secondo con una lettura di settore casuale.Se la varianza è fondamentalmente la stessa, hai un SSD; sui dischi meccanici saranno molto diversi –

0

Il numero di thread? 1 sta per sopraffare qualsiasi disco, SSD, RAID o meno. Il disco è lento, il processore è veloce. Il sistema operativo riordina le richieste del disco in ogni caso (o almeno dovrebbe) per ottenere i minimi movimenti della testa.

+0

Almeno su Windows e Linux, il sistema operativo non riordina le richieste di dischi per SSD –

+1

Nella mia esperienza OS X non fa un buon lavoro nella gestione dell'accesso al disco (l'accesso parallelo causa il criptaggio piuttosto che l'efficienza accesso). I thread multipli di I/O che accedono a SSD sono più veloci, forse solo perché c'è un sovraccarico della CPU, ma sono comunque più veloci. – Kornel