Friday, November 25, 2011

Capturing USB2 video at 35MB/sec on Linux

Problem: many USB cameras require the full bandwidth of a USB2.0 port without any interruptions. Unfortunately the kernel power saving features in modern linux distributions periodically switch the processor into sleep states that disrupt USB data transfer and cause frames to be dropped. As an example our uEye 25fps 1.3Mpix machine-vision cameras will often drop 50% of frames, not ideal from an expensive camera. The problem is with the operating system and not the hardware. It has been documented on the uEye cameras by IDS. The same problem happens with the Kinect RGBD sensor, with 10-50% of frames frequently being lost.

We have observed this problem with Intel processors including Core 2, Core i5 and i7, and running on Ubuntu 9.10, 10.04, 10.10, 11.04. It would likely occur on any Linux distribution with kernel 2.6+.  The different sleep "C-states" on Intel's processors are discussed here. It might seem counter-intuitive, however a faster PC is likely to drop more video frames.

Verify: One way to verify if the C-states are causing the issue is to heavily load the CPU so it doesn't enter any low power modes. Start capturing video data and then run something CPU intensive, eg. `cat /dev/urandom | gzip > /dev/null` will load one or two CPU cores. If you have a 4 or 8 core processor you'll want to run this multiple times. If the video capture performance improves, this is your problem.

You can check what C-states your processor is entering using Intel's powertop command line tool (`sudo apt-get install powertop` and run `powertop`).

Some BIOSs allow you to set the maximum C-state, however the operating system (both Windows or Linux) appear to ignore this setting. For Ubuntu linux the intel_idle kernel module must be instructed to not to enter any sleep C-states below 0 (or 1). However, the module is loaded at boot and despite offering a /sys interface cannot be changed after loading:
echo 0 > /sys/module/intel_idle/parameters/max_cstate
bash: /sys/module/intel_idle/parameters/max_cstate: Permission denied

Solution: on Ubuntu you need to pass the max_cstate level as a parameter during boot. This is easily done by editing the Grub config file /etc/default/grub. Add or edit the GRUB_CMDLINE_LINUX line to say:

GRUB_CMDLINE_LINUX="processor.max_cstate=0 intel_idle.max_cstate=0"
or if you'd like to try and retain some power savings:

GRUB_CMDLINE_LINUX="processor.max_cstate=1 intel_idle.max_cstate=1"
Update your Grub menu with `sudo update-grub` and reboot.

After booting confirm the C-states have been disabled by running `powertop` again. It will either indicate the processor isn't entering the states greater than zero, or not show any C-state information. Unfortunately this will increase your PC's power usage, however that's not likely a problem if you're processing live video at 35MB/sec!

No comments:

Post a Comment