Перейти к содержанию
    

Отнюдь. В реальности буфера под фреймы выделяются выровненые а нормальная разборка ведется по наложенной структуре.

Это все так, но давайте рассмотрим случай когда пакеты идут с разных интерфейсов. Eth и PPP-Link (у одного перед IP header'ом 14 байт eth заголовка, у второго длина ppp заголовка зависит от настроек канала и может быть от 1 байта и выше... И там и там "по-умолчанию" IP заголовок получается невыровненым относительно начала пакета. А мы хотим проверить по маске быстро (чтобы "одной" командой):

 

*(U32 *)(packet + offset)   &  mask

 

Вот тут недостача align exception'а может сыграть злую шутку

 

 

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

Я безотносительно, ни к чьему коду не привязываясь. Просто интересно получить ответы на следующие вопросы:

 

Что у NXP есть по поводу misalign'a - как они предлагают обрабатывать такие ситуации в run-time (какие-нить их доки на этот счет)?

Может быть есть сводка в каких NXP чипах align exception поддерживается, а в каких нет?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это все так, но давайте рассмотрим случай когда пакеты идут с разных интерфейсов.

Можно многое, что искусственно придумать и еще больше "реализовать" по дурному - не вопрос :). В данном конкретном случае сразу могу спросить, а какого они идут в один и тот-же буфер? Давайте не будем развивать эту тему. Я ведь тоже все это не просто так сказал - в частности протоколы, например, входящие в стеки SS7, ISDN, V5.2, ... реализовывалитсь на разных платформах, портировались, инкапсулировались а в них разборки на порядки сложнее и ветвистее нежели IP, пусть даже он Ethernet+VLAN и т.д.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

*(U32 *)(packet + offset)   &  mask

 

Вот тут недостача align exception'а может сыграть злую шутку

Для таких случаев нужно создавать дополнительный U32 (например U32ua) внутри pragma pack (1). Это конечно не совместимость снизу вверх, но так можно написать универсальный код, правильно работающий на 8, 16 и 32 платформах.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В данном конкретном случае сразу могу спросить, а какого они идут в один и тот-же буфер?

Ну... потому что на IP уровне и те и те - IP. Да и чтоб расход памяти соптимизировать - пользовать один и тот же пул пакетов.

 

Давайте не будем развивать эту тему.

ОК

 

Для таких случаев нужно создавать дополнительный U32 (например U32ua) внутри pragma pack (1).

Не, такое - не пойдет. Тормозить будет, т.к. будет LDRB вместо LDR.

Мы ж скорости хотим. :) - если скорость не нужна можно везде все упаковать и будет ARM как восьмибитник работать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не, такое - не пойдет. Тормозить будет, т.к. будет LDRB вместо LDR.

Мы ж скорости хотим. :) - если скорость не нужна можно везде все упаковать и будет ARM как восьмибитник работать.

Ещё как пойдёт. Только использовать его надо именно в местах разбора буферов, в которых есть хоть малейшая вероятность невыровненности данных. Для работы с обычными переменными (статика, локальные) надо применять тип без прагмы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Все верно, у меня практически такие-же вещи по полной программе, НО все это не делалось единовременно вдруг с 8 на 32. При переходе ровным счетом ни одной проблемы в работе, именно с выравниванием не вызвало. Все отсеялось в процессе портирования при работе с исходниками.

Да, понятно, что на любом проекте крупнее среднего будет практически то же самое. Но у нас некоторая разница в подходах - Вы пишете что "все отсеялось" (ну так уж и все?), а я пишу - "1% остался". И вчера мне мои прикладники показали часть от этого "1%".

 

Посторяю - 200K чего? Кода или сишных строк??? Вот прям сейчас сижу в начале обычного проекта: ARM 94 файла 40767 текстовых строк из них всего 21943 стороки с кодом. Бинарник 134504 байта. Процентов

Дело было давно (в районе 2000-го) - из любопытства написал простой скриптик подсчета текстовых строк на Perl и прогнал на каталоге с исходниками для одной платформы (AVR, кажись). Тогда вышло около 150К - всех текстовых строк - с хидерами, C- кодом, комментариями, но без документации, makefiles и всяких вспомогательных скриптов (то отдельно все лежит). Сейчас не считал, по минимуму полагаю 200K.

Эти все 200К написаны прикладниками - без платформозависимого и системного кода, который пишу я. ИМХО, по стилю там тяжеловато - с комментами напряг, и макросов засилье изрядное, так что текст - "плотненький", сколько строк именно с кодом - не скажу, но тоже не менее 50%.

 

несколько лет. Естественно есть и уже перевалившие за 300K бинарника. Говорите, что у Вас "200К строк С-шного кода" причем, как ранее говорили, для чего-либо врезультате влезающего в AVR128 и затем портированых?

