Що є більш швидкою альтернативою CRC?


27

Я роблю деяку передачу даних з dsPIC на ПК, і я роблю 8-бітний CRC для кожного блоку з 512 байтів, щоб переконатися у відсутності помилок. З увімкненим моїм кодом CRC я отримую близько 33 КБ / с, без нього я отримую 67 КБ / с.

Які існують альтернативні алгоритми виявлення помилок, щоб перевірити, що було б швидше?


5
Як реалізується сама КРС? Побіто? Потім перейдіть на табличний метод. Побічно? Розглянемо простір, складність та часовий компроміс, пов'язаний із збільшенням розміру таблиці до, скажімо, 16 біт (який би працював одразу на два байти, але зайняв би 64 КБ пам’яті таблиці).
Айдан Каллі

У мене є лише 16 КБ оперативної пам’яті та 128 КБ ПЗУ, тому таблиця 64 КБ - це не варіант.
FigBug

1
Отже, ви використовуєте 256-байтну таблицю? або розрядний CRC? Якщо ви робите побіжно, то побічно (з 256-байтною таблицею) було б у 8 разів швидше.
Айдан Каллі

Побітним чином зараз я спробую 256 таблицю
FigBug

1
67 кб / с до 33 кб / с? Я не впевнений, що пов'язано з вашою іншою обробкою, але це звучить як трохи накладні витрати, навіть для PIC. Можливо, є якісь інші проблеми, що перешкоджають вашому виступу?
Рей Міясака

Відповіді:


41

Незважаючи на те, що варіанти CRC можуть бути більш швидкими, ніж CRC, якщо ви їх використовуєте, то, швидше за все, ви принесете в жертву певну ступінь можливості виявлення помилок. Залежно від вимог щодо виявлення помилок, альтернативою може бути використання CRC-коду, оптимізованого для вашої програми.

Для порівняння CRC з іншими варіантами дивіться чудову відповідь Мартіна Томпсона .

Одним із варіантів допомогти у цьому є pycrc, який є інструментом (написаним на python 1 ), який може генерувати вихідний код C для десятків комбінацій моделі та алгоритму crc . Це дозволяє оптимізувати швидкість і розмір для вашого власного додатка, вибираючи та орієнтуючи різні комбінації. 1: Потрібен Python 2.6 або новішої версії.

Вона підтримує crc-8 модель , але і підтримує crc-5, crc-16і crc-32серед інших. Що стосується алгоритмів , він підтримує bit-by-bit, bit-by-bit-fastі table-driven.

Наприклад (завантаження архіву):

$ wget --quiet http://sourceforge.net/projects/pycrc/files/pycrc/pycrc-0.8/pycrc-0.8.tar.gz/download
$ tar -xf pycrc-0.8.tar.gz
$ cd pycrc-0.8
$ ./pycrc.py --model=crc-8 --algorithm=bit-by-bit      --generate c -o crc8-byb.c
$ ./pycrc.py --model=crc-8 --algorithm=bit-by-bit-fast --generate c -o crc8-bybf.c
$ ./pycrc.py --model=crc-8 --algorithm=table-driven    --generate c -o crc8-table.c
$ ./pycrc.py --model=crc-16 --algorithm=table-driven   --generate c -o crc16-table.c
$ wc *.c
   72   256  1790 crc8-byb.c
   54   190  1392 crc8-bybf.c
   66   433  2966 crc8-table.c
  101   515  4094 crc16-table.c
  293  1394 10242 total

Ви навіть можете робити химерні речі, такі як уточнення, використовуючи подвійні пошукові підказки (з 16-байтовою таблицею огляду), а не однобайтовий пошук, з 256-байтною таблицею огляду.

Наприклад (клонування сховища git):

$ git clone http://github.com/tpircher/pycrc.git
$ cd pycrc
$ git branch
* master
$ git describe
v0.8-3-g7a041cd
$ ./pycrc.py --model=crc-8 --algorithm=table-driven --table-idx-width=4 --generate c -o crc8-table4.c
$ wc crc8-table4.c
  53  211 1562 crc8-table4.c

