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 :(
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 ;)
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?
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:
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.
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.
There’s also the PowerNap extension that provides some advanced RTC capabilities: http://dis-dot-dat.net/index.cgi?item=/code/powernap/