I know people normally set themselves challenges like this at New Year, but I recently came across the book "Seven Languages in Seven Weeks: A Pragmatic Guide to Learning Programming". No, I've not read it, but the concept stuck in my head and so I decided to do something like it and get out of my bilingual shell and perl rut. The challenge is to write something useful - not just an educational toy - in 12 languages this year.
As I started in March, I decided to take January and February as gimmes and say they were satisfied by my constant use of perl and the shell. And then I started looking around for a small, simple, but above all useful task for this month.
Now, I have a somewhat elderly Mac Mini at home with more disks hanging off it than is reasonable, because I use that machine as my home media centre and fileserver as well as for taking automated backups of all my other machines using rsnapshot. Trouble is, taking backups does a ton of IO, and that machine has ... well, let's just say disk contention issues. If it's backing up a local filesystem to another disk, there's not enough IO for it to do things like record live TV off-air.
For a while I've been working around the problem with scripts that send SIGSTOP/SIGCONT signals to IO-hungry processes whenever it starts and stops recording something. That mostly works, but it has bad side-effects if it SIGSTOPs a process that as well as hammering the disk is also talking on the network. By the time the process is resumed with SIGCONT the network connection has timed out.
What I really want to do isn't to pause and resume processes, it's to just make them get the hell out of the way when something more important wants to use the disk. This may sound familiar to those of you who know about nice(1). That does exactly that sort of scheduling for CPU access. You can set a process to be less important, or if you are root you can set it to be more important, and then when the machine is under heavy CPU load your important processes will get more time on the CPU than the unimportant ones.
It's so similar that on some platforms there is also ionice(1), which allows you play those prioritisation games with IO. Unfortunately no one has ported that to Mac OS that I could find, so I decided to make that my small, simple, useful C project.
I didn't implement all the options that the Linux version has, because the relevant system call on Mac OS (and I believe on *BSD) doesn't appear to support getting/setting the IO priority of other processes. Thankfully I didn't need that anyway. My needs would be satisfied by just being able to start a process with a higher or lower IO priority.
And so, I give you ... ionice-MacOS, and tick language number 3 off my list. I would of course welcome patches and bug reports, and I hope you find it useful.
Of course, I expect it to be obsolete within a few years. From my testing it appears to have only minimal effect if you're using SSDs. With hindsight that's what you would expect, because what really slows spinning rust down under heavy load is the head thrashing back and forth for the next read or write. SSDs are truly random access so their performance doesn't degrade as much under load. I originally wrote this on my laptop, which has an SSD, and was most confused that it didn't really appear to do anything. It took me a while to realise what the problem was and move over to the Mini that prompted this whole exercise in the first place :-)