Jump to content

    

Большое число программных прерываний в ОС Linux при приеме информации по интерфейсу CAN на AM3517

На AM3517 при получении информации через интерфейс CAN (скорость передачи данных 1 Мбит/с шина CAN загружена около 80%) в ОС Linux генерируется много программных прерываний (около 45% загрузки процессора). Можно ли уменьшить количество программных прерываний при приеме?

Share this post


Link to post
Share on other sites

У вас случайно прерывания не по gpio идут? Если по gpio, то по фронту или по уровню?

Share this post


Link to post
Share on other sites
На AM3517 при получении информации через интерфейс CAN (скорость передачи данных 1 Мбит/с шина CAN загружена около 80%) в ОС Linux генерируется много программных прерываний (около 45% загрузки процессора). Можно ли уменьшить количество программных прерываний при приеме?

 

Уточните насчет программных прерываний. Может все-таки это реальные прерывания вызванные железом?

 

Если так, то число прерываний должно совпадать с числом принятых сообщений, переданых сообщений и еще какой-нибудь байды, которая разрешена. В контроллере CAN должен быть регистр маски прерывания. Вам следует разрешить в нем только прерывания относящиеся к делу. С передачей сообщений бывает следующая проблема. Флаг прерывания установлен всегда, пока буфер передатчика пуст. Иногда бывает флаг, что гасится тем или иным способом и не восстанавливается до следующей передачи. В устройстве могут присутствовать оба механизма. В первом случае необходимо маскировать прерывание передатчика в обработчике и разрешать, когда есть что передать.

 

Share this post


Link to post
Share on other sites
Уточните насчет программных прерываний. Может все-таки это реальные прерывания вызванные железом?

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

Я посмотрел драйвер TI тот что в mainline. Там обработка приема делается поллингом так что количество хардверных прерываний от кан интерфейса будет меньше либо равно количеству принятых пакетов.

С подтверждением прерываний может быть проблема это есть смысл проверить.

Также не исключено что высокая загрузка это норма для скорости 1М. Ядро обрабатывает принятые пакеты софтверно. Какой софт у вас получает пакеты ?

 

Share this post


Link to post
Share on other sites

Положим одна транзакция 100 бит. Значит при 80% загрузке в секунду приходит 8000 сообщений. А сколько у вас прерываний случается?

 

Share this post


Link to post
Share on other sites
Я посмотрел драйвер TI тот что в mainline. Там обработка приема делается поллингом так что количество хардверных прерываний от кан интерфейса будет меньше либо равно количеству принятых пакетов.

С подтверждением прерываний может быть проблема это есть смысл проверить.

Также не исключено что высокая загрузка это норма для скорости 1М. Ядро обрабатывает принятые пакеты софтверно. Какой софт у вас получает пакеты ?

 

Чтобы проверить прием была написана технологическая программа. Она ни чего не выводит, просто читает из сокета пакеты CAN в фоновом режиме и увеличивает счетчик принятых пракетов (по шине CAN непрерывно передается информация). Загрузку смотрю утилитой top. Так же привожу кол-во прерываний, кол-во принятых пакетов и размер принятых данных (cat /proc/interrupts ; ifconfig).

 

Mem: 32336K used, 204116K free, 0K shrd, 1568K buff, 6260K cached
CPU:   0% usr  21% sys   0% nic  35% idle   0% io   0% irq  42% sirq
Load average: 0.03 0.04 0.05 1/58 1009
 PID    PPID   USER   STAT   VSZ   %MEM   %CPU   COMMAND
1008   951    root       R     1472     1%       44%     ./a.out 
 622     2       root      SW       0       0%         6% [kworker/0:2]
 644     2       root      SW       0       0%         1% [ksdioirqd/mmc1]
