Life, Technology, and Meteorology

Month: October 2011

Using IOKit to Detect Graphics Hardware

After Seasonality Core 2 was released a couple of weeks ago, I received email from a few users reporting problems they were experiencing with the app. The common thread in all the problems was having a single graphics card (in this case, it was the nVidia 7300). When the application launched, there would be several graphics artifacts in the map view (which is now written in OpenGL), and even outside the Seasonality Core window. It really sounded like I was trying to use OpenGL to do something that wasn’t compatible with the nVidia 7300.

I’m still in the process of working around the problem, but I wanted to make sure that any work-around would not affect the other 99% of my users who don’t have this graphics card. So I set out to try and find a method of detecting which graphics cards are installed in a user’s Mac. You can use the system_profiler terminal command to do this:

system_profiler SPDisplaysDataType

But running an external process from within the app is slow, and it can be difficult to parse the data reliably. Plus, if the system_profiler command goes away, the application code won’t work. I continued looking…

Eventually, I found that I might be able to get this information from IOKit. If you run the command ioreg -l, you’ll get a lengthy tree of hardware present in your Mac. I’ve used IOKit in my code before, so I figured I would try to do that again. Here is the solution I came up with:

// Check the PCI devices for video cards. 
CFMutableDictionaryRef match_dictionary = IOServiceMatching("IOPCIDevice");

// Create a iterator to go through the found devices.
io_iterator_t entry_iterator;
if (IOServiceGetMatchingServices(kIOMasterPortDefault, 
                                 &entry_iterator) == kIOReturnSuccess) 
  // Actually iterate through the found devices.
  io_registry_entry_t serviceObject;
  while ((serviceObject = IOIteratorNext(entry_iterator))) {
    // Put this services object into a dictionary object.
    CFMutableDictionaryRef serviceDictionary;
    if (IORegistryEntryCreateCFProperties(serviceObject, 
                                          kNilOptions) != kIOReturnSuccess) 
      // Failed to create a service dictionary, release and go on.
				    // If this is a GPU listing, it will have a "model" key
    // that points to a CFDataRef.
    const void *model = CFDictionaryGetValue(serviceDictionary, @"model");
    if (model != nil) {
      if (CFGetTypeID(model) == CFDataGetTypeID()) {
        // Create a string from the CFDataRef.
        NSString *s = [[NSString alloc] initWithData:(NSData *)model 
        NSLog(@"Found GPU: %@", s);
        [s release];
		    // Release the dictionary created by IORegistryEntryCreateCFProperties.

    // Release the serviceObject returned by IOIteratorNext.

  // Release the entry_iterator created by IOServiceGetMatchingServices.

File Vault 2 on the 2011 MacBook Air

I recently upgraded to a 2011 MacBook Air. With the new Sandy Bridge processors having encryption routines built-in, I decided to try out File Vault 2 on Lion to see what kind of performance impact it would have while accessing the disk. Here’s the configuration of my MacBook Air for reference:

11″ MacBook Air (Summer 2011)
1.8Ghz Core i7
256GB SSD (Samsung model)

First the baseline. Before enabling File Vault, I did a quick test of writing a 10GB file and then reading it back.

Blade:~ mike$ time dd if=/dev/zero of=test bs=1073741824 count=10
10+0 records in
10+0 records out
10737418240 bytes transferred in 41.938686 secs (256026577 bytes/sec)
real 0m42.021s
user 0m0.005s
sys 0m6.827s
Blade:~ mike$ time dd if=test of=/dev/null bs=1073741824 count=10
10+0 records in
10+0 records out
10737418240 bytes transferred in 37.969485 secs (282790726 bytes/sec)
real 0m38.055s
user 0m0.005s
sys 0m5.069s

After enabling File Vault, the Mac restarts and it took about 50 minutes to finish the initial encryption.  While the encoding was taking place I was seeing roughly 95-120MB/sec transfer rates (190-240MB/sec combined read/write bandwidth), and it averaged about 45-50% CPU usage (% of a single core) during the encoding process.

So what how was performance with encryption enabled? Check this out…

Blade:~ mike$ time dd if=/dev/zero of=test bs=1073741824 count=10
10+0 records in
10+0 records out
10737418240 bytes transferred in 45.342448 secs (236807202 bytes/sec)

real 0m45.418s
user 0m0.001s
sys 0m7.721s
Blade:~ mike$ time dd if=test of=/dev/null bs=1073741824 count=10
10+0 records in
10+0 records out
10737418240 bytes transferred in 40.052954 secs (268080558 bytes/sec)

real 0m40.133s
user 0m0.001s
sys 0m4.032s

So read operations take a 5.5% hit, and write operations are 8.1% slower with File Vault 2 enabled. That’s a performance penalty I can live with for the extra peace of mind of my data being secure while traveling. Even better is the amount of CPU used was about the same whether encryption was enabled or disabled.

Performance summary:

File Vault Read Write
  Bandwidth CPU Bandwidth CPU
Disabled 269.69 MB/s 5.074s 244.16 MB/s 6.832s
Enabled 255.66 MB/s 4.033s 225.84 MB/s 7.722s

When the App Store thinks an app is installed when it really isn’t

I was trying to figure out a problem where the Mac App Store incorrectly thought an application was installed on my Mac. For the life of me, I couldn’t figure out why it thought that app was installed when it wasn’t. I tried deleting caches, restarting the Mac, Spotlighting for all apps with that name, all to no avail.

It ended up the problem was from the LaunchServices database. The App Store checks LaunchServices to see which apps are installed. Apparently LaunchServices still had a record of an application bundle even though it had been deleted. Here’s how to use the Terminal to check and see which apps are in the LaunchServices database:

A/Support/lsregister -dump

If you search through that verbose output and find an app that isn’t really there, you should rebuild the LaunchServices database. You can do that with the following command:

/A/Support/lsregister -kill -r -domain local -domain system -domain user

Hope this saves someone an hour or two of problem-solving…

© 2022 *Coder Blog

Theme by Anders NorenUp ↑