|
WinAVR-20081205 и тенденции, С каждым релизом WinAVR размер кода растет :( |
|
|
|
Feb 12 2009, 07:19
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Я знаю, что на этом форуме присутствуют люди, которые не только глубоко знают GCC и, в частности, WinAVR, но и участвуют в той или иной мере в совершенствовании этих продуктов. Поэтому в первую очередь мой вопрос к ним. Я понимаю, что мои вопросы почти риторические, но беспокойство от них у меня сильное...
Скачал WinAVR-20081205 (до этого был 20080610), провел тест на проекте для AT90CAN128. Было 18204 байт результрующего кода (WinAVR 20080610), стало 18350 байт. Исходник не менял, естественно, как и все параметры сборки проекта. Ранее при переходе с 20080411 так же было замечено увеличение итогового кода для проекта. То есть я делаю вывод, что от релиза к релизу GCC генерирует все менее и менее компактный код для AVR (про другие платформы не скажу, ибо не пользуюсь). Неоднократно были замечены всякие странные фокусы при сохранении регистров в прологе функций, некоторые "чудеса" оптимизации и "странности" в обработчиках прерываний (заглядываю на AVR Freaks)...
Что это? Целенаправленное стремление снизить качество GCC для AVR, косвенные следствия каких-то неведомых мне улучшений, непредвиденные последствия исправления багов или что-то еще? Казалось бы, добавилась поддержка новых микроконтроллкров - и на тебе: поддержка старых ухудшилась... Чего ждать в будущем? Единственный качественный бесплатный компилятор - неужели он обречен?!
Может быть, есть какие-то рекомендации по борьбе с такими особенностями? скажем, какие-то ключи компилятора или еще что-то, что позволит получить хотя бы прежний код с новым компилятором?
P.S. Пожалуйста, не надо ответов типа "хотите бесплатно - жрите, что дают!"... Ведь смысл бесплатного продукта не в том, чтобы унизить и заставить жрать помои...
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 12 2009, 08:25
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(_Pasha @ Feb 12 2009, 10:54)  Когда я "находил 10 отличий", дело было в более агрессивном разворачивании функций и небольших циклов в инлайны. Кроме того, сохранение регистров при входе в main() и их восстановление при выходе (т.е. никогда) для моих приложений не нужно. Это все отключаемые вещи. Видимо, набор настроек по умолчанию пока еще не устоялся. с моей точки зрения, сохранение чего бы то ни было при входе в main() для AVR без ОС - это вообще никогда не нужно! логичнее было бы сделать опцию именно для включения сохранения контекста main() для всяких многозадачных ОС... все-таки для AVR это скорее исключение, чем правило. и, кстати, как пролог main() отключить? а вот про циклы и инлайны - разговор другой... какие именно опции следует включать-выключать, чтобы избавиться от излишней агрессивности оптимизатора? или наоборот, перестроить его агрессивность в сторону компактности кода, а не скорости...
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 12 2009, 08:57
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(ARV @ Feb 12 2009, 12:25)  и, кстати, как пролог main() отключить? Я делаю так, как делать нельзя Код int main (void) __attribute__((naked)); только потому, что main() никогда не содержит локальных переменных в своем теле. В более общем случае надо указывать атрибут OS_main http://gcc.gnu.org/ml/gcc-patches/2008-04/msg00283.html Цитата какие именно опции следует включать-выключать, чтобы избавиться от излишней агрессивности оптимизатора? Была тема недавно, сейчас не могу найти: 1.Поиграться со значением штрафа --param inline-call-cost 2. Не брезговать квалификатором static для местных локальных функций 3. В особо мистических случаях - явно указывать __attribute__((noinline)) до выяснения причин излишней инлайнизации. 4. -fno-unroll-loops это запретить разворачивать циклы
|
|
|
|
|
Feb 12 2009, 09:33
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
в конкретно моем случае я перебрал все опции оптимизации, затрагивающие циклы, включая и выключая их - в лучшем случае изменения размеров не обнаружено, в худшем, естественно, увеличение... -fcall-prologues помогает здорово, но ведь по отношению к предыдущей версии это как-то не честно  static, атрибуты и прочее - это все понятно, речь идет только о том, как компилятор воспринимает уже имеющийся исходник. т.е. оптимизация методом правки исходника не затрагивается в данном контексте. про OS_main уже встречал где-то здесь, однако, в официальный релиз этот патч не вошел? в документации нет ни слова...
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 12 2009, 09:47
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(ARV @ Feb 12 2009, 10:19)  Было 18204 байт результрующего кода (WinAVR 20080610), стало 18350 байт. Итого: (18350-18204)/18204 = 0,8% Стоит ли паниковать? Как говорится, тяжело менять, ничего не меняя, нельзя приготовить омлет, не разбив яйца, на всех не угодишь и т.д. В конце концов, никто не запрещает Вам пользоваться старой версией или собрать новую под свои личные потребности.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Feb 12 2009, 09:54
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(MrYuran @ Feb 12 2009, 12:47)  Итого: (18350-18204)/18204 = 0,8% Стоит ли паниковать? Как говорится, тяжело менять, ничего не меняя, нельзя приготовить омлет, не разбив яйца, на всех не угодишь и т.д. В конце концов, никто не запрещает Вам пользоваться старой версией или собрать новую под свои личные потребности. если каждый раз для забивания гвоздя отливать для себя удобный молоток - это немножко отдает идиотизмом... а на счет паники - дело-то в другом! для attiny2313 или тем более attiny13 каждые 100 байт могут стать смертельными! какие 100 - даже десять... я устанавливаю новую версию с надеждой. что в ней меньше ошибок, багов и т.п., да и поддержку новых процессоров хотелось бы иметь под рукой... и не хочется при этом лишаться старых заделов или разводить кучу подборок компиляторов под разные цели... поймите меня правильно. P.S. не надо про ассемблер для тини - я в курсе
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 12 2009, 09:56
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Я добавил последний AVR-libc в 20071221. Держу на всякий случай, т.к. к нему вообще никаких претензий не было. Цитата(demiurg_spb @ Feb 12 2009, 12:52)  Кстати, на младших контроллерах очень полезно включать такую вот опцию: Код CFLAGS += -mshort-calls СтоИт в аврстудии по умолчанию
|
|
|
|
|
Feb 12 2009, 10:00
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(demiurg_spb @ Feb 12 2009, 12:52)  Кстати, на младших контроллерах очень полезно включать такую вот опцию: Код CFLAGS += -mshort-calls а в чем смысл? в младших контроллерах все вызовы и так короткие (rcall)... -Wl,-relax помогает не хуже
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 12 2009, 10:32
|

Местный
  
Группа: Участник
Сообщений: 340
Регистрация: 25-10-05
Из: Пермь, Россия
Пользователь №: 10 091

|
Цитата(ARV @ Feb 12 2009, 12:19)  Было 18204 байт результрующего кода (WinAVR 20080610), стало 18350 байт. Хочу заметить, что размер кода - не единственно возможный критерий качества оптимизации. Может может там с оптимизацией по скорости выполнения стало лучше? Цитата(ARV @ Feb 12 2009, 13:25)  с моей точки зрения, сохранение чего бы то ни было при входе в main() для AVR без ОС - это вообще никогда не нужно! логичнее было бы сделать опцию именно для включения сохранения контекста main() Не согласен. Во-первых, для указания компилятору, что из функции (любой, а не только main!) никогда не выполняется возврат, существует специальный атрибут. во-вторых, сохранение регистров, которые потом не будут нужны, не нарушает работу программы, а лишь делает код не таким оптимальным, как мог бы. Обратное же (несохранение регистров, которые впоследствии нужны) нарушит работу программы. Поэтому дефолтным поведением должно быть именно сохранение регистров (если специально не указано, что функция noreturn). Цитата(ARV @ Feb 12 2009, 14:33)  в конкретно моем случае я перебрал все опции оптимизации, затрагивающие циклы, включая и выключая их - в лучшем случае изменения размеров не обнаружено Предлагаю гвоворить более конкретно: вот пример кода, вот результат компиляции gcc такой-то версии с такими-то опциями, а вот - другой версии. Или с другими опциями. Вот анализ арботы оптимизатора. А так - совершенно беспредметный разговор получается...
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Feb 12 2009, 10:45
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
У меня странная проблема на большом проекте 60КБ и mega1281 опция -Wl,-relax приводит к краху линковки... avr-gcc (WinAVR 20081205) 4.3.2 Код #---------------- Linker Options ---------------- # -Wl,...: tell GCC to pass this to linker. # -Map: create map file # --cref: add cross reference to map file LDFLAGS = LDFLAGS += -Wl,-Map=$(TARGET).map,--cref LDFLAGS += -Wl,-relax LDFLAGS += $(EXTMEMOPTS) LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) Linking: ../bin/Paragraph4/Paragraph.elf avr-gcc -mmcu=atmega1281 -I. -gdwarf-2 -DF_CPU=14745600UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=.............. --output ../bin/Paragraph4/Paragraph.elf -Wl,-Map=../bin/Paragraph4/Paragraph.map,--cref -Wl,-relax -Wl,-u,vfprintf -lprintf_flt -lm make: *** [../bin/Paragraph4/Paragraph.elf] Error 1 Проверил ещё на нескольких проектах при добавлении LDFLAGS += -Wl,--relax на некоторых из них происходит крах линкера (см. картинку во вложенном файле). Что это? И как быть?
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Feb 12 2009, 10:55
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
1. в настоящее время меня интересует качество оптимизации именно по размеру, т.е. -Os. до сего момента никогда -O3 не давало в итоге меньший размер кода, чем -Os. в частности, упомянутый проект выдал 30254 байт при -O3.
2. если бы main() не стояла особняком среди прочих функций Си-программы, я был бы готов с вами согласиться. но это особая функция, потому для нее вполне можно по умолчанию использовать особые режимы генерации кода. тем более для AVR, для которых наличие ОС, вызывающей main(), все же скорее исключение, чем правило.
3. к сожалению, я установил новый WinAVR поверх старого, и пока что не спешу делать откат - возможно, все решится меньшей кровью. потому могу сравнивать только то, о чем уже сказал: есть результат компиляции проекта с опцией -Os без других специальных мер старым WinAVR, и есть новый WinAVR, дающий с теми же опциями проекта худший результат. теперь идет поиск опций, позволяющих добиться прежних результатов с новым компилятором.
пока что наибольший эффект дает применение --relax для линкера и -fcall-prologues для компилятора. однако, я очень сомневаюсь, что эти же опции помогут, например, для atmega8 (--relax уж точно не поможет)... а хочется найти универсальное решение проблемы.
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 12 2009, 11:17
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(ARV @ Feb 12 2009, 10:19)  Скачал WinAVR-20081205 (до этого был 20080610), провел тест на проекте для AT90CAN128. Было 18204 байт результрующего кода (WinAVR 20080610), стало 18350 байт. Проверте, как влияет на размер кода -fno-split-wide-types. Анатолий.
Сообщение отредактировал aesok - Feb 12 2009, 11:30
|
|
|
|
|
Feb 12 2009, 11:27
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(aesok @ Feb 12 2009, 14:17)  Проверте, как влияет на размер кода -fno-split-wide-types.
Анатолий. влияет: 18278 байт стало. но до стартовых 18204 еще есть резерв  этот параметр действует одинаково на всех контроллерах? demiurg_spb, подправьте свой пост, пожалуйста: ну невозможно пользоваться форумом - все разъехалось вширь донельзя!
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 12 2009, 11:38
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ARV @ Feb 12 2009, 14:27)  влияет: 18278 байт стало. но до стартовых 18204 еще есть резерв  этот параметр действует одинаково на всех контроллерах? demiurg_spb, подправьте свой пост, пожалуйста: ну невозможно пользоваться форумом - все разъехалось вширь донельзя! Поправил. У меня в фаерфоксе ничего не разъезжалось.. И у меня на 102 байта уменьшилось на 60КБ проекте. А что этот параметр означает-то? В доке тишина (в WinAVR\doc нет файлов, содержащих этот параметр)...
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Feb 12 2009, 11:45
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(ARV @ Feb 12 2009, 14:27)  влияет: 18278 байт стало. но до стартовых 18204 еще есть резерв  этот параметр действует одинаково на всех контроллерах? да. В этом проекте используются функции для работы с EEPROM из avr-libc? Цитата(demiurg_spb @ Feb 12 2009, 14:38)  А что этот параметр означает-то? В доке тишина (в WinAVR\doc нет файлов, содержащих этот параметр)... это паремет GCC и задокументираван в GCC 4.3.3 Manual. Цитата -fsplit-wide-types When using a type that occupies multiple registers, such as long long on a 32-bit system, split the registers apart and allocate them independently. This normally generates better code for those types, but may make debugging more difficult. Enabled at levels -O, -O2, -O3, -Os.
Сообщение отредактировал aesok - Feb 12 2009, 11:42
|
|
|
|
|
Feb 12 2009, 11:55
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
На этой странице не встречается "fno-split-wide-types" Цитата(_Pasha @ Feb 12 2009, 14:45)  Ступил... Нашёл что надо. Спасибо. Есть дока по "fsplit-wide-types". Теперь совсем неясно стало. Если разделять по несвязанным регистрам то код должен уменьшаться а тут мы запрещаем split и он уменьшается. Непонятно.... А на мелком проекте 5КБ код вырос на 4 байта
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Feb 12 2009, 12:17
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
--param -inline-call-cost=0.........17902 =1,2,3..... 17820=4,5.......17988 =6,7,8.....18002 =9..........18036 =10,11.....18292 =12.........исходные 18350 при дальнейшем росте значения идет так же рост размера  при этом никакие другие параметры не использовал! комбинация -mcall-prologues -fno-split-wide-types --param -inline-call-cost=1 -Wl,-relax дает 17112 байт! более чем на килобайт меньше отправной точки! (правда, в железе не проверил - работает оно или нет?) :D это предел? еще хачу!  P.S. интересно, а со старым компилятором сколько бы вышло?  проверю обязательно!
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Feb 12 2009, 12:45
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(ARV @ Feb 12 2009, 15:17)  при этом никакие другие параметры не использовал! комбинация -mcall-prologues -fno-split-wide-types --param -inline-call-cost=1 -Wl,-relax дает 17112 байт! более чем на килобайт меньше отправной точки! (правда, в железе не проверил - работает оно или нет?) :D По моим наблюдениям GCC 4.3 лучше чем 4.2 процента на 3. GCC 4.4 будет посередине между ними. Про -fsplit-wide-types постораюсь вечером расказать. Анатолий.
|
|
|
|
|
Feb 12 2009, 15:27
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(alx2 @ Feb 12 2009, 12:32)  Поэтому дефолтным поведением должно быть именно сохранение регистров (если специально не указано, что функция noreturn). Буквально сегодня добавил в mspgcc проверку, есть ли выход из функции. Если выхода нет - не сохраняются регистры и не генерится эпилог. Т.е. этакий автоматический __attribute__((noreturn)). Судя по листингу - получается. Даже для main(). Не знаю насколько все изменилось в gcc 4.x по сравнению с 3.х, но можно предположить, что возможность такой проверки осталась - ведь компилятор как-то умеет генерить предупреждения об отсутствии return в функции, возвращающей значения и о наличии точек выхода в функции с атрибутом noreturn. Остается дописать по одному условию в функции генерации пролога и эпилога. Цитата(ARV @ Feb 12 2009, 14:17)  это предел? еще хачу!  http://electronix.ru/forum/index.php?s=&am...st&p=393663
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Feb 12 2009, 21:34
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Сергей Борщ @ Feb 12 2009, 17:27)  Т.е. этакий автоматический __attribute__((noreturn)). Автоматический это хорошо, конечно, но пренебрагать явным не стоит - он предназачен не толко для компиляции данной функции, но и для вызывающих её. Простейший пример (в жизни врядли такой будет, но это первое, что взбрело в голову для - форсирования размещения аргументов на стеке). Код __attribute__((__noreturn__)) void foo(char *p, ...);
void moo(char *p, ...);
char cc[10];
void baa(unsigned char a) { if(a) foo(cc, 1313); moo(cc, 169); } Код .type kwa, @function kwa: ldi r18,lo8(cc) ldi r19,hi8(cc) tst r24 breq .L2 ldi r24,lo8(1313) ldi r25,hi8(1313) push r25 push r24 push r19 push r18 rcall foo ; ----------- .L2: ldi r24,lo8(169) ldi r25,hi8(169) push r25 push r24 push r19 push r18 rcall moo pop __tmp_reg__ pop __tmp_reg__ pop __tmp_reg__ pop __tmp_reg__ ret из foo "не должно быть" возврата, поэтому нет смысла после неё восстанавливать стек (собственно, можно было и rjmp нарисовать...) Аналогично - если у вызывающей функции набралось что-то в caller-save-регистрах, то перед вызовом noreturn-функции она не будет эти регистры сохранять.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Feb 13 2009, 08:17
|
Знающий
   