1009   951    root       R     2844     1%         1% top 
  45      2       root      SW       0       0%         0% [irq/74-serial i]
 951   949     root       S     2844      1%        0% -sh 
 924     1       root       S     2732      1%        0% /sbin/syslogd -n -C64 -m 20 
 926     1       root       S     2668      1%        0% /sbin/klogd -n 
 917     1       root       S     2668      1%        0% /usr/sbin/telnetd 
 912     1  messageb   S     2436      1%        0% /usr/bin/dbus-daemon --system 
 949     1       root       S     2400      1%        0% login -- root      
 692     1       root       S <  2188      1%        0% /sbin/udevd -d 
 726   692     root       S <  2184      1%        0% /sbin/udevd -d 
 727   692     root       S <  2184      1%        0% /sbin/udevd -d 
 933     1       root       S      2064      1%        0% /usr/sbin/thttpd -d /srv/www -p 8080 -
   1       0       root       S      1628      1%        0% init [5]   
 588     2       root      SW         0       0%        0% [w1_bus_master1]
   5       2       root      SW         0       0%        0% [kworker/u:0]
 633     2       root      SW         0       0%        0% [mmcqd/0]
   3       2       root      SW         0       0%        0% [ksoftirqd/0]

 

root@am3517-evm:~# cat /proc/interrupts ; ifconfig
               CPU0
11:                 0        INTC  prcm
12:           1873        INTC  DMA
20:                 0        INTC  gpmc
24:   12114477        INTC  can0
25:                 2        INTC  OMAP DSS
37:       454780        INTC  gp timer
56:     1874385        INTC  omap_i2c
57:                 0        INTC  omap_i2c
58:         84972        INTC  omap_hdq
61:                 0        INTC  omap_i2c
71:                 1        INTC  musb-hdrc.0
72:                 0        INTC  serial idle
73:                 0        INTC  serial idle
74:         22509        INTC  serial idle, OMAP UART2
77:                 0        INTC  ehci_hcd:usb2
83:           2765        INTC  mmc0
86:       286560        INTC  mmc1
160:                0        GPIO  tps6507x
162:                1        GPIO  mmc1
184:                0        GPIO  ds1374
186:                0        GPIO  tca8418-keypad
224:                0        GPIO  mmc0
Err:                 0

can0      Link encap:UNSPEC  HWaddr 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00  
         UP RUNNING NOARP  MTU:16  Metric:1
         RX packets:12732263 errors:0 dropped:0 overruns:0 frame:0
         TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
         collisions:0 txqueuelen:10 
         RX bytes:88788609 (84.6 MiB)  TX bytes:0 (0.0 B)
         Interrupt:24

 

  1 #include <stdio.h>
 2 #include <sys/types.h>
 3 #include <sys/socket.h>
 4 #include <sys/ioctl.h>
 5 #include <net/if.h>
 6 
 7 #include <linux/can.h>
 8 #include <linux/can/raw.h>
 9 #include <string.h>
10 
11 /* At time of writing, these constants are not defined in the headers */
12 #ifndef PF_CAN
13 #define PF_CAN 29
14 #endif
15 
16 #ifndef AF_CAN
17 #define AF_CAN PF_CAN
18 #endif
19 
20 int main(int argc, char *argv[])
21 {
22     /* create a frame */
23     struct can_frame frame;
24     /* interface */
25     struct ifreq ifr;
26     /* number of te */
27     int bytes_read;
28     /* create the socket */
29     int skt = socket( PF_CAN, SOCK_RAW, CAN_RAW );
30     /* socket address */
31     struct sockaddr_can addr;
32     /* counter SFF */
33     unsigned long countSFF;
34     /* counter EFF*/
35     unsigned long countEFF;
36 
37     countSFF = 0;
38     countEFF = 0;
39     /* locate the interface you wish to use */
40     strcpy( ifr.ifr_name, "can0" );
41     ioctl( skt, SIOCGIFINDEX, &ifr ); /* ifr.ifr_ifindex gets filled with that device's index */
42     /* select that CAN interface, and bind the socket to it. */
43     addr.can_family = AF_CAN;
44     addr.can_ifindex = ifr.ifr_ifindex;
45     bind( skt, ( struct sockaddr * ) &addr, sizeof( addr ) );
46     while(1)
47     {
48         bytes_read = read( skt, &frame, sizeof( frame ) );
49         if( bytes_read < 0 )
50         {
51             printf( "CAN\n" );
52         }
53         else if ( bytes_read > 0 )
54         {
55             if( !( frame.can_id & 0x80000000U ) )
56             {
57                 countSFF++;
58             }
59             else
60             {
61                 countEFF++;
62             }
63         }
64     }
65 
66     return 0;
67 }

 

