I'm trying to implement a program to read data from tactile sensors, but I have problems with high cpu load. I need help to reduce the cpu load.
My Setup
I'm reading data from several (up to 16) tacilte sensors. The sensors are connected via usb to my pc. In Linux these devices create virtual serial ports: /dev/ttyACM0, /dev/ttyACM1, /dev/ttyACM2 ...
This is what dmesg tells me, when I plug in the sensors (output for one sensor):
[ 321.998462] usb 2-2: USB disconnect, device number 3 [ 327.541414] usb 2-2: new full-speed USB device number 5 using ohci_hcd [ 327.998963] usb 2-2: New USB device found, idVendor=0471, idProduct=0889 [ 327.998983] usb 2-2: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 327.998997] usb 2-2: Product: WTS [ 327.999011] usb 2-2: Manufacturer: Weiss Robotics [ 327.999024] usb 2-2: SerialNumber: 0001 [ 328.035356] cdc_acm 2-2:1.0: This device cannot do calls on its own. It is not a modem. [ 328.035424] cdc_acm 2-2:1.0: ttyACM0: USB ACM device
I use termios from termios.h to open the serial device. As the sensors have a binary protocol I set the device to non-canonical and use raw output. The sensors provide a periodic sampling feature which will send about 270 frames of data per second.
My program should read and process the frame from the serial device as soon as the complete frame is available.
The Problem: high cpu load
This is what my code basically does:
int fd = open("/dev/ttyACM0");
struct termios settings;
settings.xxx = ... // see full code for details
tcflush( fd, TCIFLUSH );
tcsetattr( fd, TCSANOW, &settings );
while(1)
{
Frame f = readCompleteFrame(fd);
processFrame(f);
}
When I put the device into blocking read mode and execute my loop, the cpu load goes to about 15%. I have a separate thread for each sensor. As I have multiple sensors each thread will consume 15% of one cpu core.
I profiled the program using the time command: Nearly all of the cpu time is spent in the kernel. The user time is next to zero.
What I tried to fix it
- I put the device into non-blocking mode and used poll from sys/poll.h. The cpu load is the same: 15% per sensor.
- I put the device into non-blocking mode and used select from unistd.h. Same result as poll.
- I put the device into non-blocking mode and kept calling read(fd); usleep(1); until i got some data. This uses 50% cpu, but is independant of the number of sensors.
Complete test Code
The complete code I used for testing can be found here: http://pastebin.com/7dv0U2nN