KRS 0 29 октября, 2009 Опубликовано 29 октября, 2009 · Жалоба Если разница в скорости 10%, а код больше на 40%, то это библиотеки или вы не отключили функции дебагера. Нет дебагер и библиотеки здесь не причем! Я вот по map файлу смотрел, да и библиотеки у меня IARоввские были! GNU действительно генерирует большой код, но производительность от этого не так сильно страдает, а вот как видно в тумбе даже быстрее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 29 октября, 2009 Опубликовано 29 октября, 2009 · Жалоба А вот для Cortex-M3 IAR 5.40 генерит очень медленный код (даже на максимальной оптимизации). Листинг в студию. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
yuri_t 0 29 октября, 2009 Опубликовано 29 октября, 2009 · Жалоба Листинг в студию. http://tnkernel.com/downloads/tnkernel-2-5...xM3-LPC1766.zip This ZIP archive contains: - A latest TNKernel Cortex-M3 port version (2.5.3) - An examples(source code) for the NXP© LPC1766 MCU - A projects for the Rowley CrossWorks Studio 1.7, Keil RVC v.3.xx, IAR ARM v.5.xx, GCC 4.3.2 (Codesourcery 2008q3-66) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 29 октября, 2009 Опубликовано 29 октября, 2009 · Жалоба На примере простого кода, работы с битовыми полями, я его уже давно как то выкладывал, для версий 4.42, 5.11 и RVCT (уже не помню какого) struct bf_s { unsigned f1:6; unsigned f2:2; unsigned f3:20; unsigned f4:4; } bf; void short_clear(void) { bf.f2 = 0; } void short_set(void) { bf.f2 = 3; } void short_const(void) { bf.f2 = 1; } void short_var(unsigned val) { bf.f2 = val; } void long_clear(void) { bf.f3 = 0; } void long_set(void) { bf.f3 = (1<<20)-1; } void long_const(void) { bf.f3 = 1; } void long_var(unsigned val) { bf.f3 = val; } void long_var_if(unsigned val,unsigned cond) { if (cond) bf.f3 = val; else bf.f4=val; } unsigned a; unsigned b; unsigned c; void var_if(unsigned val) { if (val) a = c; else b = c; c = val; } Сейчас скомпилил последним иаром V5.40.2.51604/W32 Улучшений серьезных нет :( BFI и условное выполнение до сих пор IAR делать не умеет! Для примера листинг одной функции RVCT -O3 -Otime --cpu Cortex-M3 long_var_if PROC LDR r3,|L1.176| CMP r1,#0 LDR r2,[r3,#0] ITE EQ BFIEQ r2,r0,#28,#4 BFINE r2,r0,#8,#20 STR r2,[r3,#0] ; bf BX lr ENDP IAR --cpu Cortex-M3 -Ohs long_var_if: LDR.N R2,??DataTable13 ;; bf LDR R3,[R2, #+0] CBZ R1,??long_var_if_0 LDR.N R1,??DataTable14 ;; 0xf00000ff ANDS R1,R1,R3 LDR.N R3,??DataTable15 ;; 0xfffff00 AND R0,R3,R0, LSL #+8 ORRS R0,R0,R1 B.N ??long_var_if_1 ??long_var_if_0: LSLS R1,R3,#+4 LSRS R1,R1,#+4 ORR R0,R1,R0, LSL #+28 ??long_var_if_1: STR R0,[R2, #+0] BX LR Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 29 октября, 2009 Опубликовано 29 октября, 2009 · Жалоба http://tnkernel.com/downloads/tnkernel-2-5...xM3-LPC1766.zip Это конечно очень интересно, но совершенно не то. Я имел в виду листинг узких мест (к которым возникают вопросы по быстродействию) после компилятора. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 29 октября, 2009 Опубликовано 29 октября, 2009 · Жалоба На примере простого кода, работы с битовыми полями, я его уже давно как то выкладывал, для версий 4.42, 5.11 и RVCT (уже не помню какого) Еще раз посомтрел листинги, и заодно GNUC попробовал. GNUC - BFI использует! А вот условное выполнение нет :(. А вот новый IAR оказывается умеет иногда использовать условное выполнение и почему не всегда - загадка, вот листинги последней функции GNUC gcc version 4.3.3 (Sourcery G++ Lite 2009q1-161) -O3 var_if: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. push {r4} mov r4, r0 cbnz r0, .L29 movw r1, #:lower16:c movt r1, #:upper16:c movw r2, #:lower16:b ldr r3, [r1, #0] movt r2, #:upper16:b str r3, [r2, #0] .L27: str r4, [r1, #0] pop {r4} bx lr .L29: movw r1, #:lower16:c movt r1, #:upper16:c movw r2, #:lower16:a ldr r3, [r1, #0] movt r2, #:upper16:a str r3, [r2, #0] b .L27 IAR var_if: LDR.N R1,??var_if_0 ;; a LDR R2,[R1, #+8] CMP R0,#+0 ITE NE STRNE R2,[R1, #+0] STREQ R2,[R1, #+4] STR R0,[R1, #+8] BX LR ;; return RVCT var_if PROC LDR r2,|L1.176| CMP r0,#0 LDR r1,[r2,#0xc] ITE EQ STREQ r1,[r2,#8] ; b STRNE r1,[r2,#4] ; a STR r0,[r2,#0xc] ; c BX lr ENDP как видно еще GNUC по другому подходит к загрузке адреса в регистр! Но IMHO это неоптимально, вместо одной 16 битной инструкции и 32 бит данных используется две 32 битных команды. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AHTOXA 14 29 октября, 2009 Опубликовано 29 октября, 2009 · Жалоба как видно еще GNUC по другому подходит к загрузке адреса в регистр! Но IMHO это неоптимально, вместо одной 16 битной инструкции и 32 бит данных используется две 32 битных команды. Это для скорости, так наверное конвейер не слетает:) При -Os gcc грузит адрес одной инструкцией. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
klen 1 1 ноября, 2009 Опубликовано 1 ноября, 2009 · Жалоба Генерит GCC условные команды IT я взял асм своего проека где Stm32 UsbLib использую - там вот обнаружился такой кусок к примеру void ClearDTOG_RX(uint8_t bEpNum) { 800160e: b2c0 uxtb r0, r0 _ClearDTOG_RX(bEpNum); 8001610: f853 2020 ldr.w r2, [r3, r0, lsl #2] 8001614: f412 4f80 tst.w r2, #16384 ; 0x4000 8001618: bf1f itttt ne 800161a: f853 1020 ldrne.w r1, [r3, r0, lsl #2] 800161e: f648 728f movwne r2, #36751 ; 0x8f8f 8001622: 400a andne r2, r1 8001624: f442 4280 orrne.w r2, r2, #16384 ; 0x4000 8001628: bf18 it ne 800162a: f843 2020 strne.w r2, [r3, r0, lsl #2] } 800162e: 4770 bx lr 8001630: 40005c00 .word 0x40005c00 далее я взял примерно такойже кусок кода как выше указывался: struct bf_s { unsigned f1:20; char f2:8; char f3:8; unsigned f4:20; } bf; void long_var_if(char val,char cond) { if (cond) { bf.f3 = val; bf.f1 = val; bf.f2 = val; } else bf.f4=val; } char var_if(char a , char b ) { char x = a; if (a) { x = b; } return x; } arm-kgp-elf-gcc -mthumb -march=armv7-m -mcpu=cortex-m3 -S -O3 test2.c результат: .syntax unified .thumb .file "test2.c" .text .align 2 .global long_var_if .thumb .thumb_func .type long_var_if, %function long_var_if: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. tst r1, #255 itete ne ldrne r3, .L4 ldreq r3, .L4 ldrne r2, [r3, #0] ldreq r2, [r3, #4] uxtb r0, r0 itett ne bfine r2, r0, #0, #20 bfieq r2, r0, #8, #20 strne r2, [r3, #0] strbne r0, [r3, #4] ite ne strbne r0, [r3, #3] streq r2, [r3, #4] bx lr .L5: .align 2 .L4: .word bf .size long_var_if, .-long_var_if .align 2 .global var_if .thumb .thumb_func .type var_if, %function var_if: @ args = 0, pretend = 0, frame = 0 @ frame_needed = 0, uses_anonymous_args = 0 @ link register save eliminated. uxtb r1, r1 uxtb r0, r0 cmp r0, #0 ite ne movne r0, r1 moveq r0, #0 bx lr .size var_if, .-var_if .comm bf,8,4 .ident "GCC: (GNU) 4.5.0 20091029 (experimental)" из сего видно что GCC прекрасно генерит BFI и IT команды. Другое дело что не ВСЕГДА КОГДА НАМ ЭТО ОЧЕВИДНО! полазив по исходникам компилера я увидел что допустим IT или переходы, например BNE являются для него алтернативами в зависимоти от ситуации принимается решение генерить то или иное. Если учесть что IT способно обойти и загрузить конвеер Cortex'а не более чем на 4 инструкции то становится понятным почему короткий if компиллер генерит через IT а более длинный с его точки зрения (n>4) генерится переход. Есть желание думать что скорость нада проверять а не наличие тех или иных команд. собсно примерно так. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
KRS 0 1 ноября, 2009 Опубликовано 1 ноября, 2009 · Жалоба из сего видно что GCC прекрасно генерит BFI и IT команды. Другое дело что не ВСЕГДА КОГДА НАМ ЭТО ОЧЕВИДНО! полазив по исходникам компилера я увидел что допустим IT или переходы, например BNE ... да это все известно и из описания архитектуры, для этого лезть в исходники компилера не надо! в моем варианте функции var_if - GNUC явно полез оптимизировать нетуда! в итоге функция неимоверно больше по размеру, использует стек! и явно медленне работает! Про BFI - я сразу говорил что гнусь это умеет! Вот что что а а все подобные иснтуркции гнусь всегда задействует. у IAR с BFI проблема пока. По поводу Вашей функции var_if - вообще смешно!!! RVCT - ее скомпилировал так var_if PROC CMP r0,#0 IT NE MOVNE r0,r1 BX lr ENDP по поводу UTX - конечно можно спорить, но это явно лишнее, раз указано что на входе char, дополнительно чистить его не надо, это должна делать вызывающая сторона! арифмитических опреаций с переменными здесь не проводится так что переполнения в старшие биты быть не может! листинг первой функции, выкладывать не буду, но он тоже оптимальнее и код красивее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dch 0 2 ноября, 2009 Опубликовано 2 ноября, 2009 · Жалоба обычно компиляторы несравниваются по наличию ошибок, по тому какой суппорт удается получить и как быстро компилятор переползает на новую архитектуру, пока не начинаются подмены ресурсов на публичных сайтах public domain или близкие к нему GNU ресурсы обычно достаточно надежны, впрочем наверное начинать писать свой кроскомпилятор уже наверное можно, судя по количеству несанкционированного доступа к инет реурсам. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ReAl 0 2 ноября, 2009 Опубликовано 2 ноября, 2009 · Жалоба Полуоффтоп: Не, ну таки странности у gcc проскакивают ещё те. Чистая культура кода: uint8_t pos(uint8_t num) // num = 0..8 { uint8_t pos = 0x40; while(num >= 3) { pos += 0x40; num -= 3; } pos += num * 7; return pos; } avr-gcc 4.3.2 (WinAVR-20090313) умудрился это дело скомпилировать так, как если бы было написано uint8_t pos(uint8_t num) { return (num/3+1)*0x40 + (num % 3)*7; } Он, конечно, правильно понял, что происходит, но назачем в этой короткой функции два вызова __udivmodqi4 ??? Более ранние скомпилировали что написано. Что интересно, эта 20090313 на объёме в около 5.5кБ несмотря на финт с делением таки дала код на сотню байт короче, чем 20071221. И 4.4.0 (Klen-20090207 и 20090323) тоже обошлись без /%, в этой конкретной функции ещё и аккуратнее регистры разложили и общий код ещё почти на сотню байт уменьшили. "но осадок остался" Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
brag 0 11 июня, 2012 Опубликовано 11 июня, 2012 · Жалоба Выкладываю несколько результатов бенчмарков. мож кому будет еще интересно... Проц STM32F105RC gcc-4.7.1-RC -O2 sz=185024 MP3 Time: 41 TWF Time: 20 CRC32 Time: 12 gcc-4.7.1-RC -O3 -fno-tree-vectorize sz=202516 MP3 Time: 41 TWF Time: 19 CRC32 Time: 6 gcc-4.6.4-PRE -O2 sz=186076 MP3 Time: 43 TWF Time: 25 CRC32 Time: 12 gcc-4.6.4-PRE -O3 -fno-tree-vectorize sz=200312 MP3 Time: 43 TWF Time: 25 CRC32 Time: 7 rvct 4.1 894 -O2 -Otime sz=180016 MP3 Time: 39 TWF Time: 23 CRC32 Time: 16 rvct 4.1 894 -O3 -Otime sz=183440 MP3 Time: 38 TWF Time: 19 CRC32 Time: 11 armcc 5.01.64 -O2 -Otime sz=180008 MP3 Time: 39 TWF Time: 23 CRC32 Time: 16 armcc 5.01.64 -O3 -Otime sz=183432 MP3 Time: 38 TWF Time: 19 CRC32 Time: 10 gcc-4.6.1 (Sourcery CodeBench Lite 2011.09-69) -O2 sz=202708 MP3 Time: 41 TWF Time: 26 CRC32 Time: 7 gcc-4.6.1 (Sourcery CodeBench Lite 2011.09-69) -O3 sz=213940 MP3 Time: 38 TWF Time: 26 CRC32 Time: 7 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
brag 0 6 июля, 2012 Опубликовано 6 июля, 2012 · Жалоба Ни один компилятор не смог нормально соптимизировать простые очевидные вещи.. class tormoz{ public: void remove(); private: tormoz *next; tormoz *prev; }; void tormoz::remove(){ next->prev=prev; prev->next=next; } rvct -O3 -Otime 00000134 <_ZN6tormoz6removeEv>: 134: e9d0 1200 ldrd r1, r2, [r0] 138: 604a str r2, [r1, #4] 13a: e9d0 1000 ldrd r1, r0, [r0] ;<<<---- Зачем?? 13e: 6001 str r1, [r0, #0] 140: 4770 bx lr gcc-4.7.1 -O3 -Otime 00000000 <_ZN6tormoz6removeEv>: 0: 6803 ldr r3, [r0, #0] 2: 6842 ldr r2, [r0, #4] 4: 605a str r2, [r3, #4] 6: 6842 ldr r2, [r0, #4] ;<<<---- Зачем?? 8: 6013 str r3, [r2, #0] a: 4770 bx lr Вот так оптимизирует нормально на обеих компиляторах, но это ж не те уже времена, когда использовали ключевое слово register и вучную оптимизировали порядок загрузки.. void tormoz::remove(){ tormoz *n=next,*p=prev; n->prev=p; p->next=n; } 0: e890 000c ldmia.w r0, {r2, r3} 4: 6053 str r3, [r2, #4] 6: 601a str r2, [r3, #0] 8: 4770 bx lr Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Petka 0 6 июля, 2012 Опубликовано 6 июля, 2012 · Жалоба Ни один компилятор не смог нормально соптимизировать простые очевидные вещи.. Очевидно же: После выполнения next->prev=next; Следующаяя строка кода может работать с совсем ДРУГОЙ памятью, нежели ДО выполнения предыдущей строчки. Оптимизатор просто не имеет права ничего удалять. prev->next=prev; В данном случае всё указано однозначно. void tormoz::remove(){ tormoz *n=next,*p=prev; n->prev=p; p->next=n; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
brag 0 6 июля, 2012 Опубликовано 6 июля, 2012 · Жалоба Следующаяя строка кода может работать с совсем ДРУГОЙ памятью, нежели ДО выполнения предыдущей строчки. Оптимизатор просто не имеет права ничего удалять. Интересно с какой? Если будет next==prev всеравно поля next->prev,prev->prev и next->next,prev->next будут иметь разные адреса. Если next==prev==this тогда this->prev=this; this->next=this; Чет никак не могу придумать, как можно добится разного поведения от этих двух разных реализаций... апд. сории,в коде перепутал местами, но сути это не меняет,компилится так же.должно быть так next->prev=prev; prev->next=next; 11a: e9d0 1200 ldrd r1, r2, [r0] 11e: 604a str r2, [r1, #4] 120: e9d0 1000 ldrd r1, r0, [r0] 124: 6001 str r1, [r0, #0] Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться