ARM Neon Assembler - странен проблем с тръбопровода

Опитвам се да повиша производителността на част от код, написан на ARM Assembler, използвайки инструкции на Neon.

За тестване и изчисляване използвам този калкулатор: http://pulsar.webshaker.net/ccc/sample-706454b3

Забелязах, че на ред "n.34-0 1c n0" изведнъж модулът Neon изглежда трябва да изчака (?) 10 цикъла. Каква може да е причината за това или е просто грешка в калкулатора?

Също така ще ми трябва малко обща информация как да подобря производителността в ARM/Neon Assembler.

Целта е ARM Cortex-A9. За компилиране използвам най-новия android-ndk с вграден асемблер. Благодаря ти.


person HectorLector    schedule 15.03.2012    source източник


Отговори (3)


Всъщност това е малко по-сложно. BitBank е прав, NEON трябва да изчака D4.

Но трябва да изчакате 10 цикъла, защото Neon имат опашка за зареждане/съхраняване. И опашката се запълва с други инструкции преди

vld1.64 d4, [r7, :64]

Така че, когато имате нужда от D4, трябва да изчакате изпълнението на тази инструкция, но за да изпълните тази инструкция, трябва да изпълните всички предишни инструкции за зареждане/съхраняване, поставени в опашката за зареждане/съхраняване на NEON.

person webshaker    schedule 19.03.2012

Модулът NEON трябва да изчака тази инструкция, защото препращате към регистър (D4), който е бил зареден в предишната инструкция NEON (n.33-0 1c n0). Зарежданията не са мигновени и поради конвейерната обработка има забавяне в наличността на данните, дори ако идват от кеша. Трябва да пренаредите както вашите ARM, така и NEON инструкции, за да не се опитвате да използвате регистри веднага след като ги заредите, или ще завършите с пропилени цикли (конвейерни застой).

person BitBank    schedule 15.03.2012
comment
тези опасности са само 1~2 цикъла, ако кешът е ударен. В този случай е нещо различно. - person Jake 'Alquimista' LEE; 18.03.2012

Не трябва да осъществявате достъп до паметта през ARM, докато NEON си върши работата. Това причинява пълно спиране на NEON.

Очевидно опитвате някаква паралелна обработка, която е опустошителна поради горната причина.

Освен това има твърде много ldrb. Байтовият достъп на ARM също е почти грях.

Предлагам ви първо да пренапишете изцяло кода си на C, с 32-битов достъп само до паметта, след което преценете дали изобщо е предназначен да бъде за NEON,

person Jake 'Alquimista' LEE    schedule 18.03.2012
comment
Благодаря за коментара. Имам нужда само от един байт, така че ако чета 32 бита наведнъж, трябва да Shift/AND цялото нещо отново и това ще бъде по-бавно. Кодът вече е там като C & ARM Assembler и трябва да проверя дали мога да го ускоря с инструкция Neon. На теория би трябвало да е с 30-40% по-бързо. Кои операции могат да се извършват паралелно. ARM аритметика и Neon зареждане/съхраняване, но не (?) Neon аритметика и ARM зареждане/съхранение? - person HectorLector; 18.03.2012
comment
Няма да повярвате: 32-битовото четене + маскирането е много по-бързо от четенето на байтове. - person Jake 'Alquimista' LEE; 19.03.2012
comment
Забравете паралелната обработка. Преместването на стойности от Neon към ARM също води до загуба на 11 цикъла при промиване на конвейер. ARM ще служи само като контролен блок, докато Neon върши цялата работа. - person Jake 'Alquimista' LEE; 19.03.2012
comment
Ще опитам да заредя 32 бита и да маскирам, но мисля, че някой го е тествал преди и беше по-бавно. Добре, благодаря ви за информацията. Изглежда, че в моя случай не мога да увелича производителността с инструкции на Neon :-( - person HectorLector; 20.03.2012
comment
Защо не опиташ да пренапишеш напълно функцията си в NEON? Neon е изключително способен да извършва цели операции и не изисква всички времеемки маскиращи операции. Ако вашата функция съдържа по-малко от две if-elses в рамките на цикъла, Neon е правилният начин. - person Jake 'Alquimista' LEE; 21.03.2012
comment
Скоростта на четене на байтове може да варира в зависимост от SoC. Има някои трикове за ускоряване на операциите по маскиране, което прави маскирането ВИНАГИ по-бързо от четенето на байтове на ARM: const unsigned int mask=0xff; byte0=maskbyte1=маска&(данни››8);byte2=маска&(данни››16);byte3=маска&(данни››24); - person Jake 'Alquimista' LEE; 21.03.2012
comment
Трикът по-горе се възползва от вградения барабанен превключвател на ARM и 1 цикъл всеки. Можете да пропуснете маскирането на byte3, като го вмъкнете в желаната операция, например: резултат += (данни››24); Моля, обърнете внимание, че този трик работи само в режим ARM, тъй като Thumb не поддържа IBS. Така или иначе трябва да компилирате всички критични за производителността процедури в ARM режим. - person Jake 'Alquimista' LEE; 21.03.2012
comment
проблемът е, че през повечето време изчислявам адреси (изместване + изместване на стойността), от които отново зареждам стойности. Ако направя изчислението в Neon, отново трябва да преместя получените адреси в регистрите на ARM - което е много бавно. Така че правя изчислителната част в ARM Assembler и просто използвам Neon за зареждане от получените адреси и някои XOR. Предполагам, че това не е истинският враг на Neon, но се надявам, че ще донесе поне някакво подобрение. Благодаря за информацията, ще пробвам Bitmasking. Наясно съм с превключвателя на ARM Barrel - така че ще ви кажа дали работи ;-) - person HectorLector; 27.03.2012