Группа: Участник
Сообщений: 596
Регистрация: 26-05-06
Из: Москва
Пользователь №: 17 484

|
Цитата(ARV @ Feb 13 2009, 10:38)  а вот еще вопрос (не совсем в тему, но касающийся оптимизации размера): каким образом убрать из кода таблицу векторов прерываний, если прерывания не используются, чтобы "полезный" код начинался с адреса 0х000? актуально для tiny-проектов. Я так ни когда не делал, но можете попробовать этот вариант. Не знаю получиться ли так в WinAVR. 1. качаете исходники avr-libc и распаковываете их; 2. находите заголовычный файл для вашего контроллера avr-libc\include\avr\io<нужный_контроллер>.h, и правите макрос _VECTORS_SIZE, в соттветствии с необходимым количеством векторов. Учтите _VECTORS_SIZE размер таблицы векторов в байтах; 3. компилируете avr-libc; Код mkdir build cd build ../avr-libc/configure -v --host=avr --prefix=/tools/ make make install - не делаете; 4. ищете statr-up файл для вашего контроллера build\avr\lib\avr<2,3,....51>\<нужный_контроллер>\gcrt1.o 5. линкуете этот gcrt1.o в ваш проект вместо стандартного. Анатолий.
Сообщение отредактировал aesok - Feb 13 2009, 08:23
|
|
|
|
|
Feb 13 2009, 08:38
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(aesok @ Feb 13 2009, 11:31)  Пока только так... слово "пока" зарождает надежду... а нельзя ли принципиально удалять таблицу векторов, если имеется опция -mno-interrupts ? по-моему, очень логично...
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|