|
Как повысить скорость работы по сети AT91SAM7X256 |
|
|
|
Apr 22 2008, 07:21
|
Участник

Группа: Участник
Сообщений: 70
Регистрация: 5-12-06
Пользователь №: 23 146

|
Некоторое время назад я разрабатывал прошивку для этого процесора в которой была добавлена функциональность обмена данными по сети и USB. В качестве операционной системы использована FreeRTOS, TCP/IP стека - uIP. Сейчас потребовалось повысить скорость обработки событий устройством и оказалось, что по сети обмен данными идёт медленно. Так как я разбирался со всеми нюансами процесора и внутренностями сети самостоятельно, то мог пропустить какие-то важные моменты. Может кто увидит какие-то недостатки приведённого ниже алгоритма и подскажет как увеличить скорость работы устройства. Итак, в устройство периодически по сети передаются данные блоком размером приблизительно в 16-20 кБ. Эти данные записываются в масив памяти и по таймеру процесора обрабатываются. Когда я програмировал работу с сетью то передачу данных сделал блоками по 1500 Байт. Может я что-то не учёл, а может тогда вылезали другие ошибки, но при передачи блока большей длины у меня подвисал процесор (приёмный буфер установлен приблизительно на 2кБ), поэтому сделать так как в USB, когда я пишу в порт всё одним куском, на уровне USB контролера масив разбивается на части, а в процесоре я уже собираю данные (гарантированно доставленные), мне не удалось. Сейчас я смотрю, что похоже можно в обработчике прерываний от сети поставить свой код анализа входных данных и сделать похоже как в USB но не уверен - не буду ли я получать повреждённые даные, которые долго нужно будет перефрагментировать, проверять и т.д. Сейчас у меня скорость передачи данных приблизительно 2Мб/с по 100 мегабитной сети. Выглядит это приблизительно так (результат теперешнего анализа с помощью Ethereal): отсылается пакет размером в 1500 байт в процесор, приблизительно через 4мс (время работы стека и моего копирования порции в нужное место памяти) процесор отсылает однобайтный пакет-подтверждения о приёме данных (чтобы внешняя программа не начала посылать данные пока я не обработал предыдущую порцию - правильно ли?), приблизительно через (дома забыл логи поэтому тут цыфру не помню) толи 1, толи 0,1мс, отсылается следующая порция данных. В результате 16кБ передаётся приблизительно за 50мс. Долго, было бы хорошо хотя бы в 2 раза быстрее. Можно ли улучшить скорость? Я смотрел, что при обработке стек копирует данные из буфера контролера в память, а потом я копирую куда мне нужно. Может можно сразу копировать без промежуточного буфера, но не будут ли проблемы с проверкой ошибок при передаче? Может в стеке uIP можно убрать лишнюю обработку?
Пока что я в процессе анализа кода, может ещё что и сам найду, но за любые советы и предложения буду искренне благодарен.
|
|
|
|
|
 |
Ответов
|
May 3 2008, 20:30
|
Участник

Группа: Участник
Сообщений: 70
Регистрация: 5-12-06
Пользователь №: 23 146

