Высокая загрузка процессора при чтении из /dev/ttyACM0

#c #linux #kernel #driver

#c #linux #ядро #драйвер

Вопрос:

Я пытаюсь реализовать программу для считывания данных с тактильных датчиков, но у меня проблемы с высокой загрузкой процессора. Мне нужна помощь, чтобы уменьшить нагрузку на процессор.

Моя настройка

Я считываю данные с нескольких (до 16) тактильных датчиков. Датчики подключены через usb к моему компьютеру. В Linux эти устройства создают виртуальные последовательные порты: /dev/ttyACM0, /dev/ttyACM1, /dev/ttyACM2 …

Это то, что сообщает мне dmesg, когда я подключаю датчики (вывод для одного датчика):

 [ 321.998462] usb 2-2: отключение USB, номер устройства 3
 [ 327.541414] usb 2-2: новое высокоскоростное USB-устройство № 5 с использованием ohci_hcd
 [ 327.998963] usb 2-2: найдено новое USB-устройство, idVendor= 0471, idProduct=0889
 [ 327.998983] usb 2-2: строки нового USB-устройства: Mfr=1, Product=2, SerialNumber=3
 [ 327.998997] usb 2-2: Продукт: WTS
 [ 327.999011] usb 2-2: Производитель: Weiss Robotics
 [ 327.999024] usb 2-2: серийный номер: 0001
 [ 328.035356] cdc_acm 2-2:1.0: это устройство не может выполнять вызовы самостоятельно. Это не модем.
 [ 328.035424] cdc_acm 2-2:1.0: ttyACM0: устройство USB ACM

Я использую termios из termios.h для открытия последовательного устройства. Поскольку датчики имеют двоичный протокол, я устанавливаю устройство на неканонический и использую необработанный вывод. Датчики обеспечивают функцию периодической выборки, которая будет отправлять около 270 кадров данных в секунду.

Моя программа должна считывать и обрабатывать кадр с последовательного устройства, как только будет доступен полный кадр.

Проблема: высокая загрузка процессора

Это то, что в основном делает мой код:

 int fd = open("/dev/ttyACM0");
struct termios settings;
settings.xxx = ... // see full code for details
tcflush( fd, TCIFLUSH );
tcsetattr( fd, TCSANOW, amp;settings );

while(1)
{
    Frame f = readCompleteFrame(fd);
    processFrame(f);
}
 

Когда я перевожу устройство в режим блокировки чтения и выполняю свой цикл, загрузка процессора составляет около 15%. У меня есть отдельный поток для каждого датчика. Поскольку у меня несколько датчиков, каждый поток будет потреблять 15% одного ядра процессора.

Я профилировал программу с помощью команды time: почти все процессорное время тратится в ядре. Время пользователя близко к нулю.

Что я пытался исправить

  • Я перевел устройство в неблокирующий режим и использовал опрос из sys/poll.h. Загрузка процессора такая же: 15% на датчик.
  • Я перевел устройство в неблокирующий режим и использовал select из unistd.h. Тот же результат, что и при опросе.
  • Я перевел устройство в неблокирующий режим и продолжал вызывать read(fd); usleep(1); пока не получил некоторые данные. Это использует 50% ЦП, но не зависит от количества датчиков.

Полный тестовый код

Полный код, который я использовал для тестирования, можно найти здесь: http://pastebin.com/7dv0U2nN

Комментарии:

1. Я хотел бы увидеть здесь больше вопросов для начинающих, подобных этому.

Ответ №1:

Изучив код, вы, вероятно, мало что можете сделать, чтобы исправить это в своем приложении.

Вероятно, нагрузка вызвана проблемой в драйвере ядра или тем, как USB-устройство взаимодействует с ПК.