|
|
  |
WinAVR обновился до 20081118rc2, Похоже, скоро релиз появится! |
|
|
|
Nov 22 2008, 02:01
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(Сергей Борщ @ Nov 22 2008, 02:29)  Пойдет. Лично не пользовал, но уважаемые форумчане хвалят.Дык... O3 - это для больших машин с кучей памяти. Инлайн и разворот циклов где только можно в погоне за скоростью. Для AVR оптимальным является Os. Кроме того там есть еще куча ключей для тонкой настройки. Ваш код действительно дал какой-то неадекватный результат. Для ИАРа оптимизация по скорости очень часто дает меньший код, чем оптимизация по размеру (парадокс!). Попробуйте включить кластеризацию переменных, и вообще все галочки, которые доступны в дополнительных параметрах оптимизации. Пробовал - не помогает. Исправляюсь - кроме О3 тестил ещё и на Os. Да, последний режим давал более приемлимые результаты Цитата(IgorKossak @ Nov 22 2008, 02:50)  Поставьте перед функцией __z, а ещё лучше __x (передавать указатель через регистровую пару весьма разумно) или оптимизацию установите по объёму и будет Вам счастье. Не всё так просто. Не спасает ничего, кроме установки перед функцией ключа __x_z. Но почему я должен каждую микроскопическую функцию проверять и персонально настраивать под оптимальную генерацию руками? На это нужна куча времени!
|
|
|
|
|
Nov 23 2008, 08:22
|
Группа: Участник
Сообщений: 6
Регистрация: 16-12-05
Пользователь №: 12 291

|
Цитата(Alex_NEMO @ Nov 20 2008, 15:22)  ... - Various bugs fixed. Вот с ЭТОГО бы места да поподробнее.
|
|
|
|
|
Nov 23 2008, 10:07
|
Частый гость
 
Группа: Свой
Сообщений: 106
Регистрация: 13-05-05
Пользователь №: 4 977

