|
|
  |
[avr-gcc]Как побороть лишнюю оптимизацию? |
|
|
|
Feb 4 2009, 13:38
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Добрый день. Столкнулся вот с какой незадачей - компиляция программы происходит так, что часть одной функции как бы выбрасывается из программы. Ошибок в функции нет, но что там говорить, вот эта функция: (функция "как есть", в целях понимания ничего не убирал, надеюсь поймёте) Код void processing_data(void) { if(mdns.mdfl[U] <= mdns.mdfl[PGSU1]) { mdns.mdfl[Conc] = mdns.mdfl[A1]*mdns.mdfl[U] + mdns.mdfl[B1]; } else { mdns.mdfl[Conc] = mdns.mdfl[A2]*mdns.mdfl[U] + mdns.mdfl[B2]; } char _s_disrec = 0; if(mdns.mdfl[Conc] < 0) { mdns.mdfl[Conc] = 0; } if(mdns.mdfl[Conc] >= mdns.mdfl[Pr]) { pereg(); } else if(mdns.mdfl[Conc] >= /*mdns.mdfl[P2]*/0.88) { _s_disrec = 1; if((flags&0x03 == 0) || (flags&0x03 == 1)) //если нет порогов или только первый { mdns.mdui[P1Count]++; mdns.mdui[P2Count]++; WriteByteIntoExtEEPROM(0X3E, mdns.mdWorkSpace[0X46]); WriteByteIntoExtEEPROM(0X3F, mdns.mdWorkSpace[0X47]); WriteByteIntoExtEEPROM(0X40, mdns.mdWorkSpace[0X48]); WriteByteIntoExtEEPROM(0X41, mdns.mdWorkSpace[0X49]); modbus_buf[9] = mdns.mdWorkSpace[0x48];//p2 modbus_buf[8] = mdns.mdWorkSpace[0x49];//p2 modbus_buf[7] = mdns.mdWorkSpace[0x46];//p1 modbus_buf[6] = mdns.mdWorkSpace[0x47];//p1 } flags |= (1 << 1); flags &= ~(1 << 0); modbus_buf[2] = flags; } else if(mdns.mdfl[Conc] >= mdns.mdfl[P1]) { if(flags&0x03 == 0) //если небыло до этого порога { mdns.mdui[P1Count]++; WriteByteIntoExtEEPROM(0X3E, mdns.mdWorkSpace[0X46]); WriteByteIntoExtEEPROM(0X3F, mdns.mdWorkSpace[0X47]); modbus_buf[9] = mdns.mdWorkSpace[0x48];//p2 modbus_buf[8] = mdns.mdWorkSpace[0x49];//p2 } flags |= (1 << 0); flags &= ~(1 << 1); modbus_buf[2] = flags; } else { flags &= ~(1 << 0); flags &= ~(1 << 1); modbus_buf[2] = flags; } if(_s_disrec == 0) stop_disrec |= 0x0F; } если упрощённо, то функция делает следующее: Код void processing_data(void) { расчитываем некое значение mdns.mdfl[Conc] if(проверяем - невышло ли значение сверх всяких норм) если да, то орём всем, чем можем и записываем сей факт в журнале
else if(проверяем - не слишком ли близко подошло значение к "сверх всяких норм") { верещим пищалкой, зажигаем два светодиода и делаем запись в журнале }
else if(проверяем - не превысило ли значение из ряда "нормальных значений") { верещим пищалкой, зажигаем один светодиод и делаем запись в журнале }
else { всё хорошо, продолжаем как ни в чём небыло }
} Так вот - вне зависимости от значения во второй и тетий if программа незаходит. Т.е. зачение расчитывается, я его спрашиваю по модбасу, оно соответсвует действительности, но ни один светодиод не загорается и звуковой извещатель всё время молчит. Поэтому я даже не знаю - толи эти if'ы не вошли в готовую программу, либо всё время заходит в последний иф. В живую получить значения выше mdns.mdfl[Pr] у меня нет возможности, поэтому этот if мне не проверить. В процессе отладки я закомментировал расчёты mdns.mdfl[Conc] просто присваивал этой переменной различные значения. Результат тотже (это в принципе неудивительно, тут ещё можно поверить оптимизатору), но если я этой переменной присваивал значение выше чем mdns.mdfl[Pr], то в первый if программа заходит. Из этого я могу сделать вывод, что оптимизации поддались все остальные if'ы. Можно ли это как-нибудь побороть? прочие исходные данные : avr-gcc (WinAVR 20080512) 4.3.0; уровень оптимизации "s" (меньше ставить нельзя, больше смысла нет).
|
|
|
|
|
Feb 5 2009, 05:58
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Код union { float mdfl[22]; unsigned int mdui[45]; char mdch[90]; unsigned char mduc[90]; unsigned char mdWorkSpace[90]; } mdns; //ModBusNameSpace
unsigned char flags;
unsigned char modbus_buf[16]; Соответсвенно все "Conc", "U", "A1" и т.д. - это const unsigned char.
|
|
|
|
|
Feb 5 2009, 06:57
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Цитата(MrYuran @ Feb 5 2009, 09:37)  Значит, надо взять пожирнее. Делать что-то без запаса - неразумно. Я за год одну прошивку последовательно пропатчил с 15 до 22 кБ. А вы что будете делать потом, ели вдруг (да наверняка) ещё что-нибудь добавится?
PS: буферы свои объявите volatile, наверняка в прерывании их меняете Насчёт запаса - просто есть уже готовое устройство, которое прошло все стадии разработок и меняться уже не будет. Более того - программа по всё это дело тоже уже готовая и запас свободного места составляет 25%. Эта ерунда проявилась после последней правки программы (до этого всё было нормально) и принципиально нового в принципе уже ничего не добавиться. Также следуя правилу о преждевременной оптимизации кода я этой оптимизацией и не занимался (я имею в виду С-шный код, который я пишу, а не компилятор). Думаю после этого свободного места будет процентов 40. Сейчас размер прошивки ~6,3 кб, использую восьмую атмегу с 8кб памяти. насчёт постскриптума - а разве volatile влияет на то, что эти переменные как то изменяются в прерывании? Объясните этот момент поподробней пожалуйста (я правда это не знаю  )
|
|
|
|
|
Feb 5 2009, 07:38
|

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

|
Цитата(UniBomb @ Feb 5 2009, 09:57)  принципиально нового в принципе уже ничего не добавиться к.г. правка программы заканчивается со смертью программиста  (и то не всегда) Цитата насчёт постскриптума - а разве volatile влияет на то, что эти переменные как то изменяются в прерывании? volatile объясняет компилятору, что не нужно слишком умничать и оптимизировать данную переменную. Он же не знает, что она может измениться где-то в другом потоке, и может решить, что раз переменная явно нигде не меняется, то и результат сравнения будет "как в прошлый раз". Я утрирую конечно, но просто все переменные, которые используются одновременно в прерываниях и где-то ещё, всегда объявляют как volatile.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
|
Feb 5 2009, 08:03
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Цитата(MrYuran @ Feb 5 2009, 10:38)  к.г. правка программы заканчивается со смертью программиста  (и то не всегда) Цитата(MrYuran @ Feb 5 2009, 10:38)  volatile объясняет компилятору, что не нужно слишком умничать и оптимизировать данную переменную. Он же не знает, что она может измениться где-то в другом потоке, и может решить, что раз переменная явно нигде не меняется, то и результат сравнения будет "как в прошлый раз". Я утрирую конечно, но просто все переменные, которые используются одновременно в прерываниях и где-то ещё, всегда объявляют как volatile. Объявил с volatile. Ничего не изменилоь... И кстате свои буферы я изменяю в каждой второй функции. Я не зря объявил msdn как union - этот буфер я передаю по модбасу, по своему "техническому" протоколу как по частям, так и всем буфером сразу, в процессе работы отдельные части изменяються постояно.
|
|
|
|
|
Feb 5 2009, 11:05
|

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

|
Цитата(UniBomb @ Feb 4 2009, 18:38)  В процессе отладки я закомментировал расчёты mdns.mdfl[Conc] просто присваивал этой переменной различные значения. Результат тотже (это в принципе неудивительно, тут ещё можно поверить оптимизатору), но если я этой переменной присваивал значение выше чем mdns.mdfl[Pr], то в первый if программа заходит. Из этого я могу сделать вывод, что оптимизации поддались все остальные if'ы. Можно ли это как-нибудь побороть? Напрашивается вывод, что mdns.mdfl[Pr] имеет значение меньшее, чем 0.88 и mdns.mdfl[P1]
--------------------
Всего наилучшего, Alex Mogilnikov
|
|
|
|
|
Feb 5 2009, 17:08
|

Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250

|
Вообще оптимизатор может "похозяйничать" с конструкцией типа if(){} только в том случае, если по его мнению условие в скобках всегда истино или всегда ложно. Отсюда следует вывод, что если оптимизатор проанализировав вычисление mdns.mdfl[Conc] решит что эта переменная всегда будет больше нуля, то первый if он выбросит. Аналогично и со вторым if. А вы mdns.mdfl[Conc] константы присваивали для проверки непосредственно перед if-ами? И при этом, при mdns.mdfl[Conc]=(например)10; в первый if все равно не заходит? Ну в этом случае, помнится мне были какие-то ключики для GCC (-funsigned-char, -funsigned-bitfields и кажется что-то еще было), чтобы он при компиляции без явного объявления переменной signed, по умолчанию считает переменную unsigned, в этом случае получилась бы как раз Ваша ситуация. Проверьте наличие таких ключей в make-файле. Все это справедливо, если причина "молчания" Вашего девайса действительно в оптимизаторе.
--------------------
- Бендер, ты же робот, зачем тебе пить пиво? - Незачем! Я могу бросить в любой момент!
|
|
|
|
|
Feb 6 2009, 06:29
|
Частый гость
 
Группа: Свой
Сообщений: 148
Регистрация: 26-05-05
Пользователь №: 5 416

|
Цитата(Rst7 @ Feb 5 2009, 12:47)  А в чем проблема? Натравите на данный модуль гнуся с ключем -S (т.е. остановится на ассемблировании), почитайте асмовский листинг. Может тогда станет понятно, что и как. Не то, что бы я не разбирался в ассемблерном коде, но на продолжительный взгляд всё там хорошо. И вот какая странность - в отладчике вроде всё работает... Цитата(alx2 @ Feb 5 2009, 14:05)  Напрашивается вывод, что mdns.mdfl[Pr] имеет значение меньшее, чем 0.88 и mdns.mdfl[P1] Нет, это искючено. Я проверял значения во время работы (путём опроса по 485-му) и всё значения были в норме. Цитата(injen-d @ Feb 5 2009, 20:08)  Вообще оптимизатор может "похозяйничать" с конструкцией типа if(){} только в том случае, если по его мнению условие в скобках всегда истино или всегда ложно. Отсюда следует вывод, что если оптимизатор проанализировав вычисление mdns.mdfl[Conc] решит что эта переменная всегда будет больше нуля, то первый if он выбросит. Аналогично и со вторым if. А вы mdns.mdfl[Conc] константы присваивали для проверки непосредственно перед if-ами? И при этом, при mdns.mdfl[Conc]=(например)10; в первый if все равно не заходит? Ну в этом случае, помнится мне были какие-то ключики для GCC (-funsigned-char, -funsigned-bitfields и кажется что-то еще было), чтобы он при компиляции без явного объявления переменной signed, по умолчанию считает переменную unsigned, в этом случае получилась бы как раз Ваша ситуация. Проверьте наличие таких ключей в make-файле. Все это справедливо, если причина "молчания" Вашего девайса действительно в оптимизаторе. Нет, значения присваивал в самом начале, перед всеми ифами. В этом случае всё происходит нормально... Насчёт ключей - щас гляну...
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|