Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: [avr-gcc]Как побороть лишнюю оптимизацию?
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
UniBomb
Добрый день. Столкнулся вот с какой незадачей - компиляция программы происходит так, что часть одной функции как бы выбрасывается из программы. Ошибок в функции нет, но что там говорить, вот эта функция:

(функция "как есть", в целях понимания ничего не убирал, надеюсь поймёте)

Код
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" (меньше ставить нельзя, больше смысла нет).
injen-d
Приведите объявления переменных, в частности mdns.mdfl - какого типа?
UniBomb
Код
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.
MrYuran
А без оптимизации работает?
UniBomb
а без оптимизации размер программ превышает размер памяти мк smile.gif Самый низкий уровень оптимизации, на выходе которой рзмер программы позволяет прошиться в мк - 2. Но при этом всё остаёться без изменений...
MrYuran
Цитата(UniBomb @ Feb 5 2009, 09:26) *
а без оптимизации размер программ превышает размер памяти мк smile.gif

Значит, надо взять пожирнее. Делать что-то без запаса - неразумно. Я за год одну прошивку последовательно пропатчил с 15 до 22 кБ.
А вы что будете делать потом, ели вдруг (да наверняка) ещё что-нибудь добавится?

PS: буферы свои объявите volatile, наверняка в прерывании их меняете
UniBomb
Цитата(MrYuran @ Feb 5 2009, 09:37) *
Значит, надо взять пожирнее. Делать что-то без запаса - неразумно. Я за год одну прошивку последовательно пропатчил с 15 до 22 кБ.
А вы что будете делать потом, ели вдруг (да наверняка) ещё что-нибудь добавится?

PS: буферы свои объявите volatile, наверняка в прерывании их меняете


Насчёт запаса - просто есть уже готовое устройство, которое прошло все стадии разработок и меняться уже не будет. Более того - программа по всё это дело тоже уже готовая и запас свободного места составляет 25%. Эта ерунда проявилась после последней правки программы (до этого всё было нормально) и принципиально нового в принципе уже ничего не добавиться. Также следуя правилу о преждевременной оптимизации кода я этой оптимизацией и не занимался (я имею в виду С-шный код, который я пишу, а не компилятор). Думаю после этого свободного места будет процентов 40. Сейчас размер прошивки ~6,3 кб, использую восьмую атмегу с 8кб памяти.


насчёт постскриптума - а разве volatile влияет на то, что эти переменные как то изменяются в прерывании? Объясните этот момент поподробней пожалуйста (я правда это не знаю biggrin.gif )
MrYuran
Цитата(UniBomb @ Feb 5 2009, 09:57) *
принципиально нового в принципе уже ничего не добавиться

к.г. правка программы заканчивается со смертью программиста biggrin.gif (и то не всегда)
Цитата
насчёт постскриптума - а разве volatile влияет на то, что эти переменные как то изменяются в прерывании?

volatile объясняет компилятору, что не нужно слишком умничать и оптимизировать данную переменную.
Он же не знает, что она может измениться где-то в другом потоке, и может решить, что раз переменная явно нигде не меняется, то и результат сравнения будет "как в прошлый раз".
Я утрирую конечно, но просто все переменные, которые используются одновременно в прерываниях и где-то ещё, всегда объявляют как volatile.
UniBomb
Цитата(MrYuran @ Feb 5 2009, 10:38) *
к.г. правка программы заканчивается со смертью программиста biggrin.gif (и то не всегда)

biggrin.gif


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

Объявил с volatile. Ничего не изменилоь... И кстате свои буферы я изменяю в каждой второй функции. Я не зря объявил msdn как union - этот буфер я передаю по модбасу, по своему "техническому" протоколу как по частям, так и всем буфером сразу, в процессе работы отдельные части изменяються постояно.
Rst7
Цитата
Поэтому я даже не знаю - толи эти if'ы не вошли в готовую программу, либо всё время заходит в последний иф.


А в чем проблема? Натравите на данный модуль гнуся с ключем -S (т.е. остановится на ассемблировании), почитайте асмовский листинг. Может тогда станет понятно, что и как.
alx2
Цитата(UniBomb @ Feb 4 2009, 18:38) *
В процессе отладки я закомментировал расчёты mdns.mdfl[Conc] просто присваивал этой переменной различные значения. Результат тотже (это в принципе неудивительно, тут ещё можно поверить оптимизатору), но если я этой переменной присваивал значение выше чем mdns.mdfl[Pr], то в первый if программа заходит. Из этого я могу сделать вывод, что оптимизации поддались все остальные if'ы. Можно ли это как-нибудь побороть?
Напрашивается вывод, что mdns.mdfl[Pr] имеет значение меньшее, чем 0.88 и mdns.mdfl[P1]
injen-d
Вообще оптимизатор может "похозяйничать" с конструкцией типа if(){} только в том случае, если по его мнению условие в скобках всегда истино или всегда ложно. Отсюда следует вывод, что если оптимизатор проанализировав вычисление mdns.mdfl[Conc] решит что эта переменная всегда будет больше нуля, то первый if он выбросит. Аналогично и со вторым if. А вы mdns.mdfl[Conc] константы присваивали для проверки непосредственно перед if-ами? И при этом, при mdns.mdfl[Conc]=(например)10; в первый if все равно не заходит? Ну в этом случае, помнится мне были какие-то ключики для GCC (-funsigned-char, -funsigned-bitfields и кажется что-то еще было), чтобы он при компиляции без явного объявления переменной signed, по умолчанию считает переменную unsigned, в этом случае получилась бы как раз Ваша ситуация. Проверьте наличие таких ключей в make-файле. Все это справедливо, если причина "молчания" Вашего девайса действительно в оптимизаторе.
UniBomb
Цитата(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-файле. Все это справедливо, если причина "молчания" Вашего девайса действительно в оптимизаторе.

Нет, значения присваивал в самом начале, перед всеми ифами. В этом случае всё происходит нормально... Насчёт ключей - щас гляну...
UniBomb
Всем спасибо за внимание, проблема разрешилась. Я немного упростил эту функцию и часть её вынес в другую. Всё заработало, хотя о причинах этого глюка я до сих пор могу только догадываться.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.