It's important to realize that the job of mdworker is observing changes in the file system and reflect those changes into Spotlight's content indexes. That's not the problem. The problem is that, by default, mdworker appears to be running with the same priority and I/O priority than most your user space processes. Depending on your computer usage pattern, you may or may not observe any performance degradation caused by mdworker: in fact, I bet most users won't notice it, but when you do, it's a real pain.
In my case, I notice a huge performance degradation when using programs that can generate massive changes in the file system in a short period of time, such as Adobe Lightroom or Apple Aperture. I found myself watching the Lightroom window freezing so often, waiting for mdworker to finish its job and relinquish some resources, that I decided to look for a solution to this problem.
Fortunately, there's a quick workaround that works pretty well and addresses the core issue with mdworker: its priority.
OS X Tiger (10.4) introduced a service management framework, launchd, that essentially replaced a bunch of legacy service handling daemons such as init, inetd, xinetd, and all the related scripts. launchd centralizes service management and, as such, it also centralizes service configuration using a property list files. If you're new to OS X development, property list essentially are XML files using a schema defined by Apple.
If you want to customize the behavior of an OS X service, you can just modify the corresponding configuration file without any deeper knowledge of the service behavior. You can read the launchd.plist official documentation for a list of valid configuration keys.
Although we're focusing on mdworker here, the concepts herein can be applied to any service you'd like to configure.
Modifying a Service Configuration File
Service configuration files are currently stored in two directories:- /System/Library/LaunchAgents
- /System/Library/LaunchDaemons
First of all, you've got to locate the configuration file of the service you want to customize. Open the file in your favorite XML editor and carefully modify it. An invalid property list file will result in launchd rejecting the invalid configuration and the corresponding service failing to start.
With the release of XCode 4, the Property List Editor is no longer available as a separate application and all the editing is performed inside XCode. If you've got XCode, it's very easy to modify property list files using its GUI. If you haven't got XCode, it's a bit overkill to install such a huge application only to modify a property list file. I'd rather use an alternative XML editor and carefully review the changes before applying them.
In any case, I'm including my entire configuration file in this blog post so that you can just copy it over yours.
Reducing the mdworker Priority
The configuration file of mdworker (the Spotlight's indexer) is:/System/Library/LaunchDaemons/com.apple.metadata.mds.plist
As we can see in launchd.plist documentation, we can take advantage of two configuration keys to lower the working priority of this process:
- LowPriorityIO
- Nice
For CPU-intensive processes, Nice can be the solution, since it specifies the service's scheduling priority. The higher the nice level, the lower its priority. Nice can take values in the [-20, 20] range.
Since mdworker is also a I/O-intensive process, we will use the LowPriorityIO configuration key as well. This configuration key takes a boolean value and, when set to true, it instructs the kernel to consider the process as low priority when performing file system I/O. That's just what we need to avoid mdworker jeopardizing our resources when using I/O intensive processes such as Adobe Lightroom.
The resulting configuration file is the following:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>KeepAlive</key>
<true/>
<key>Label</key>
<string>com.apple.metadata.mds</string>
<key>ProgramArguments</key>
<array>
<string>/System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Support/mds</string>
</array>
<key>MachServices</key>
<dict>
<key>com.apple.metadata.mds</key>
<true/>
<key>com.apple.metadata.mds.xpc</key>
<true/>
<key>com.apple.metadata.mds.xpcs</key>
<true/>
</dict>
<key>SoftResourceLimits</key>
<dict>
<key>NumberOfFiles</key>
<integer>2048</integer>
</dict>
<key>HardResourceLimits</key>
<dict>
<key>NumberOfFiles</key>
<integer>2048</integer>
</dict>
<key>LowPriorityIO</key>
<true/>
<key>Nice</key>
<integer>20</integer>
</dict>
</plist>
Here's the same file as seen in XCode:
XCode 4 - Property List Editor (Integrated) |
Conclusion
The next time the service restarts the new configuration will take effect. The easiest way to do it is just reboot. mdworker will now work as usual, but won't steal your resources as aggressively as before.You can check that mdworker is now running with a lower priority examining ps output (6th and 7th column):
$ ps -axl | grep mdworker
UID PID PPID F CPU PRI NI SZ RSS WCHAN S ADDR TTY TIME CMD
501 234 232 84004 0 4 17 2485976 25916 - SN ffffff800f0bbdc0 ?? 3:56.98 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Versions/A/Support/mdworker -s mdworker -c MDSImporterWorker -m com.apple.mdworker.pool.0
89 881 879 84004 0 4 17 2479740 6420 - SN ffffff800fd84200 ?? 0:00.14 /System/Library/Frameworks/CoreServices.framework/Frameworks/Metadata.framework/Versions/A/Support/mdworker -s mdworker -c MDSImporterWorker -m com.apple.mdworker.pool.0