Это где я говорил что все 200К строк исходников одновременно влезают в 128К? Я сказал, что в сумме есть 200К строк из которых получается сотня различных вариантов путем условной компиляции.

 

Процентов 15% пришло с 8bit. Еще 20% вообще сразу живут на всех платформах

В-о-о-о-т. А у нас 75-90% пришло с 8-битника и эти же 75-90% живут на всех 8/32-битных платформах. Из оставшихся 10-25% для 32-битников - 80% (ОС, стеки) тоже живут на всех 32-битных платформах. Итого - у меня "не живущая" и заново пишущаяся для платформы часть составляет 2-5% - против Ваших 65%. Отсюда и Ваш совет - "при портировании надо пересмотреть код". Когда пишешь заново - не вопрос - само собой так получается, а вот когда оно уже написано, отлажено и работает - хто ж в здравом уме туда полезет?

 

Так вот не верю.

Чему именно? Что бывают проекты где 75-90% процентов платформо-независимо и может жить на 8/16/32?

 

 

Не, такое - не пойдет. Тормозить будет, т.к. будет LDRB вместо LDR.

Мы ж скорости хотим. :) - если скорость не нужна можно везде все упаковать и будет ARM как восьмибитник работать.

У меня эту проблему в общем случае решить не удалось. Для TCP/IP у меня такая реализация:

LW_INLINE_FORCED
DWORD
lw_ipload(
    PLW_IP_ADDR ptr)
{
#if LW_ALIGNED_HDR
    //
    // Вариант перестановки для выравненного доступа
    //
    DWORD    v, t1, t2;

    v = *(PDWORD)ptr;

    t1 = v ^ ((v << 16) | v >> 16);        // t1 =  2143 ^ 4321
    t2 = (v >> 8) | (v << 24);            // t2 =  1432 
    t1 = t1 & 0xFF00FFFF;                // t1 =  2043 ^ 4021
    return t2 ^ (t1 >> 8);                // 1432 ^ (0204 ^ 0402)
#else
    //
    // Вариант перестановки для невыравненного доступа
    //
    return  (DWORD)((PBYTE)ptr)[3]
         | ((DWORD)((PBYTE)ptr)[2] << 8)
         | ((DWORD)((PBYTE)ptr)[1] << 16)
         | ((DWORD)((PBYTE)ptr)[0] << 24);
#endif
}

 

Для PowerPC в bigendian это выглядит так:

LW_INLINE_FORCED
DWORD
lw_ipload(
    PLW_IP_ADDR ptr)
{
    return *(PDWORD)ptr;
}

 

Если в проекте есть хоть один сетевой интерфейс для которого поле IP может быть невыравнено, то в кофигурации указан LW_ALIGNED_HDR нулевой. Но обычно есть только один ethernet, я стараюсь чтобы было выравнивание (гы, на SAM7X - получилось выровнять пакеты при приеме, на LPC - нет :)) и работает выравненный вариант.

 

Пример работы с полем:

{
    DWORD ip;

    ip = lw_ipload(&iphdr->ipsrc);
    //
    // Делаем с IP чего надо
    //
{

 

Но тут как раз проблема ловли исключений не так остро стоит - этот код свой и писался изначально под разные платформы с разной endianess и alignment. Проблема острее стоит в портированном "старье".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Чему именно?

Я более, чем четко сказал чему, что и подтвердилось. Если считать строки "по Вашему", то у меня их в одном из проектов и 500K, пожалуй наберется только это дутые строки. Из нуждающихся во внимательном портировании ни у Вас, ни у меня и десятка % не наберется. Тем более когда Вы ведете речь практически обо все совокупности наработанного из которого полагаю только 10-20% в конкретный проект ложатся. Порядка единиц процентов можно неспешно и глазками вычитать на предмет скользких мест.

Что бывают проекты где 75-90% процентов платформо-независимо и может жить на 8/16/32?

У меня сейчас, пожалуй, поболе 99,9% не зависят от 8/16/32, ибо я говорил откуда пришли исходники, а не то, какими они стали.

из любопытства написал простой скриптик подсчета текстовых строк на Perl и прогнал

Я в редактор скрипт встроил - всегда могу глянуть :)

 

 

У меня эту проблему в общем случае решить не удалось.

Для общего случая эта проблема решается через memcpy(). Причем для прилично писанных на ASM библиотек все получается вполне эффективно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Мое мнение - можно вычитать на 99% :), вчерашний случай это подтвердил

А про неспешно - забудьте - еще в прошлом году уже все должно быть сделано.

 

Я в редактор скрипт встроил - всегда могу глянуть :)