|
Писать свой менеджер памяти, пока для меня будет сложно, поэтому разбираюсь с lwIP. Правда ещё попробую копировать по 4 байта. А пока такой вопрос - прошивка у меня компилируется в Thumb виде, согласно документации - использование ARM команд повышает быстродействие по сравнению с Thumb режимом. Пока что, при компиляции в ARM у меня система перестаёт работать - запускается нормально, но при попытке объявить (или запустить, ещё не разобрался) какую-либо задачу (использую FreeRTOS) - виснет. Соответсвенно вопрос - стоит ли этим баловаться (в смысле компиляцией в ARM) и в чём может быть проблема, что у меня подвисает система (может я не учёл что-либо общеизвестное)?
Сообщение отредактировал OlegHmt - May 3 2008, 20:31
|
|
|
|
|
May 3 2008, 21:26
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(OlegHmt @ May 3 2008, 23:30)  А пока такой вопрос - прошивка у меня компилируется в Thumb виде, согласно документации - использование ARM команд повышает быстродействие по сравнению с Thumb режимом. Справедливо для быстрой памяти, т.е. если ARM и Thumb инструкции будут выбираться одинаково быстро. Но для SAM7 это не так. Надо помнить что слабое место у SAM7 это флеш. В ARM режиме размер кода увеличивается в среднем на 30%, а это значит как минимум на 30% больше обращений к медленной флеш. Плюс в SAM7 применена технология ускоренной выборки для Thumb режима (по две Thumb инструкции за одно обращение к флеш). Т.е. при размещении программы во флеш Thumb режим заведомо в выигрыше. Кроме того при прочих равных (если код выполнять из RAM), для IP стека ARM режим практически не даст никакого выигрыша, возможно даже проиграет, из-за big-endian формата данных в пакетах и множества byte и half-word полей. В ARM режиме резонно написать некоторые особо критические функции, и разместить их в RAM. Но надо смотреть каждую конкретную функцию, т.к. например функция копирования приведенная выше и в ARM режиме и в Thumb компилуруется в 16 инструкций. Листинги привожу ниже: ARM mode Код 258: static void memcpy_burst( U32 *pDest, U32 *pSrc, U32 size ) 259: { 0x00001EC0 E92D0010 STMDB R13!,{R4} 0x00001EC4 E1A03002 MOV R3,R2 260: U32 wCnt = (size + 3) >> 2; // words count to be copied 0x00001EC8 E1A02003 MOV R2,R3 0x00001ECC E2822003 ADD R2,R2,#0x00000003 0x00001ED0 E1A02122 MOV R2,R2,LSR #2 261: do 262: { 263: *pDest++ = *pSrc++; 0x00001ED4 E1A03001 MOV R3,R1 0x00001ED8 E2831004 ADD R1,R3,#0x00000004 0x00001EDC E5934000 LDR R4,[R3] 0x00001EE0 E1A03000 MOV R3,R0 0x00001EE4 E2830004 ADD R0,R3,#0x00000004 0x00001EE8 E5834000 STR R4,[R3] 264: } while (--wCnt); 0x00001EEC E1A03002 MOV R3,R2 0x00001EF0 E2433001 SUB R3,R3,#0x00000001 0x00001EF4 E1A02003 MOV R2,R3 0x00001EF8 E3530000 CMP R3,#0x00000000 0x00001EFC 1AFFFFF4 BNE 0x00001ED4 265: } Thumb mode Код 258: static void memcpy_burst( U32 *pDest, U32 *pSrc, U32 size ) 259: { 0x00001EC0 B410 PUSH {R4} 0x00001EC2 1C13 ADD R3,R2,#0 260: U32 wCnt = (size + 3) >> 2; // words count to be copied 0x00001EC4 1C1A ADD R2,R3,#0 0x00001EC6 3203 ADD R2,#0x03 0x00001EC8 0892 LSR R2,R2,#2 261: do 262: { 263: *pDest++ = *pSrc++; 0x00001ECA 1C0B ADD R3,R1,#0 0x00001ECC 3104 ADD R1,#0x04 0x00001ECE 681C LDR R4,[R3,#0x00] 0x00001ED0 1C03 ADD R3,R0,#0 0x00001ED2 3004 ADD R0,#0x04 0x00001ED4 601C STR R4,[R3,#0x00] 264: } while (--wCnt); 0x00001ED6 1C13 ADD R3,R2,#0 0x00001ED8 3B01 SUB R3,#0x01 0x00001EDA 1C1A ADD R2,R3,#0 0x00001EDC 2B00 CMP R3,#0x00 0x00001EDE D1F4 BNE 0x00001ECA 265: }
|
|
|
|
|
May 4 2008, 11:06
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(defunct @ May 4 2008, 00:26)  В ARM режиме резонно написать некоторые особо критические функции, и разместить их в RAM. Но надо смотреть каждую конкретную функцию, т.к. например функция копирования приведенная выше и в ARM режиме и в Thumb компилуруется в 16 инструкций. Листинги привожу ниже: ... Вы уж простите, что лезу, но вменяемые компиляторы делают совсем другой код: Код 623 __arm void memcpy_burst( U32 *pDest, U32 *pSrc, U32 size ) 624 { 625 U32 wCnt = (size + 3) >> 2; // words count to be copied \ memcpy_burst: \ 00000000 032082E2 ADD R2,R2,#+3 \ 00000004 2221A0E1 LSR R2,R2,#+2 626 do 627 { 628 *pDest++ = *pSrc++; \ ??memcpy_burst_0: \ 00000008 ........ LDR R3,[R1], #+4 \ 0000000C ........ STR R3,[R0], #+4 629 } while (--wCnt); \ 00000010 012052E2 SUBS R2,R2,#+1 \ 00000014 FBFFFF1A BNE ??memcpy_burst_0 630 } \ 00000018 0EF0A0E1 MOV PC,LR ;; return Код 623 __thumb void memcpy_burst( U32 *pDest, U32 *pSrc, U32 size ) 624 { 625 U32 wCnt = (size + 3) >> 2; // words count to be copied \ memcpy_burst: \ 00000000 D21C ADDS R2,R2,#+3 \ 00000002 9208 LSRS R2,R2,#+2 626 do 627 { 628 *pDest++ = *pSrc++; \ ??memcpy_burst_0: \ 00000004 0B68 LDR R3,[R1, #+0] \ 00000006 0360 STR R3,[R0, #+0] \ 00000008 091D ADDS R1,R1,#+4 \ 0000000A 001D ADDS R0,R0,#+4 629 } while (--wCnt); \ 0000000C 521E SUBS R2,R2,#+1 \ 0000000E F9D1 BNE ??memcpy_burst_0 630 } \ 00000010 7047 BX LR А вообще-то, правильный memcpy должен работать в ARM и использовать STM/LDM (для больших кусков, для маленьких - развернутое копирование с переходом в нужное место) - тогда будет максимальное быстродействие, конечно, для выровненных данных, без этого - никуда. Цитата Кроме того при прочих равных (если код выполнять из RAM), для IP стека ARM режим практически не даст никакого выигрыша, возможно даже проиграет, из-за big-endian формата данных в пакетах и множества byte и half-word полей. Тут надо смотреть, чтобы хватало регистров. Если в тумбе не помещается в 8 регистров, то код резко ухудшается (и по размеру, и по быстродействию). По поводу big-endian - тоже не согласен, переворот байт в арм-режиме занимает меньше, чем в тумбе.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
May 4 2008, 13:58
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Rst7 @ May 4 2008, 14:06)  Вы уж простите, что лезу, но вменяемые компиляторы делают совсем другой код: Да дело не во вменяемости. Компилил вменяемым RVCT. Единственное забыл включить оптимизацию. Но даже если взять оптимизированный код приведенный вами, то в ARM получается 4 слова в ключевом цикле, в Thumb - 3. Так что все равно надо смотреть, что будет выполняться быстрее на SAM7 при размещении во флеш. Цитата Стандартные библиотеки писаны далеко не дураками, и не на C. Не важно на чем они писаны. Стандартные библиотеки поддерживают стандарт, стандартная memcpy просто обязана делать проверки на выровненность данных и не выходить за границы копируемого участка, чтобы ничего лишнего не перетирать. Надо ли отметить, что опустив эти проверки, получается дополнительный выигрыш в скорости? Цитата Не надо уходить от memcpy! Тут все по-своему правы. Уходить надо, там где важна скорость. В этой ветке скорость важна, значит уходить надо. Если важна универсальность, чистота и прогнозируемость кода, а на скорость можно забить, тогда можно и не уходить. Цитата(prottoss @ May 4 2008, 16:01)  Ну тогда объясните, чем memcpy лучше обмена списками вида Есть места где от копирования не уйти. Если DMA не умеет самостоятельно склеивать списки в пакет, то "memcpy" как минимум понадобится для копирования ethernet/ip header'a в каждый пакет. Цитата(zltigo @ May 4 2008, 13:45)  Для изначально "правильных" программ Thumb у меня ПРОИГРАЛ. По объему кода?
|
|
|
|
|
May 4 2008, 14:55
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(defunct @ May 4 2008, 21:26)  Ну как же нет. Ключевая фраза у Вас - "заполняем каждый блок своим хидером". Как заполняем? быстрее и логичнее всего - скопировать заранее подготовленный шаблон. Стало быть от копирования нельзя уйти. Хедер TCP я заполняю примерно так: Код /* Fill IP header */ hIP.vihl = socket->vihl; hIP.tos = socket->tos; hIP.tlen = SWAP16(sizeof(IP_HEADER) + sizeof(TCP_HEADER) + data_len); hIP.id = IP_GetNextPacketID(); hIP.frags = 0; hIP.ttl = socket->ttl; /* ttl */ hIP.protocol = IP_TCP; /* packet protocol */ hIP.src_ip = HOST_IP(); /* My IP */ hIP.dest_ip = arp_entry->ip; /* Dest IP */ /* Make checksum */ hIP.checksum = 0; hIP.checksum = (UINT16)~IP_MakeChecksum(0, &hIP, sizeof(IP_HEADER)); Код /* Fill TCP header */ hTCP.src_port = socket->src_port; hTCP.dest_port = socket->dest_port; hTCP.seqno = SWAP32(socket->send_unacked); hTCP.ackno = SWAP32(socket->receive_next); hTCP.hlen = (sizeof(TCP_HEADER) << 2) & 0xfc; hTCP.window = SWAP16(socket->window); hTCP.urgent = 0; if(flags) /* If flags are sets, we update them, differently we leave old */ hTCP.flags = flags; hTCP.checksum = TCP_MakeChecksum(&hIP, &hTCP, data); hIP и hTCP - соответсвенно блоки прамяти для IP и TCP заголовка, и мне не понятно, с какого шаблона я их сформирую:-) Ну и, думаю, что БЫСТРЕЕ и логичнее заполнить именно так
--------------------
|
|
|
|
|
May 4 2008, 14:59
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(prottoss @ May 4 2008, 17:55)  hIP и hTCP - соответсвенно блоки прамяти для IP и TCP заголовка, Ок, как часто у вас поменяется Ethernet header и сколько полей IP заголовка в пределах сессии? То, что не меняется - и будет шаблоном. Цитата и мне не понятно, с какого шаблона я их сформирую:-) Ну например в структуре "socket" резервируете 14 + 20 байт +2 байта GAP. единожды заполняете Eth/IP header - это будет шаблон. далее выделяете блок для Eth/IP, копируете туда шаблон спец функцией расчитаной на быстрое копирование выровненных блоков длиной 9 слов. Меняете поле Len и пересчитываете CS. Уже будет гораздо быстрее чем заполнение для каждого пакета.
|
|
|
|
|
May 4 2008, 15:33
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(prottoss @ May 4 2008, 18:27)  Я говорю не про не про Ethernet заголовок, который можно копировать и с помощью memcpy - ради бога (+- один попугай), а про то что ссказал Rst7 постом выше - про реку данных (или даже пакетов по 60 байт - их две реки в приличной сети), которые приходится постоянно копировать. Ну дык на 60-ти байтных пакетах +/- попугай ой как видно. На коротких пакетах уже и неактуально манипулировать четырьмя блоками, быстрее скопировать и передать одним. Цитата Ну в таком случае по вашему копирование двух указателей на данные а не самих данных тожде memcpy? Нет, я рассматривыаю только копирование частей тела пакета. Указатели это другой вопрос, который упирается в другую проблему - чем больше блоков и чем короче блоки тем неэффективнее используется DMA. (на кадый пересылаемый блок DMA 4 раза должен обратиться к дескриптору, если блоки сравнимы по длине с дескриптором * 2, то эффективность сильно упадет).
|
|
|
|
|
May 4 2008, 15:52
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(defunct @ May 4 2008, 22:33)  Ну дык на 60-ти байтных пакетах +/- попугай ой как видно.На коротких пакетах уже и неактуально манипулировать четырьмя блоками, быстрее скопировать и передать одним. Спорный вопрос. К тому же тема именно про большие объемы данных между приложениями, а не про скорость обмена ARP, DNS, BOOTP и прочими пакетами. Здесь как раз актуально то, что EMAC эти данные уже поместил в память, и у нас есть выбор - отдать данные приложению через memcpy, или как список указателей на блоки данных. Во втором случае программа получается намного сложнее и объемнее по коду, но и скорость доставки данных приложению намного выше.
--------------------
|
|
|
|
Сообщений в этой теме
OlegHmt Как повысить скорость работы по сети AT91SAM7X256 Apr 22 2008, 07:21 _dem 2 мегабита или 2 мегабайта ? Apr 22 2008, 07:26 OlegHmt Цитата(_dem @ Apr 22 2008, 10:26) 2 мегаб... Apr 22 2008, 08:03 Gemm Цитата(OlegHmt @ Apr 22 2008, 11:21) ...
... Apr 22 2008, 08:01 chds А транспорт UDP или TCP?
Мы юзали uCOS у нас с под... Apr 22 2008, 08:24 OlegHmt Цитата(chds @ Apr 22 2008, 11:24) А транс... Apr 22 2008, 08:36 prottoss Закончил примерно с месяц встраиваемый HTTP-сервер... Apr 22 2008, 09:04 OlegHmt Цитата(prottoss @ Apr 22 2008, 12:04) Зак... Apr 22 2008, 11:06  defunct Цитатав таких приложениях - использование memcpy
Д... Apr 22 2008, 13:08   aaarrr Цитата(defunct @ Apr 22 2008, 17:08) Да о... May 4 2008, 10:06    zltigo Цитата(aaarrr @ May 4 2008, 12:06) Не над... May 4 2008, 10:45    prottoss Цитата(aaarrr @ May 4 2008, 17:06) Не над... May 4 2008, 13:01     zltigo Цитата(prottoss @ May 4 2008, 15:01) Free... May 4 2008, 16:33      prottoss Цитата(zltigo @ May 4 2008, 23:33) Мне с... May 4 2008, 16:58      defunct Цитата(zltigo @ May 4 2008, 19:33) По быс... May 4 2008, 20:09 _dem Какую скорость требуется получить ?
на uip много ... Apr 22 2008, 14:33 OlegHmt Цитата(_dem @ Apr 22 2008, 17:33) Какую с... Apr 22 2008, 14:59            prottoss Цитата(defunct @ May 4 2008, 22:33) Указа... May 4 2008, 16:01             defunct prottoss
можете привести реальные цифры?
Сколько у... May 4 2008, 16:10              prottoss Цитата(defunct @ May 4 2008, 23:10) prott... May 4 2008, 16:48          blackfin Цитата(defunct @ May 4 2008, 19:20) Может... May 4 2008, 15:53           defunct Цитата(blackfin @ May 4 2008, 18:53) Это ... May 4 2008, 15:58            blackfin Цитата(defunct @ May 4 2008, 19:58) А с ч... May 4 2008, 16:37             zltigo Цитата(blackfin @ May 4 2008, 18:37) Если... May 4 2008, 16:52              blackfin Цитата(zltigo @ May 4 2008, 20:52) Ага, т... May 4 2008, 16:59               zltigo Цитата(blackfin @ May 4 2008, 18:59) Став... May 4 2008, 17:47                blackfin Цитата(zltigo @ May 4 2008, 21:47) Будет ... May 4 2008, 17:58                 zltigo Цитата(blackfin @ May 4 2008, 19:58) Меня... May 4 2008, 18:09    aaarrr Цитата(defunct @ May 4 2008, 17:58) Надо ... May 4 2008, 15:15 OlegHmt Понятно, тогда вопрос со стороны lwIP - можно ли и... May 3 2008, 22:30 defunct Цитата(OlegHmt @ May 4 2008, 01:30) Перво... May 3 2008, 23:12  OlegHmt Цитата(defunct @ May 4 2008, 02:12) А чем... May 4 2008, 07:36 Rst7 Цитатарасчитаной на быстрое копирование выровненны... May 4 2008, 15:19 Rst7 ЦитатаНу дык на 60-ти байтных пакетах +/- попугай ... May 4 2008, 15:43 Rst7 ЦитатаДлина блоков, применительно к SAM7X уже выбр... May 4 2008, 16:37 AlexandrY Возьмите процы от Freescale, в них IP-core Ethern... May 4 2008, 21:32 zltigo Цитата(AlexandrY @ May 4 2008, 23:32) RTO... May 5 2008, 08:07  AlexandrY Я ж не предлагаю отказаться от оси. Это ж святое... May 5 2008, 09:19 OlegHmt Ну и темку же я поднял
Поделюсь результатами кот... May 5 2008, 06:59 Rst7 ЦитатаВозьмите процы от Freescale, в них IP-core ... May 5 2008, 09:44 AlexandrY Не забывают, а не договаривают. Ну не всеж сразу в... May 5 2008, 10:24 Rst7 ЦитатаЕсть такой тэг VLAN, в MAC хидере. Используя... May 5 2008, 11:12 AlexandrY Вообще-то я просто прикалывался, но была одна мелк... May 5 2008, 13:20
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|