Зважаючи на вашу пам'ять та обмеження швидкості, ця опція може бути найкращим компромісом між швидкістю та розміром коду. Єдиний спосіб бути впевненим у тому, щоб це було порівняно.


Pycrc репозиторій на GitHub , як його відстеження проблем , але він також може бути завантажена з сайту SourceForge .


Я не вірю, що більшість людей, які пишуть речі для PIC, використовують C, але це може спрацювати, якщо так.
Біллі ONeal

4
@Billy - Дійсно? Я не думаю, що я натрапив на когось, хто розробляє для PIC комерційно, який не використовував C. Я, звичайно, не маю терпіння для асемблера в наші дні, і добре структурований C може закінчитися досить компактним.
Марк Бут

Я використовую dsPIC і використовую C.
FigBug

@FigBug - Дякую, радий, що тобі подобається моя відповідь. Якщо ви запускаєте якісь тестові показники, сміливо відредагуйте мою відповідь вашими результатами. Я хотів би дізнатися, скільки різниць має кожен з алгоритмів з точки зору пропускної здатності вашої програми та пам’яті.
Марк Бут

1
Ще один голос за pyCrc тут. використовувати його в різних проектах з різними обмеженнями, і це просто чудово.
Вікі

11

Простий однобітний паритет (в основному XORing даних над собою знову і знову) проходить так само швидко, як можна отримати. Ви все-таки втрачаєте багато перевірки помилок CRC.

У псевдокоді:

char checksum = 0;
for each (char c in buffer)
{
    checksum ^= c;
    SendToPC(c);
}
SendToPc(checksum);

1
Я заглянув у це деякий час тому. Я вважаю, що підсумовування замість xor насправді працює трохи краще. (як правило, підсумовуйте все, а потім передайте 2-го доповнення суми як контрольну суму. На приймачі підсумовуйте все, включаючи отриману контрольну суму. Результат 0, якщо його все добре, а не-0 в іншому випадку.)
швидко_зна

1
@quickly: Я не думаю, що між цими двома є суттєва різниця - жоден метод не дає всієї такої хорошої впевненості, що речі не були пошкоджені. Якщо додавання швидше в цільовій архітектурі, використовуйте це замість цього.
Біллі ONeal

7
Я згадав: Основна відмінність ADD від XOR полягає в тому, що менше виявлення помилок декількох бітів. У випадку потоку байтів помилки в одному і тому ж бітовому положенні скасовуються за допомогою XOR. Під час використання ADD розповсюдження бітів вгору через байт контрольної суми означає, що цей випадок виявляється більш чітко. (Однак декілька бітових помилок у різних бітах, що поширюються через потік байтів, ймовірно, будуть менш помітні - залежно від обставин на той час) Будь-яка компоновка контрольної суми, подібна до цієї, є ТЕРИЧНОЮ для багаторозрядних помилок, тому це доволі незначний аргумент.
quick_now

XOR набагато менш корисний, ніж CRC.

3
@ Thorbjørn: Я вважаю, що це я визнав у своїй відповіді. :)
Біллі ONeal

10

Дійсно хороший документ, що порівнює продуктивність різних контрольних сум і CRC у вбудованому контексті:

Ефективність контрольних сум для вбудованих мереж

Деякі цитати висновків (засновані на їх дослідженнях невиявлених ймовірностей помилок):

Коли домінуючі помилки домінують

XOR, два доповнення доповнення та контрольні суми CRC забезпечують кращу ефективність виявлення помилок, ніж контрольні суми доповнення, Fletcher та Adler.

В інших додатках

"Добрий" поліном CRC, коли це можливо, слід використовувати для виявлення помилок

Якщо вартість обчислень дуже обмежена

(як у вашому випадку) використовуйте (в порядку ефективності):

Інші цитати:

Контрольна сума Fletcher має менші обчислювальні витрати, ніж контрольна сума Адлера, і, всупереч поширеній думці, також більш ефективна у більшості ситуацій.

і

Як правило, немає причин продовжувати поширену практику використання контрольної суми XOR у нових конструкціях, оскільки вона має таку ж обчислювальну вартість програмного забезпечення, як контрольна сума на основі додатків, але лише приблизно вдвічі ефективніша при виявленні помилок.