Зачем? Это же смешно - строками меряться :). Я вот давно объем оценил и забыл, сейчас вот брякнул - и пожалел :). Я обычно объем архива смотрю - и прогресс виден и понятно когда снапшоты бэкапить пора.

 

 

Для обшего случая эта проблема решается через memcpy(). Причем для прилично писанных на ASM библиотек все получается вполне эффективно.

А можно пример?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А можно пример?

В смысле? Копируете Ваши байты по адресу переменной/структуры с произвольного адреса. memcpy() содержит разборки с адресами и обеспечивает побайтное копирование невыровненных адресов и пословное выровненных. Да, естественно, имея дополнительно информацию об обьектах можно в частом случае превзойти универсальный вариант.

 

Вот прям сейчас под руками получение контрольной суммы прошивки располагающейся по совершенно произвольному адресу:

memcpy( &crc, (BYTE *)crc_addr, 2 );

Естественно такое черевато:

crc = *((ushort *)crc_addr );

А такое мудрено:

crc = (((ushort)(*(((BYTE *)crc_addr)+1)))<<8) | (ushort)( *((BYTE *)crc_addr) );

Кстати, знаете почему я именно этот кусок привел :) :) :) - Я НА ЭТО НАСТУПИЛ и запомнил. Наступил, сразу скажу, не при портировании, а при изучении ARM - первые шаги, загрузчик, контроль целостности... Наступил и запомнил :) и теперь просто внимателен и осторожен.

Зачем? Это же смешно - строками меряться :).

Упаси бог - Чисто для себя делалось - так сказать интегральная оценка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ещё как пойдёт.

Да не пойдет так! т.к. медленно.

Конкретно в этом случае ожидается, что данные в буфере выровнены. Если нет - тогда это критическая ситуация и проц должен дать мне фатальный эксепшин.

 

Только использовать его надо именно в местах разбора буферов, в которых есть хоть малейшая вероятность невыровненности данных. Для работы с обычными переменными (статика, локальные) надо применять тип без прагмы.

Зачем замедлять работу программы лишними проверками и лишними побайтовыми операциями в критических для производительности местах?

Из-за "малейшей" вероятности делать код вчетверо медленнее - увольте. Мне лучше эксепшн :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

memcpy( &crc, (BYTE *)crc_addr, 2 );

Естественно такое черевато:

crc = *((ushort *)crc_addr );

А такое мудрено:

crc = (((ushort)(*(((BYTE *)crc_addr)+1)))<<8) | (ushort)( *((BYTE *)crc_addr) );

Ну и - почему просто не написать:

crc = lw_wload((ushort *)crc_addr);

где lw_wload - это макрос, аналогичный приведенному мной в посте выше и вырождающийся в один из Ваших вариантов. Если адрес произвольный и неизвестно, выравнен ли он при runtime, на этот случай есть макрос lw_wload_na() (na - not aligned). Все эти макросы компилируются в нормальный компактный код, да еще и обеспечивают конверсию BE/LE при необходимости. А вызов функции - всегда оверхед, и очень заметный, особенно для копирования 2/4 байт. Хотя бы посмотрите в листинг - сколько при вызове для ARM-а регистров сохраняться будет. Не-е-е - это не мой путь, точно. ИМХО, скопировать структуру целиком - еще можно, но это если памяти завались и скорость не волнует. А у меня так не бывает :(

 

И все же:

 

1. Есть проект, состоит из двух частей - прикладной и системной

2. Системная часть - небольшой процент от проекта

- легко заменяется при смене аппаратной части на том же процессоре

3. Прикладная часть - большой процент от проекта и

- развивается долгий срок

- долгое время живет на 8-битной платформе

- долгое время компилируется одним и тем же компилятором

- значительная многовариантность

- значительная оптимизация по размеру кода и оперативной памяти, с учетом платформы и компилятора

4. Возникает необходимость смены платформы на 32-битную

 

И теперь, как автор системной части, я обязан обеспечить своим коллегам-прикладникам максимально безболезненные условия для портирования и отладки прикладной части. А я не могу сделать это в полном объеме, потому как NXP не удосужилась сделать простейшую и стандартную вещь. И что, мое возмущение неоправдано?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну и - почему просто не написать:

Когда это оправдано, естественно, используются разные способы и макросы однин из часто используемых. В данном случае Вы просили пример с memcpy() - я привел пример использования в загрузчике - совершенно не критичном по скорости месте. При копировании струкрур тоже весьма эффективно.

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

Ну насчет размера кода то возможны и даже очень возможны варианты :)

А у меня так не бывает :(

Посмею опять не поверить, основываясь на своих реалиях, что вcегда и везде дела обстят именно так :).

