Playing with Realtime with Python

For a little app, I need to send stream over UDP at a fixed rate. I have done severals tests w/ some buffers and sleep(), but I can’t achieve the desired speed. Mainly because sleep() doesn’t provide a stable enought result.

I decided to look at this a little deeply, and decided to use /dev/rtc to do the trick. Here a little example of the stuff.

from  fcntl import ioctl
import os, time

# some linux kernel header
RTC_IRQP_SET = 1074032652
RTC_PIE_ON =  28677
RTC_PIE_OFF = 28678

# open the realtime clock
f = open ("/dev/rtc", "r")
fd = f.fileno()

# 2048 freq
ioctl(fd,RTC_IRQP_SET,2048)
ioctl(fd,RTC_PIE_ON,0)

t0 = time.time()
interupt = 0

# the read will block until the next interrupt.
while interupt < 1000 :
    os.read(fd,4)  # 4 = size of double
    interupt = interupt + 1

delta = time.time() - t0
print interupt / delta

# drop the scheduler
ioctl(fd,RTC_PIE_OFF,0)

This is quite accurate enought, the only issue is that I’m unable to call the sched_setscheduler() from Python right now. So, if the host isn’t loaded I get the 2048 interrupts.. but it can be less :(

Update:
The sched_setscheduler can be done w/ a simple pyrex extension:

cdef extern from "sched.h":
struct sched_param:
int sched_priority
int sched_setscheduler(int pid, int policy,sched_param  *p)

SCHED_FIFO = 1

def switchRTCPriority(nb):
cdef sched_param sp
sp.sched_priority = nb
sched_setscheduler (0,SCHED_FIFO , &sp);

After this quick Pyrex hack, I now have a accurate realtime interrupt in Python ;)



Related Posts

5 thoughts on “Playing with Realtime with Python

  1. I don’t understand the structure of your code. I also fail to see where you make use of the Pyrex module.
    Could you elaborate further?

    Alain

  2. The structure is quite simple, just set the right value in /dev/rtc, and after call the read on it. It will block until you receive an interrupt.

    The pyrex code, simply implement a switchRTCPriority(nb), that should be call before setting the rtc. (I added this after, so it isn’t really clear)

    The right code should be:

    import os, time
    
    # some linux kernel header
    RTC_IRQP_SET = 1074032652
    RTC_PIE_ON =  28677
    RTC_PIE_OFF = 28678
    
    
    # get a hight priority
    switchRTCPriority(60)
    
    # open the realtime clock
    ....
    
  3. Have you considered the possibility of using the Linux networking stack to limit your send rate? This would greatly reduce the CPU load induced by your idle loop, and allow the networking stack to cooperatively provide QoS with any other network streams active in the system.

    You main loop could then simply become a select() that blocks until your socket is writeable, and everything else is delegated back to the system.

    I couldn’t even begin to advise you as to how to go about setting up Linux to do this, although I believe TLDP has several HOWTOs on the subject.

    HTH,

    David.

  4. Hi, David

    This is a quite nice way to do of course. But first the idle loop doesn’t eat a lot of CPU (This surprise me a lot too, but this stuff is really efficient).

    The main issue, is that Linux and QOS is a pure nightmare. I setup several QOS in a past life using some BSD (pf based on netbsd).. and the syntax is clean, and works out of the box. On Linux you have bunch of QOS module, each doing a different stuffs..

    On the other side, I think I gonna build a traffic shapper in pure python. I’ve been to busy right now.. but perhaps a day until I get too old.

    Enjoy ;)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>