1
Як бонус, контрольна сума Fletcher дуже легко здійснити.
RubberDuck

6

Контрольна сума Адлера повинна бути достатньою для перевірки спотворень передачі. Він використовується бібліотекою стиснення Zlib і був прийнятий стандартом графічної графіки Java 3D для забезпечення швидкої, але ефективної перевірки цілісності даних.

На сторінці вікіпедії :

Контрольна сума Adler-32 отримується шляхом обчислення двох 16-бітних контрольних сум A і B та об'єднання їх бітів у 32-бітове ціле число. A - сума всіх байтів у рядку плюс один, а B - сума окремих значень A з кожного кроку.

На початку пробігу Adler-32 A ініціалізується на 1, B на 0. Суми проводяться за модулем 65521 (найбільше просте число менше 2 ^ 16 або 65536). Байти зберігаються в мережевому порядку (великий ендіан), B займають два найбільш значущі байти.

Функція може бути виражена як

 A = 1 + D1 + D2 + ... + Dn (mod 65521)
 B = (1 + D1) + (1 + D1 + D2) + ... + (1 + D1 + D2 + ... + Dn) (mod 65521)
   = n×D1 + (n-1)×D2 + (n-2)×D3 + ... + Dn + n (mod 65521)

 Adler-32(D) = B × 65536 + A

де D - рядок байтів, для яких слід обчислити контрольну суму, а n - довжина D.


Зауважте, що Adler32 майже непридатний для короткого пробігу даних. До близько 180 байт, він створює численні зіткнення.
greyfade

+1 - розумна середина між CRC та простим парним бітом.
Біллі ONeal

@greyfade - FigBug згадав про використання 512 байтових блоків, тому це не повинно бути проблемою для ОП. Добре, що це відзначається людям з іншими вимогами.
Марк Бут

5

Я не знаю нічого, що настільки ефективно на виявленні помилок, як CRC, і швидше - якби вони були, люди замість цього використовували б.

Ви можете спробувати просту контрольну суму, але це набагато менше шансів виявити помилки.


2
Я готовий відмовитись від ефективності щодо швидкості.
FigBug

3

Добре, що логіка контрольної суми хороша, і люди можуть допомогти у більш швидких алгоритмах.

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

Якщо вони є двома незалежними елементами (у різних потоках), ви можете отримати повну швидкість передачі та надсилати лише невдалі пакети.

Алгоритм виглядатиме приблизно так:

  • Сервер розпадається на відомі розміри пакетів (скажімо, 1K шматки). Ставить їх у чергу "надіслати".
  • Кожен пакет надсилається з 16 або 32 бітовим ідентифікатором І його контрольною сумою.
  • Клієнт отримує кожен пакет і ставить його в чергу для обробки.
  • На окремій потоці клієнт приймає пакет одночасно, робить перевірку.
    • Після успіху він додає його до остаточної колекції пакетів (у порядку ідентифікації)
    • У разі відмови він повідомляє про невдалий ідентифікатор назад на сервер, який подає чергу до цього пакета, щоб повторно відмовитися.
  • Після отримання та перевірки пакетів та отримання ідентифікаторів у правильній послідовності (починаючи з 1) ви можете почати записувати їх на диск (або робити все, що потрібно).

Це дозволить вам передавати з максимально можливою швидкістю, і якщо ви граєте з розміром вашого пакету, ви можете розробити коефіцієнт відмови оптимію VS для перевірки / повторної передачі.


2

Капсули традиційні

(зменшити # '+ потік)

XOR, як зазначено вище, також буде працювати

(зменшити # 'потік XOR)

Трохи більш детальною (повільнішою) схемою є стандартна перевірка парності для послідовних з'єднань.

На цьому рівні ви торгуєте правильністю швидкості. Вони періодично виходять з ладу.

На наступному, найскладнішому рівні, ви можете використовувати деякі матеріали типу crc / hash.

Іншою конструкцією було б збільшення розміру блоку, який використовується для потоку.

Ви повинні мати оцінку фактичної частоти помилок, щоб настроїти вибір алгоритму та параметри для розміру блоку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.