И теперь, как автор системной части, я обязан обеспечить своим коллегам-прикладникам максимально безболезненные условия для портирования и отладки прикладной части. А я не могу сделать это в полном объеме, потому как NXP не удосужилась сделать простейшую и стандартную вещь.

Смотря как подходить к делу, сваять обработчик exception и умыть руки, предоставив возможность поэкспериментировать с наступанием на грабли в паркетно-домашних условиях? Но что делать при таком эмпирическом подходе к делу в реально-непаркетных условиях эксплуатации? Сделать из заказчика естествоиспытателя? В рабочей системе есть система фиксации и выкарабкивания нештатных сттуаций? Тогда какая особо разница, между вылетом и фиксацией факта разборки, например, странного пакета в конкретной ветке?

И что, мое возмущение неоправдано?

Лучше, конечно, быть здоровым и богатым :).... А вообще, настаиваю, что лучше думать. Вы, например, настаиваете на необходимости максимально возможной производительности всегда и везде? Как тогда быть, напимер на 32bit x86, когда при "неправильном" доступе к памяти просто напросто молча получими торможение в разы :(. Опять возмущаться :(?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Посмею опять не поверить, основываясь на своих реалиях, что вcегда и везде дела обстят именно так :).

Гы, я обычно пишу системный код - то есть универсальные сервисы, которые будут использовать другие люди, иногда даже через несколько лет после написания. Поэтому вполне естественно заложить максимально возможное быстродействие и все доступные оптимизации. Вы гарантируете, что при использовании memcpy() у Вас не переполнится, к примеру стек? (а в многопоточке это будет естественно скопировать выравненную структуру в локальную переменную). Или прикладники не будут злоупотреблять частым вызовом функции? Хотя иногда так приятно себе сказать - "а вот таких гадских условий у нас в этой функции не будет никогда" и не писать какой-то противный кусок. В тех нечастых случаях, когда я себе такое позволяю, подстилается соответствующий ASSERT. А вообще - разочарован я Вашим примером использования memcpy(). Он, конечно, имеет право на жизнь, но я надеялся увидеть что-нить менее брутальное.

 

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

Это уже мои проблемы и мои фантазии какой обработчик написать, понадобится - буду эмулировать корректный доступ, потребуют - запишу проблему в лог, разрешат - отправлю баг-репорт по и-мейлу. Но на LPC23xx у меня нет выбора.

 

максимально возможной производительности всегда и везде? Как тогда быть, напимер на 32bit x86, когда при "неправильном" доступе к памяти просто напросто молча получими торможение в разы :(. Опять возмущаться :(?

Ну это уже, имхо, передергивание - априори программу пытаемся написать правильно, доступ предполагаем корректный и по необходимости оптимизированный (если уж хотим избежать "торможения в разы"). Речь идет об исключении - когда что-то пошло нештатно. А насчет возмущения - есть стандартная, привычная и много раз использованная при отладке вещь - OAT/DABT, а теперь вот ее нет, а она реально полезна.

А думать - да, оно вредно обычно (а то опять не поверите :)) не бывает.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гы, я обычно пишу системный код - то есть универсальные сервисы, которые будут использовать другие люди, иногда даже через несколько лет после написания. Поэтому вполне естественно заложить максимально возможное быстродействие и все доступные оптимизации.

 

Абсолютно аналогично :)

 

А вообще - разочарован я Вашим примером использования memcpy(). Он, конечно, имеет право на жизнь, но я надеялся увидеть что-нить менее брутальное.

Пример, как пример. Один из варианов наряду с разнообразными (к сожалению разнообразными) макросами, какими-нибудь узкозаточенными intrinsic функциями типа memcpy_word_from_unaligned( dst, src ) представляющими собой усеченные memcpy(), где только dst гарантированно "хороший" адрес и прочими совершенно, напомню, не отрицаемыми мною решениями. Причем (действительно зачастую брутальный) memcpy() можно легко и гарантировнно безошибочно обернуть в любые макросы и ими сразу и без проблем обозначать проблемные места. C последующим обдумыванием и созданием более узкоспециализированных решений. 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да не пойдет так! т.к. медленно.

Паранойя?! Вы ещё совсем недавно всё на AVR песали и не жаловались на быстродействие. LPC раз в 5 быстрее AVR, и если на нём побайтово из буфера собирать Long, то особых тормозов не будет заметно. Дальше спорить не буду. Я всё равно останусь при своём мнении.

 

А вообще, тут все забыли одну вещь касательно Data Abort при невыровненных словах. Где-то читал, что в LPC он возникает только если проц работает в USER MODE. Во всех остальных MODE, в частности в SYSTEM MODE он специально заблокирован, так как все остальные режимы предназначены для системы. Так что, господа песатели, отлаживайте свои проги в USER MODE, а когда уже всё отладите можете переносить код в другие режимы :biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...