У вас случайно прерывания не по gpio идут? Если по gpio, то по фронту или по уровню?

 

Прерывания CAN осуществляется не по GPIO (фрагмент из команды "cat /proc/interrupts" 24: 12114477 INTC can0).

 

Положим одна транзакция 100 бит. Значит при 80% загрузке в секунду приходит 8000 сообщений. А сколько у вас прерываний случается?

 

Из "cat /proc/interrupts" следует, что за несколько минут, при загрузки шины CAN примерно 80% количество прерываний 12114477.

Share this post


Link to post
Share on other sites
Чтобы проверить прием была написана технологическая программа. Она ни чего не выводит, просто читает из сокета пакеты CAN в фоновом режиме и увеличивает счетчик принятых пракетов

...

Пока не вижу криминала. По вашим данным

12114477 INTC can0

12732263 RX packets

У вас 0,95 прерывания на пакет. Абсолютное большинство пакетов система успевает забрать и обработать до прихода следующего.

Возможно это нормальная работа socketcan. Там довольно накручено поэтому еще живы альтернативные решения, например lincan.

Вот бенчмарки

CAN driver benchmark

В бенчмарке есть хорошая идея - тестировать socketcan при одновременной нагрузке ethernet.

 

Положим одна транзакция 100 бит. Значит при 80% загрузке в секунду приходит 8000 сообщений. А сколько у вас прерываний случается?

По моим расчетам (я мог ошибиться) для скорости 1М максимальный темп передачи пакетов CAN при 100% загрузке шины и длине данных 8 бит составляет 63 и 81мкс для стандартных и расширенных пакетов соответственно что дает 15873 и 12345 пакетов в секунду.

У ТС загрузка шины 80% значит пакеты поступают каждые 79мкс.

Share this post


Link to post
Share on other sites
Пока не вижу криминала. По вашим данным

12114477 INTC can0

12732263 RX packets

У вас 0,95 прерывания на пакет. Абсолютное большинство пакетов система успевает забрать и обработать до прихода следующего.

Возможно это нормальная работа socketcan. Там довольно накручено поэтому еще живы альтернативные решения, например lincan.

Вот бенчмарки

CAN driver benchmark

В бенчмарке есть хорошая идея - тестировать socketcan при одновременной нагрузке ethernet.

 

 

По моим расчетам (я мог ошибиться) для скорости 1М максимальный темп передачи пакетов CAN при 100% загрузке шины и длине данных 8 бит составляет 63 и 81мкс для стандартных и расширенных пакетов соответственно что дает 15873 и 12345 пакетов в секунду.

У ТС загрузка шины 80% значит пакеты поступают каждые 79мкс.

Ваши рассчеты точнее моих. Я просто оценил порядок величины. Похоже система работает правильно. На каждый принятый пакет прерывание. Просто пакетов много.

 

Share this post


Link to post
Share on other sites
Ваши рассчеты точнее моих. Я просто оценил порядок величины. Похоже система работает правильно. На каждый принятый пакет прерывание. Просто пакетов много.

 

 

Проанализировал ситуацию (после прочтения предложений участников) и посмотрел в интернете насчет LinCAN наткнулся на одну интересную статью

CAN driver benchmark

В итоге пришел к выводу, что эта проблема драйвера и механизма доступа к нему, который реализовали сотрудники TI. Так что AM3517 с драйвером CAN от TI не обеспечивает низкую загрузку центрального процессора при приеме CAN пакетов сильно загруженной шины CAN. Буду уменьшать загрузку шины CAN, чтобы уменьшить нагрузку на центральный процессор при приеме. Всем спасибо за помощь.

Edited by Таратухин Сергей

Share this post


Link to post
Share on other sites
наткнулся на одну интересную статью

CAN driver benchmark

 

