views:

524

answers:

2

I would like a particular set of Python subprocesses to be as low-impact as possible. I'm already using nice to help limit CPU consumption. But ideally I/O would be limited as well. (If skeptical, please humor me and assume there is value in doing this; it doesn't matter how long they take to run, there can be a lot of them, and there is higher-priority stuff (usually) going on on the same machine, etc.)

One possibility appears to be ionice. Are there any existing Python packages for invoking ionice (Google didn't turn up anything)? It wouldn't be difficult to write code to simply run the ionice command; but I'd prefer to avoid writing code that someone else has written/tested; sometimes there are subtle edge cases, etc. And, is there just a better way to limit I/O consumption?

The man page for ionice suggests that the ionice value can be affected by the nice value, but running this Python 2.6 script appears to disprove that, even for child processes where the nice value is inherited:

#!/usr/bin/env python

import os
import multiprocessing

def print_ionice(name):
    print '*** ', name, ' ***'
    os.system("echo -n 'nice: '; nice")
    os.system("echo -n 'ionice: '; ionice -p%d" % os.getpid())

for niced in (None, 19):
    if niced: os.nice(niced)
    print '**** niced to: ', niced, ' ****'
    print_ionice('parent')
    subproc = multiprocessing.Process(target=print_ionice, args=['child'])
    subproc.start()
    subproc.join()

Which has the following output:

$ uname -as
Linux x.fake.org 2.6.27-11-server #1 SMP Thu Jan 29 20:13:12 UTC 2009 x86_64 GNU/Linux
$ ./foo.py
**** niced to:  None  ****
***  parent  ***
nice: 0
ionice: none: prio 4
***  child  ***
nice: 0
ionice: none: prio 4
**** niced to:  19  ****
***  parent  ***
nice: 19
ionice: none: prio 4
***  child  ***
nice: 19
ionice: none: prio 4
+3  A: 

Why not have whatever launches the processes do the ionice on them (i.e., run them with ionice) rather than having them ionice themselves? It seems a whole lot cleaner.

MarkusQ
I effectively want to fork and not exec (e.g., using the 'multiprocessing' module); unsure where ionice would fit in there. The children *could* call ionice -p<pid> -cblah (on themselves, e.g., using os.system).
Jacob Gabrielson
+2  A: 

Hm.

As a start pointer, you should find what syscall number are the ioprio_set and ioprio_get system calls in your kernel. I'd suggest you check in /usr/include/asm/unistd_32.h or /usr/include/asm/unistd_64.h, depending on your kernel arch; if not there, start with the suggestion of the syscall(2) man page, which should be /usr/include/sys/syscall.h and work your way down includes.

Given that, you should use ctypes, à la:

def ioprio_set(which, who, ioprio):
    rc= ctypes.CDLL('libc.so.6').syscall(289, which, who, ioprio)
    # some error checking goes here, and possibly exception throwing

That's it, more or less. Have fun :)

ΤΖΩΤΖΙΟΥ