|
Цитата(NetTracer @ Nov 23 2008, 11:22)  Вот с ЭТОГО бы места да поподробнее.  Не по адресу вопрос! Когда релиз выйдет, возможно, распишут более подробно! Но то, что новых добавят - это несомненно! (См. ветку)
|
|
|
|
|
Nov 24 2008, 15:23
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Портировал я свою программу с IARа на GCC. Оптимизация максимальная по скорости у первого, и Os с ключами -mcall-prologues -fno-inline-small-functions -fno-threadsafe-statics -ffunction-sections --gc-sections --relax у второго. В результате код IARа - 6 090 bytes of CODE memory + 493 bytes of DATA memory. Код GCC - Program: 7120 bytes + Data: 363 bytes. Код иара компактнее свыше чем на килобайт. Правда, некоторые функции "тюнингованы" специальными ключами (типа __z_x и т.д.) для оптимальной генерации. Добавление некоторых аттрибутов для функций в GCC в аналогичных целях, к сожалению, не дало абсолютно никакого результата... На первый взгляд, скомпилированный GCC код весьма красив и аккуратен, за исключением излишней любви к LDS и STS, например: исходный текст: Код case USART_SEND_DATA_EX: length = 4 + 4 + 4 + 20; *pb++ = length + 1; *pb++ = command; *pb++ = temperature.cpu; *pb++ = temperature.gpu; *pb++ = temperature.amb; *pb++ = temperature.hdd; *pb++ = fan_speed[0]; *pb++ = fan_speed[1]; *pb++ = fan_speed[2]; *pb++ = fan_speed[3]; *pb++ = cpuFan.GetCurrentSpeed(); *pb++ = rearFan.GetCurrentSpeed(); *pb++ = sideFan.GetCurrentSpeed(); *pb++ = frontFan.GetCurrentSpeed(); *pb++ = cpuFan.RPMval[RPM_MIN]; *pb++ = cpuFan.RPMval[RPM_MED]; *pb++ = cpuFan.RPMval[RPM_MAX]; *pb++ = cpuFan.minTEMPval; *pb++ = cpuFan.maxTEMPval; *pb++ = rearFan.RPMval[RPM_MIN]; *pb++ = rearFan.RPMval[RPM_MED]; *pb++ = rearFan.RPMval[RPM_MAX]; *pb++ = rearFan.minTEMPval; *pb++ = rearFan.maxTEMPval; *pb++ = sideFan.RPMval[RPM_MIN]; *pb++ = sideFan.RPMval[RPM_MED]; *pb++ = sideFan.RPMval[RPM_MAX]; *pb++ = sideFan.minTEMPval; *pb++ = sideFan.maxTEMPval; *pb++ = frontFan.RPMval[RPM_MIN]; *pb++ = frontFan.RPMval[RPM_MED]; *pb++ = frontFan.RPMval[RPM_MAX]; *pb++ = frontFan.minTEMPval; *pb++ = frontFan.maxTEMPval; break; результат IARа: Код 105 case USART_SEND_DATA_EX: 106 length = 4 + 4 + 4 + 20; \ ??usartSendCommand_4: \ 000000C4 E280 LDI R24, 32 107 *pb++ = length + 1; \ 000000C6 E201 LDI R16, 33 \ 000000C8 930D ST X+, R16 108 *pb++ = command; \ 000000CA 934D ST X+, R20 109 *pb++ = temperature.cpu; \ 000000CC 9100.... LDS R16, temperature \ 000000D0 930D ST X+, R16 110 *pb++ = temperature.gpu; \ 000000D2 9100.... LDS R16, (temperature + 1) \ 000000D6 930D ST X+, R16 111 *pb++ = temperature.amb; \ 000000D8 9100.... LDS R16, (temperature + 2) \ 000000DC 930D ST X+, R16 112 *pb++ = temperature.hdd; \ 000000DE 9100.... LDS R16, (temperature + 3) \ 000000E2 930D ST X+, R16 113 *pb++ = fan_speed[0]; \ 000000E4 9100.... LDS R16, fan_speed \ 000000E8 930D ST X+, R16 114 *pb++ = fan_speed[1]; \ 000000EA 9100.... LDS R16, (fan_speed + 1) \ 000000EE 930D ST X+, R16 115 *pb++ = fan_speed[2]; \ 000000F0 9100.... LDS R16, (fan_speed + 2) \ 000000F4 930D ST X+, R16 116 *pb++ = fan_speed[3]; \ 000000F6 9100.... LDS R16, (fan_speed + 3) \ 000000FA 930D ST X+, R16 117 *pb++ = cpuFan.GetCurrentSpeed(); \ 000000FC .... LDI R16, LOW(cpuFan) \ 000000FE .... LDI R17, (cpuFan) >> 8 \ 00000100 .... RCALL ??GetCurrentSpeed \ 00000102 930D ST X+, R16 118 *pb++ = rearFan.GetCurrentSpeed(); \ 00000104 .... LDI R16, LOW(rearFan) \ 00000106 .... LDI R17, (rearFan) >> 8 \ 00000108 .... RCALL ??GetCurrentSpeed \ 0000010A 930D ST X+, R16 119 *pb++ = sideFan.GetCurrentSpeed(); \ 0000010C .... LDI R16, LOW(sideFan) \ 0000010E .... LDI R17, (sideFan) >> 8 \ 00000110 .... RCALL ??GetCurrentSpeed \ 00000112 930D ST X+, R16 120 *pb++ = frontFan.GetCurrentSpeed(); \ 00000114 .... LDI R16, LOW(frontFan) \ 00000116 .... LDI R17, (frontFan) >> 8 \ 00000118 .... RCALL ??GetCurrentSpeed \ 0000011A 930D ST X+, R16 121 *pb++ = cpuFan.RPMval[RPM_MIN]; \ 0000011C 9100.... LDS R16, (cpuFan + 5) \ 00000120 930D ST X+, R16 122 *pb++ = cpuFan.RPMval[RPM_MED]; \ 00000122 9100.... LDS R16, (cpuFan + 6) \ 00000126 930D ST X+, R16 123 *pb++ = cpuFan.RPMval[RPM_MAX]; \ 00000128 9100.... LDS R16, (cpuFan + 7) \ 0000012C 930D ST X+, R16 124 *pb++ = cpuFan.minTEMPval; \ 0000012E 9100.... LDS R16, (cpuFan + 8) \ 00000132 930D ST X+, R16 125 *pb++ = cpuFan.maxTEMPval; \ 00000134 9100.... LDS R16, (cpuFan + 9) \ 00000138 930D ST X+, R16 126 *pb++ = rearFan.RPMval[RPM_MIN]; \ 0000013A 9100.... LDS R16, (rearFan + 5) \ 0000013E 930D ST X+, R16 127 *pb++ = rearFan.RPMval[RPM_MED]; \ 00000140 9100.... LDS R16, (rearFan + 6) \ 00000144 930D ST X+, R16 128 *pb++ = rearFan.RPMval[RPM_MAX]; \ 00000146 9100.... LDS R16, (rearFan + 7) \ 0000014A 930D ST X+, R16 129 *pb++ = rearFan.minTEMPval; \ 0000014C 9100.... LDS R16, (rearFan + 8) \ 00000150 930D ST X+, R16 130 *pb++ = rearFan.maxTEMPval; \ 00000152 9100.... LDS R16, (rearFan + 9) \ 00000156 930D ST X+, R16 131 *pb++ = sideFan.RPMval[RPM_MIN]; \ 00000158 9100.... LDS R16, (sideFan + 5) \ 0000015C 930D ST X+, R16 132 *pb++ = sideFan.RPMval[RPM_MED]; \ 0000015E 9100.... LDS R16, (sideFan + 6) \ 00000162 930D ST X+, R16 133 *pb++ = sideFan.RPMval[RPM_MAX]; \ 00000164 9100.... LDS R16, (sideFan + 7) \ 00000168 930D ST X+, R16 134 *pb++ = sideFan.minTEMPval; \ 0000016A 9100.... LDS R16, (sideFan + 8) \ 0000016E 930D ST X+, R16 135 *pb++ = sideFan.maxTEMPval; \ 00000170 9100.... LDS R16, (sideFan + 9) \ 00000174 930D ST X+, R16 136 *pb++ = frontFan.RPMval[RPM_MIN]; \ 00000176 9100.... LDS R16, (frontFan + 5) \ 0000017A 930D ST X+, R16 137 *pb++ = frontFan.RPMval[RPM_MED]; \ 0000017C 9100.... LDS R16, (frontFan + 6) \ 00000180 930D ST X+, R16 138 *pb++ = frontFan.RPMval[RPM_MAX]; \ 00000182 9100.... LDS R16, (frontFan + 7) \ 00000186 930D ST X+, R16 139 *pb++ = frontFan.minTEMPval; \ 00000188 9100.... LDS R16, (frontFan + 8) \ 0000018C 930D ST X+, R16 140 *pb++ = frontFan.maxTEMPval; \ 0000018E 9100.... LDS R16, (frontFan + 9) \ 00000192 CF96 RJMP ??usartSendCommand_12 141 break; вполне прилично. А вот у GCC: Код case USART_SEND_DATA_EX: length = 4 + 4 + 4 + 20; *pb++ = length + 1; 153c: 81 e2 ldi r24, 0x21; 33 153e: 80 93 ed 01 sts 0x01ED, r24 *pb++ = command; 1542: 90 93 ee 01 sts 0x01EE, r25 *pb++ = temperature.cpu; 1546: 80 91 34 01 lds r24, 0x0134 154a: 80 93 ef 01 sts 0x01EF, r24 *pb++ = temperature.gpu; 154e: 80 91 35 01 lds r24, 0x0135 1552: 80 93 f0 01 sts 0x01F0, r24 *pb++ = temperature.amb; 1556: 80 91 36 01 lds r24, 0x0136 155a: 80 93 f1 01 sts 0x01F1, r24 *pb++ = temperature.hdd; 155e: 80 91 37 01 lds r24, 0x0137 1562: 80 93 f2 01 sts 0x01F2, r24 *pb++ = fan_speed[0]; 1566: 80 91 6f 01 lds r24, 0x016F 156a: 80 93 f3 01 sts 0x01F3, r24 *pb++ = fan_speed[1]; 156e: 80 91 70 01 lds r24, 0x0170 1572: 80 93 f4 01 sts 0x01F4, r24 *pb++ = fan_speed[2]; 1576: 80 91 71 01 lds r24, 0x0171 157a: 80 93 f5 01 sts 0x01F5, r24 *pb++ = fan_speed[3]; 157e: 80 91 72 01 lds r24, 0x0172 1582: 80 93 f6 01 sts 0x01F6, r24 *pb++ = cpuFan.GetCurrentSpeed(); 1586: 87 e3 ldi r24, 0x37; 55 1588: 92 e0 ldi r25, 0x02; 2 158a: 4c d7 rcall .+3736 ; 0x2424 <__data_load_end+0x6fe> 158c: 80 93 f7 01 sts 0x01F7, r24 *pb++ = rearFan.GetCurrentSpeed(); 1590: 81 e4 ldi r24, 0x41; 65 1592: 92 e0 ldi r25, 0x02; 2 1594: 47 d7 rcall .+3726 ; 0x2424 <__data_load_end+0x6fe> 1596: 80 93 f8 01 sts 0x01F8, r24 *pb++ = sideFan.GetCurrentSpeed(); 159a: 8b e4 ldi r24, 0x4B; 75 159c: 92 e0 ldi r25, 0x02; 2 159e: 42 d7 rcall .+3716 ; 0x2424 <__data_load_end+0x6fe> 15a0: 80 93 f9 01 sts 0x01F9, r24 *pb++ = frontFan.GetCurrentSpeed(); 15a4: 85 e5 ldi r24, 0x55; 85 15a6: 92 e0 ldi r25, 0x02; 2 15a8: 3d d7 rcall .+3706 ; 0x2424 <__data_load_end+0x6fe> 15aa: 80 93 fa 01 sts 0x01FA, r24 *pb++ = cpuFan.RPMval[RPM_MIN]; 15ae: 80 91 3c 02 lds r24, 0x023C 15b2: 80 93 fb 01 sts 0x01FB, r24 *pb++ = cpuFan.RPMval[RPM_MED]; 15b6: 80 91 3d 02 lds r24, 0x023D 15ba: 80 93 fc 01 sts 0x01FC, r24 *pb++ = cpuFan.RPMval[RPM_MAX]; 15be: 80 91 3e 02 lds r24, 0x023E 15c2: 80 93 fd 01 sts 0x01FD, r24 *pb++ = cpuFan.minTEMPval; 15c6: 80 91 3f 02 lds r24, 0x023F 15ca: 80 93 fe 01 sts 0x01FE, r24 *pb++ = cpuFan.maxTEMPval; 15ce: 80 91 40 02 lds r24, 0x0240 15d2: 80 93 ff 01 sts 0x01FF, r24 *pb++ = rearFan.RPMval[RPM_MIN]; 15d6: 80 91 46 02 lds r24, 0x0246 15da: 80 93 00 02 sts 0x0200, r24 *pb++ = rearFan.RPMval[RPM_MED]; 15de: 80 91 47 02 lds r24, 0x0247 15e2: 80 93 01 02 sts 0x0201, r24 *pb++ = rearFan.RPMval[RPM_MAX]; 15e6: 80 91 48 02 lds r24, 0x0248 15ea: 80 93 02 02 sts 0x0202, r24 *pb++ = rearFan.minTEMPval; 15ee: 80 91 49 02 lds r24, 0x0249 15f2: 80 93 03 02 sts 0x0203, r24 *pb++ = rearFan.maxTEMPval; 15f6: 80 91 4a 02 lds r24, 0x024A 15fa: 80 93 04 02 sts 0x0204, r24 *pb++ = sideFan.RPMval[RPM_MIN]; 15fe: 80 91 50 02 lds r24, 0x0250 1602: 80 93 05 02 sts 0x0205, r24 *pb++ = sideFan.RPMval[RPM_MED]; 1606: 80 91 51 02 lds r24, 0x0251 160a: 80 93 06 02 sts 0x0206, r24 *pb++ = sideFan.RPMval[RPM_MAX]; 160e: 80 91 52 02 lds r24, 0x0252 1612: 80 93 07 02 sts 0x0207, r24 *pb++ = sideFan.minTEMPval; 1616: 80 91 53 02 lds r24, 0x0253 161a: 80 93 08 02 sts 0x0208, r24 *pb++ = sideFan.maxTEMPval; 161e: 80 91 54 02 lds r24, 0x0254 1622: 80 93 09 02 sts 0x0209, r24 *pb++ = frontFan.RPMval[RPM_MIN]; 1626: 80 91 5a 02 lds r24, 0x025A 162a: 80 93 0a 02 sts 0x020A, r24 *pb++ = frontFan.RPMval[RPM_MED]; 162e: 80 91 5b 02 lds r24, 0x025B 1632: 80 93 0b 02 sts 0x020B, r24 *pb++ = frontFan.RPMval[RPM_MAX]; 1636: 80 91 5c 02 lds r24, 0x025C 163a: 80 93 0c 02 sts 0x020C, r24 *pb++ = frontFan.minTEMPval; 163e: 80 91 5d 02 lds r24, 0x025D 1642: 80 93 0d 02 sts 0x020D, r24 *pb++ = frontFan.maxTEMPval; 1646: 80 91 5e 02 lds r24, 0x025E 164a: 80 93 0e 02 sts 0x020E, r24 164e: 10 e2 ldi r17, 0x20; 32 1650: cf e0 ldi r28, 0x0F; 15 1652: d2 e0 ldi r29, 0x02; 2 1654: 08 c0 rjmp .+16 ; 0x1666 <_Z16usartSendCommandhPKvh+0x24e> break; жаль, не догадался компилер использовать указатель А зря. Итог - внушительный, в два раза больший, размер функции. Также в коде есть одна немаленькая static inline функция, которая используется всего один раз (и то, понятно, инлайнится в тело вызывающей функции), но непонятно, почему остаётся её вторая копия? За короткое время знакомства с GCC понравилось: удобная реализация атомарности через макросы ATOMIC_BLOCK(), удобная обёртка для обработчиков прерываний вида ISR(vector_name){}. Что не понравилось: гиморрой с обработкой данных, расположенных во флеш - для их чтения необходимо использовать специальный макрос pgm_read_...(). В ИАРе достаточно объявить указатель типа __flash и можно работать с ним совершенно обычным образом Также не очень удобно каждый раз пользоваться PSTR() для обозначения in-line строк вида: printText(PSTR("some")). ИАР тут опять на высоте со своим __flash, так как подобная функция в нём декларируется как printText(char const __flash __flash * pointer), и вызов делается просто: printText("that`s cool")
|
|
|
|
|
Nov 24 2008, 19:57
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(IgorKossak @ Nov 24 2008, 20:59)  Боком выйдет то, что локальные переменные располагаются в стеке, что для больших массивов неоправданно расточительно. Да нет, массив всего 32 байта размером. Самое место на стёке. Лишь бы не уничтожился раньше времени Цитата(IgorKossak @ Nov 24 2008, 20:59)  Разве в случае известных адресов оптимизация не нужна? Действительно. При наличии статических данных тупо юзается абсолютная адресация. Никакой толковой оптимизации. Эх, чем дольше я сравниваю IAR и GCC и чем больше лазию по генерируемому ими коду, тем больше убеждаюсь - не стоит ждать от них хорошего, наиболее приближенного к "ручному" ассемблеру коду. Косячат оба. У GCC, также, как и у IAR, часто в циклах попадаются "обёрточные" конструкции: Код movw r26, r16 st X+, r30 movw r16, r26 А также гну очень любит юзать в циклах копирования данных в качестве счётчиков итераций 16-ти битные слова (это даже если переменная изначально имеет 8 бит ширины  ). Точнее, "счётчика" как такового не создаётся, вычисление окончания идёт путём сравнения адреса одного из указателей. Это, конечно, универсальное решение, но в случае небольших циклов (до 256 итераций) неоправданно расходуется память и производительность... Раз уже сел за Си, то лучше всего взять камень "потолще", побыстрее, и не париться
|
|
|
|
|
Nov 24 2008, 23:45
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(_Pasha @ Nov 25 2008, 01:56)  Вот так они, эти сишники и зомбируют. А что мешает узкие места прописывать асмом? Причем, не просто асмом, а асм+ срр... Ну если только совсем уж узкие Посмотрев как-то на инлайн-ассемблер я просто ужаснулся нагромождению скобок и кавычек: Код __asm__ __volatile__ ( "/* START EEPROM WRITE CRITICAL SECTION */\n\t" "in r0, %[__sreg] \n\t" "cli \n\t" "sbi %[__eecr], %[__eemwe] \n\t" "sbi %[__eecr], %[__eewe] \n\t" "out %[__sreg], r0 \n\t" "/* END EEPROM WRITE CRITICAL SECTION */" : : [__eecr] "i" (_SFR_IO_ADDR(EECR)), [__sreg] "i" (_SFR_IO_ADDR(SREG)), [__eemwe] "i" (EEMWE), [__eewe] "i" (EEWE) : "r0" ); Это не дело, так мучаться. А как делать правильно?
|
|
|
|
|
Nov 24 2008, 23:49
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(sonycman @ Nov 24 2008, 18:23)  жаль, не догадался компилер использовать указатель А зря. Итог - внушительный, в два раза больший, размер функции. А вы попробуйте чуть помочь компилятору примерно в таком ключе: Код unsigned char buffer[10];
typedef struct { unsigned char b0; unsigned char b1; } SimpleStruct;
typedef struct { unsigned char b0; unsigned char b1; unsigned char b2; unsigned char b3; unsigned char b4; SimpleStruct ss; unsigned char b5; unsigned char b6; unsigned char b7; unsigned char b8; } MyStruct;
MyStruct mystruct;
void copy(unsigned char *pd, MyStruct *ps) { MyStruct *p = ps; *pd++ = p->b7; *pd++ = p->b1; *pd++ = p->b5; *pd++ = p->ss.b0; *pd++ = p->b2; *pd++ = p->b0; *pd++ = p->ss.b1; *pd++ = p->b1; *pd++ = p->b3; *pd++ = p->b4; }
int main() { copy(buffer, &mystruct);
while (1); } И получите код ну никак не хуже IAR: Код void copy(unsigned char *pd, MyStruct *ps) { 5c: cf 93 push r28 5e: df 93 push r29 60: fc 01 movw r30, r24 62: db 01 movw r26, r22 MyStruct *p = ps; *pd++ = p->b7; 64: eb 01 movw r28, r22 66: 89 85 ldd r24, Y+9; 0x09 68: 81 93 st Z+, r24 *pd++ = p->b1; 6a: 89 81 ldd r24, Y+1; 0x01 6c: 81 93 st Z+, r24 *pd++ = p->b5; 6e: 8f 81 ldd r24, Y+7; 0x07 70: 81 93 st Z+, r24 *pd++ = p->ss.b0; 72: 8d 81 ldd r24, Y+5; 0x05 74: 81 93 st Z+, r24 *pd++ = p->b2; 76: 8a 81 ldd r24, Y+2; 0x02 78: 81 93 st Z+, r24 *pd++ = p->b0; 7a: 8c 91 ld r24, X 7c: 81 93 st Z+, r24 *pd++ = p->ss.b1; 7e: 8e 81 ldd r24, Y+6; 0x06 80: 81 93 st Z+, r24 *pd++ = p->b1; 82: 89 81 ldd r24, Y+1; 0x01 84: 81 93 st Z+, r24 *pd++ = p->b3; 86: 8b 81 ldd r24, Y+3; 0x03 88: 81 93 st Z+, r24 *pd++ = p->b4; 8a: 8c 81 ldd r24, Y+4; 0x04 8c: 80 83 st Z, r24 8e: df 91 pop r29 90: cf 91 pop r28 92: 08 95 ret Увы, у каждого компилятора свои фенечки...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|