В статье описан типичный поллинг - ISR отрабатывает первый пакет а остальные (если они есть) отрабатываются в контексте soft irq (bottom half) или обычного процесса проверкой бита готовности данных. Для ethernet в ядре есть готовый механизм - NAPI. В общем техника широко применяемая.

Share this post


Link to post
Share on other sites
На AM3517 при получении информации через интерфейс CAN (скорость передачи данных 1 Мбит/с шина CAN загружена около 80%) в ОС Linux генерируется много программных прерываний (около 45% загрузки процессора). Можно ли уменьшить количество программных прерываний при приеме?

Не знаю везде ли, но у СТМ и майкрочипа фильтр стоит на ИД, принимает только те, которые нужно

Share this post


Link to post
Share on other sites
В статье описан типичный поллинг - ISR отрабатывает первый пакет а остальные (если они есть) отрабатываются в контексте soft irq (bottom half) или обычного процесса проверкой бита готовности данных. Для ethernet в ядре есть готовый механизм - NAPI. В общем техника широко применяемая.

 

Про методику читал (NAPI), но как им пользоваться не знаю (найти примеры не получилось). Если есть возможность рассказать про этот механизм подробнее буду очень благодарен.

 

Не знаю везде ли, но у СТМ и майкрочипа фильтр стоит на ИД, принимает только те, которые нужно

 

Фильтровать на аппаратном уровне могу (необходимо принимать примерно 15% от максимальной загрузки шины, при этом нагрузка центрального процессора действительно маленькая порядка 4-7%), но есть ситуации когда необходимо будет принять большой объем пакетов (примерно 80% загрузки шины).

Edited by Таратухин Сергей

Share this post


Link to post
Share on other sites
Проанализировал ситуацию (после прочтения предложений участников) и посмотрел в интернете насчет LinCAN наткнулся на одну интересную статью

CAN driver benchmark

В итоге пришел к выводу, что эта проблема драйвера и механизма доступа к нему, который реализовали сотрудники TI. Так что AM3517 с драйвером CAN от TI не обеспечивает низкую загрузку центрального процессора при приеме CAN пакетов сильно загруженной шины CAN. Буду уменьшать загрузку шины CAN, чтобы уменьшить нагрузку на центральный процессор при приеме. Всем спасибо за помощь.

 

У любого устройства есть свои пределы. CAN довольно неудобно обрабатывать на Линуксе. Она довольно неоднородна (имею ввиду сложность сообщений) и на каждое сообщение может требоваться индивидуальная реакция. Поэтому классический подход разгрузки прерываний в Линусе -- ПДП применить непросто, а может и невозможно.

 

Я уверен что процессор без ОС или с какой-нибудь реал-тайм ОС покажет лучшие результаты чем Линукс. Дело в том, что в Линуксе плата за универсальность долгий вход в обработчик прерывания.

 

Если вам будет интересно сделать CAN на другом процессоре, я лет 10 назад писал драйверы для RTOS SALVO на микрочипе. Причем там есть как с внутренним контроллером так и с подключенным как в статье по SPI. Mогу дать код.

 

Прерывание тупо кладет (если нет ошибок) в очередь, а тред уже забирает оттуда и обрабатывает. Система быстро выходит из прерывания, а значит имет лучше динамические характеристики.

 

Edited by Tarbal

Share this post


Link to post
Share on other sites
Про методику читал (NAPI), но как им пользоваться не знаю (найти примеры не получилось). Если есть возможность рассказать про этот механизм подробнее буду очень благодарен.

 

Посмотрите как сделано у Freescale для flexcan

http://lxr.free-electrons.com/source/drive.../flexcan.c#L564

Edited by sasamy

Share this post


Link to post
Share on other sites
Посмотрите как сделано у Freescale для flexcan

 

Кстати - в ванильном ядре и HECC NAPI поддерживает

http://lxr.free-electrons.com/source/drive.../ti_hecc.c#L604

 

насколько я понял

http://processors.wiki.ti.com/index.php/Si...29_Linux_Driver

 

у вас на процессоре такой контроллер используется.

 

PS я пропустил сообщение _3m

http://electronix.ru/forum/index.php?showt...t&p=1194005

он вам об этом уже говорил

Edited by sasamy

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this