Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Странное предупреждение
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Страницы: 1, 2
scifi
Цитата(jcxz @ Jun 21 2018, 14:06) *
И по асму шагать не надо, надо выучить ассемблер и "глазами" аналитически сравнить си-исходник с асм-результатом. И только если в этом случае будут найдены несоответствия между ними - только в этом случае можно однозначно говорить о вине компилятора.

Советую взять современный GCC и дать ему ключики -Os -flto. При любом более-менее нетривиальном коде "аналитическое сравнение" легко способно перейти в бессонные ночи biggrin.gif
jcxz
Цитата(adnega @ Jun 21 2018, 13:25) *
компилятор генерит правильный s-файл. Иначе генерит таблицу, в которой смещения не помещаются.
Где тут моя ошибка? Где ошибка компилятора я разобрался и на всякий случай сменил компилятор (была сборка arm-kgp-eabi-procyon).

Из Вашего описания я понял, что асм-файл писали Вы сами....
Для таких малопопулярных ядер как ESP8266, вполне допускаю что компилятор гораздо более сырой, чем для main stream Cortex-M например.

Цитата(scifi @ Jun 21 2018, 14:09) *
Советую взять современный GCC и дать ему ключики -Os -flto. При любом более-менее нетривиальном коде "аналитическое сравнение" легко способно перейти в бессонные ночи biggrin.gif

У juvf функция очень тривиальная и маленькая. В худшем случае будет бессонный час. laughing.gif
scifi
Цитата(jcxz @ Jun 21 2018, 14:10) *
Для таких малопопулярных ядер как ESP8266, вполне допускаю что компилятор гораздо более сырой, чем для main stream Cortex-M например.

Пожалуйста, похожая история с Cortex-M: тыц.
jcxz
Цитата(juvf @ Jun 21 2018, 13:50) *
У меня црц считается с ошибкой всегда, когда вкл оптимизация, не изредка, а всегда. И всегда считается правильно с отключенной оптимизацией. Нету хаотичных и внезапных сбоев.

Это не устранение причины. Это как вместо лечения причины болезни, бороться с её симптомами.
Если Вы подозреваете, что виноват компилятор, то устранение бага в таком случае - замена компилятора. Ведь если он косячит в данной функции, то где гарантия что не косячит в других местах? Просто эти косяки сейчас не проявляются (например - по этим веткам ветвления не проходит управление, но при каком-то стечении обстоятельств в будущем оно пройдёт и баг получит уже пользователь).
Но вину компилятора сперва нужно однозначно доказать.
juvf
Цитата(jcxz @ Jun 21 2018, 16:06) *
При переполнении стека симптомы могут быть какие угодно: может fault вылететь, а могут просто данные испортиться.
я же писал, данные не портятся, в фолаут не вылетаю, а црц считает с ошибкой.

Цитата
Если Вы считаете, что в недостаточном объёме выделенной под стек памяти виноват оптимизатор, а не "пейсатель" кода, то больше разговаривать не о чем..... smile3046.gif
Я достаточно выделил памяти на стек. Без оптимизации глубины стека хватает с запасом. Если оптимизатор удвоил запросы ОЗУ на стек, то мне такой оптимизатор не нужен. laughing.gif
Во вторых, бывало вылазил за стек.... на разных проекта.... либо фолаут, либо данные портились. Это быстро обнаруживается. Тут идет подсчет црц, но неправильный. Ни чего не портиться и не падает.

jcxz
Цитата(scifi @ Jun 21 2018, 14:13) *
Пожалуйста, похожая история с Cortex-M: тыц.

Да я не спорю, что и в компиляторах есть косяки. Я даже сам несколько лет назад выкладывал сюда на форум описание одного из них.
Но я чётко доказал, что это именно косяк компилятора (это был IAR вроде v6.20 или v6.40).
И выложил и фрагмент си-кода и результат компиляции (ассемблер) и ключи компиляции, при которых этот результат получен. Чтобы каждый смог лично проверить.
juvf
Цитата(jcxz @ Jun 21 2018, 16:19) *
Ведь если он косячит в данной функции, то где гарантия что не косячит в других местах?
Нет гарантии. Все места проверяются глубоким тестированием. А если компилятор оптимизатор не косячит - то нет ни какой гарантии, что нет косяков пейсателя/компилятора в других местах. Все места проверяются глубоким тестированием, стрестестами и т.п. , Это касается любого компилятора/оптимизатора, любого кода.


Цитата(scifi @ Jun 21 2018, 16:04) *
Я так понимаю, версия про "volatile" была проверена и не подтвердилась? ....
конечно первым делом volatile.
Цитата
SPI1->SR нужно начинать читать не сразу, а через пару тактов, без оптимизации задержка получалась сама собой - как вариант.
Чуть не написал "Слона не увидел", но слона нет. Во первых в даташите про это ни чего не говориться, во вторых.... сначала готовлю данные, потом их отправляю в спи, не дожидаясь завершения ..... на русском сложно писать, написшу на си

Код
sleepMs(1000);
for()
{
//подготовка данных
waitSpi();
//запись данных в спи регистр.
}

в waitSpi() с оптимизацией не задерживаюсь ни когда, а должен не задерживаться только первый раз. После отправки данных до чтения регистра SPI1->SR проходит много времени, но меньше, чем выход 8 бит в спи.
jcxz
Цитата(juvf @ Jun 21 2018, 13:50) *
inline void waitSpi() { while( (SPI1->SR & (uint8_t)SPI_FLAG_BSY));} - вот этот код не работает с оптимизацией в пустом хороводе. И не изредка - а всегда. 100 раз из 100. А без оптимизации работает как часы. ни каких сбоев в обмене по SPI замечено не было.

Описание типов данных, какое ядро/МК, описание SPI_FLAG_BSY и декларации SPI1 где? Асм-результат с оптимизацией где?
Или с декларациями что-то не так или у вас в этом коде например гонки или куча других причин. laughing.gif
И опять - пример никак не свидетельствует о вине компилятора.
Вот приведу такой случай из своей практики:
Писал я как-то под CC5502 (TI DSP). Был простейший цикл типа Вашего выше: просто в цикле опрашивался флаг, типа: while (!flag);
Этот flag в состояние !=0 устанавливался в ISR завершения DMA-транзакции (цикл ждал завершения DMA).
И вот у меня возникла ситуация подобная Вашей: без оптимизации или с минимальной оптимизацией всё работает, а с полной оптимизацией - виснет в бесконечном ожидании в этом цикле и через некоторое время вылетает в bus-fault в DMA-контроллере. А дальше стало ещё хуже - выяснилось, что при добавлении/убирании строчек кода из совершенно других мест си-исходника, этот код иногда начинает работать. Причём работать 100%! Но при следующем редактировании исходника опять начинает падать в bus-fault (внимание adnega - очень знакомое поведение, не правда-ли? rolleyes.gif )

Видимо Вы бы уже сложили ручки и обвинили во всём компилятор. Но я продолжил рыть. И в конце-концов нашёл причину!
Оказалось, что при полной оптимизации код цикла получался такой короткий и быстрый, что CPU всё время был занят подкачкой команд в буфер предвыборки, только загрузил в конвеер команду условного перехода, пока грузил следующий пакет предвыборки за ней, то команда успевала выполниться, шёл сброс конвеера и загрузки предвыборки из начала цикла. Вобщем - тело цикла было длиной всего 2-3 такта. И если получалось что тело цикла располагалось на границе сегментов предвыборки (смещение начала цикла в памяти & 3 было == определённым значениям), то процессор полностью загружал шину к памяти своими запросами. А у него приоритет доступа к шине был выше чем у DMA-контроллера. DMA-контроллер считав данные из периферии, делал 512 попыток запроса доступа к шине ОЗУ у арбитра, не получал доступа и в конце концов останавливал работу с выставлением fault-а.
При добавлении/удалении строк кода в разных местах исходника, весь код сдвигался, соответственно - чтение тела цикла иногда влезало в 1 сегмент prefetch (требовало на 1 такт меньше времени) и код чудесным образом начинал работать (DMA-контроллер в этот 1 освободившийся такт успевал пролезть на шину и записать данные в ОЗУ).

Вот такой пример из практики. И что же - тут виноват компилятор? Нет, виноват конечно был я - не надо было располагать DMA-буфер и код в одном сегменте ОЗУ (МК не позволял задать для DMA приоритет доступа к шине выше чем CPU) laughing.gif
adnega
Цитата(jcxz @ Jun 21 2018, 14:12) *
Из Вашего описания я понял, что асм-файл писали Вы сами....

Как телепат телепату, откройте секрет, где в моем сообщении можно хоть как-то прийти к такому выводу?
В строчке
make.EXE: *** [obj_sw/esp8266.o] Error 1
видим, что не собирается цель esp8266.o
А ошибку видим в s-файле с роботским именем C:\Users\user\AppData\Local\Temp\ccShzzAY.s в месте похуже корзины.
Т.е. вы решили, что мой проект лежит в Temp, я сам написал asm-файл и дал ему имя ccShzzAY.s, а затем как-то
заставил компилятор ругаться при сборке esp8266.o причем русским языком ниже сказано про Си-исходник? КАК?
jcxz
Цитата(juvf @ Jun 21 2018, 14:46) *
в waitSpi() с оптимизацией не задерживаюсь ни когда, а должен не задерживаться только первый раз. После отправки данных до чтения регистра SPI1->SR проходит много времени, но меньше, чем выход 8 бит в спи.

Как одна из возможных причин:
Загружаете данные в буферный регистр SPI. Флаг DLY при этом не выставляется. А выставляется он только после того, как данные из буфера попадут в сдвиговый регистр. А попадут они туда после того как пройдёт некая задержка от завершения предыдущего SPI-фрейма (предыдущего поднятия CS=high), выдержки межфреймовой паузы (при CS=high), выдержки паузы после CS=fall и началом первого клока SCLK. Вот в этот момент возможно данные переместятся в сдвиговый регистр и выставится флаг DLY.
Т.е. - от момента записи данных в буферный регистр SPI до момента выставления флага DLY может пройти существенное время (в зависимости от частоты SCLK). А у Вас в программе возможно вы после записи очередной порции данных в буферный регистр SPI сразу переходите к waitSpi() и считаете что данные уже передались (так как флага нет), а они по-настоящему ещё и не начинали передаваться.
При запрете оптимизации же, код выполняется медленнее и DLY успевает выставиться, поэтому и работает.

Вот такой тип багов и называется "гонки". Как я выше и писал. И он конечно ваш, а не оптимизатора. laughing.gif

PS: Это как возможный вариант причины бага. Причина может быть и другой. Так как всего кода я не вижу и как работает SPI в вашем МК - не знаю.

Цитата(adnega @ Jun 21 2018, 15:01) *
А ошибку видим в s-файле с роботским именем C:\Users\user\AppData\Local\Temp\ccShzzAY.s в месте похуже корзины.
Т.е. вы решили, что мой проект лежит в Temp, я сам написал asm-файл и дал ему имя ccShzzAY.s, а затем как-то
заставил компилятор ругаться при сборке esp8266.o причем русским языком ниже сказано про Си-исходник? КАК?

Я не смотрю на имена файлов тем более пути. Достаточно только расширения. И про си-исходник там сказано только что что-то в нём меняете. Как вариант: после смены там функция становится больше, перемещается в другое место в памяти и эта функция вызывается из асм между метками .L274, .L276 - и команда вызова становится длиннее и расстояние между .L274 и .L276 увеличивается.

PS: Если хотите чтобы Вас понимали однозначно, излагайте свои мысли ясно.
juvf
Цитата(jcxz @ Jun 21 2018, 16:48) *
описание SPI_FLAG_BSY и декларации SPI1 где?
Вы мои посты читаете? все описания и декларации в приведённом коде.

Цитата
Как одна из возможных причин:....
Я же говорю, вы не читаете мои посты. Смотрите код. Наверно на си не понятно, напишу на русском.

CS - нет. СПИ-мастер.

1)спим секунду. если что-то и было в спи, то давно вышло.
2)готовим данные....
3)проверяем бизи - waitSpi()
4)записываем в SPI1->DR данные. Данные пишутся в тх регистр, и потом копируются в шифтРегистр. в этот момент должен встать флаг бизи.
6)если ещё есть данные для передачи, goto 2)

с момента записи в SPI1->DR до waitSpi() проходит не 1 такт цпу. Тут один поток...проверка на кол-во переданых данных, подготовка данных не быстрая, спешить не куда, всё равно ждать waitSpi().

scifi
Цитата(juvf @ Jun 21 2018, 15:29) *
CS - нет. СПИ-мастер.

1)спим секунду. если что-то и было в спи, то давно вышло.
2)готовим данные....
...

Суть в том, что вы замели проблему под ковёр, не разбираясь в причинах. В условиях цейтнота такое бывает оправдано, а вообще это некрасиво, не говоря уже о том, что эта проблема может вылезти в будущем. Плюс опыт - он ведь сын ошибок трудных. Вот, собственно, и всё. Лезть глубже в вашу систему сейчас едва ли продуктивно.
adnega
Цитата(jcxz @ Jun 21 2018, 15:11) *
PS: Если хотите чтобы Вас понимали однозначно, излагайте свои мысли ясно.

Дык, вы же заявляете: "Я не смотрю на имена файлов тем более пути".
Может, вам стоит более вдумчиво читать, что тут пишут, вместо упражнений в фантазировании? (которое уже даже не смешно).
Сейчас вам ясно, что виноват компилятор, а не я?
Сказанное "В приведённом Вами примере баг в Вашем коде, а не в компиляторе" не желаете опровергнуть и извиниться?
juvf
Цитата(jcxz @ Jun 21 2018, 17:11) *
Вот такой тип багов и называется "гонки". Как я выше и писал. И он конечно ваш, а не оптимизатора. laughing.gif
Допустим, гипотетически.... записал в спи-сд данные, что-то сделал пусть будет проверка for(), проверил бизи. между записью и бизи было времени достаточно для выставлдения флага бизи. нужно 1 мкс, f было 10 мкс. Код рабочий, глюков нет. Может такой код перваться прерыванием и 10 мкс могут только увеличиться.... до 100, до 200.... код от этого не упадет и всё будет работать.
Гипотетически!

Код
for()
{
waitSpi();
spi->sd = data_out;
somethinkDo();
}


Допустим такой код работает без оптимизации..... включили оптимизацию и появилась ваша гонка.... опять же гипотетически.... Вот вы взяли асм.... и начали исследовать, что там не так... и нашли ГОНКУ!!! Как её убрать? не нужно сразу читать SR, а нужно подождать начало передачи. Что делать? Поставить паузу.... Т.е. поставите оптимизатор, чтоб было быстрее, и потом поставите паузу, чтоб не было гонки? Я просто отключу оптимизатор в нужном месте и всё.

В таком случает я считаю нет ошибки в неоптимизированном исходном коде и нет ошибки компилятора. Есть одно - при включении оптимизатора код перестает работать. Я вам не пытаюсь доказать, что есть ошибка компилятора. я не знаю. я говорю, что при включении оптимизатора на весь код, на код без ошибок и без глюков - код может лечь. И это не ошибка кода.

Цитата
Суть в том, что вы замели проблему под ковёр, не разбираясь в причинах. В условиях цейтнота такое бывает оправдано
В чем то я с вами соглашусь.... Про цейтнот согласен, про проблему под ковром - нет. Дело в том, что проблема такая "оптимизированный waitSpi() не работает". Тут два пути: 1 - не использовать оптимизированный waitSpi(), 2 - искать причину в оптимизированном waitSpi(). Посмотрите код waitSpi - там по сути оптимизация не нужна. Там нужно указать volatile, что делается в SPL. Весь код функции - одна строчка. Я пошел по пути наименьшего сопротивления. Тоже самое можно сказать про црц и про другие случаи (не буду всё сюда валить). У меня ещё не было случаев, чтобы оптимизатор оголял ошибки в коде. Если есть ошибка в коде - она находится без всяких оптимизаторов. Горе программист, которому для нахождения ошибки нужен оптимизатор.
scifi
Цитата(juvf @ Jun 21 2018, 16:09) *
Дело в том, что проблема такая "оптимизированный waitSpi() не работает". Тут два пути: 1 - не использовать оптимизированный waitSpi(), 2 - искать причину в оптимизированном waitSpi().

Это совсем поверхностный взгляд на проблему. "Когда мокрые пальцы сую в розетку - бьёт током, а когда сухие - не бьёт. Буду совать в розетку сухие пальцы." laughing.gif
adnega
Цитата(juvf @ Jun 21 2018, 16:09) *
Т.е. поставите оптимизатор, чтоб было быстрее, и потом поставите паузу,

Именно.
Без for(delay = 0; delay < 20; delay++) __NOP(); не работает складно в железе, ибо
таймер питается частотой с предделителя и запись в регистр MDR_TIMER3->CH1_CNTRL1 не
приводит к должному результату, если после записи MDR_TIMER3->CH1_CNTRL не установить нужное число NOPов.
Код
                            MDR_TIMER3->CH1_CNTRL1 = CH_CNTRL1_FORCE_0;
                            MDR_TIMER3->CH1_CNTRL = (0 << MDR_TIMER_CH_CNTRL_OCCM);
                            MDR_TIMER3->CCR1 = last_cnt + temp;
                            MDR_TIMER3->CH1_CNTRL = (3 << MDR_TIMER_CH_CNTRL_OCCM);
                            for(delay = 0; delay < 20; delay++) __NOP();
                            MDR_TIMER3->CH1_CNTRL1 = CH_CNTRL1_WAIT_RISE;
                            //for(delay = 0; delay < 20; delay++) __NOP();
                            MDR_TIMER3->STATUS = ~(1 << MDR_TIMER_STATUS_CCR_REF1_EVENT);
                            //for(delay = 0; delay < 20; delay++) __NOP();
                            MDR_TIMER3->IE |= (1 << MDR_TIMER_IE_CCR_REF1_EVENT_IE);
                            pulse[0].state = PULSE_STATE_WAIT_RISE;

Телепаты в курсе, что это миландровский К1986ВЕ92 попил мою кровушку.
scifi
Цитата(adnega @ Jun 21 2018, 16:34) *
Телепаты в курсе, что это миландровский К1986ВЕ92 попил мою кровушку.

А не лучше ли вот так:
Код
MDR_TIMER3->CH1_CNTRL = NEW_VALUE;
while (MDR_TIMER3->CH1_CNTRL != NEW_VALUE);

???
adnega
Цитата(scifi @ Jun 21 2018, 16:40) *
А не лучше ли вот так:
Код
MDR_TIMER3->CH1_CNTRL = NEW_VALUE;
while (MDR_TIMER3->CH1_CNTRL != NEW_VALUE);

???

Не пройдет. Я так понял, что там это не просто регистр, а какой-то командный центр.
Запишется-прочитается на HCLK, но реальное железо отработает, только когда на него клок придет с предделителя.
Вроде, с RTC такое бывает - там нужно ждать синхронизации с блоком 32кГц, но там и битик есть, что синхронизация состоялась.
jcxz
Цитата(juvf @ Jun 21 2018, 15:29) *
Я же говорю, вы не читаете мои посты. Смотрите код. Наверно на си не понятно, напишу на русском.

Да пишите хоть на китайском, мне ваш код безразличен, это ведь не у меня при включении/выключении оптимизации он то работает, то нет. Мои исходники работают вне зависимости от того включена оптимизация или нет, у меня таких проблем нет.

Цитата(juvf @ Jun 21 2018, 15:29) *
1)спим секунду. если что-то и было в спи, то давно вышло.
2)готовим данные....
3)проверяем бизи - waitSpi()
4)записываем в SPI1->DR данные. Данные пишутся в тх регистр, и потом копируются в шифтРегистр. в этот момент должен встать флаг бизи.
6)если ещё есть данные для передачи, goto 2)

Должен да не обязан. Где между п.4 и п.6 проверка, что бизи установился? "Вы мои посты читаете"? Я о таком кривом подходе как здесь ещё несколько постов назад написал. Вот как раз такой код и будет работать в зависимости от уровня оптимизации, количества передаваемых данных, фаз луны.... А, ну да, зачем читать и думать, ведь всё уже выяснено - компилятор виноват! laughing.gif

Цитата(adnega @ Jun 21 2018, 15:57) *
Сказанное "В приведённом Вами примере баг в Вашем коде, а не в компиляторе" не желаете опровергнуть и извиниться?

Нет, не желаю так как причина баг не найдена. Вы не доказали никак вину компилятора. Да собственно там у вас и не баг в выполнении программы, а ошибка компиляции.

Цитата(juvf @ Jun 21 2018, 16:09) *
Допустим такой код работает без оптимизации..... включили оптимизацию и появилась ваша гонка....

Гонки у Вас всегда есть, а не только при вкл. оптимизации. Почитайте в инете что это такое. Надо писать код, свободный от такого.

Цитата(juvf @ Jun 21 2018, 16:09) *
Как её убрать? не нужно сразу читать SR, а нужно подождать начало передачи. Что делать? Поставить паузу.... Т.е. поставите оптимизатор, чтоб было быстрее, и потом поставите паузу, чтоб не было гонки? Я просто отключу оптимизатор в нужном месте и всё.

Правильно тут уже написали про Ваш стиль: Вместо подумать и понять как сделать правильно, замести проблему под ковёр. biggrin.gif
В том цикле достаточно всего лишь после записи данных в SPI, дождаться начала их передачи (выставления бизи). Но конечно это кривой метод, так как потребует запрета прерываний (чтобы вся передача не проскочила за время внезапно возникшего прерывания).
А чтобы написать правильно и корректно нужно вообще весь алгоритм этот изменить, использовать другие флаги, прерывания и пр.

Цитата(juvf @ Jun 21 2018, 16:09) *
Горе программист, которому для нахождения ошибки нужен оптимизатор.

Ещё горше тот, которому оптимизатор её нашёл, указал, а он прячет голову в песок.

Цитата(adnega @ Jun 21 2018, 16:34) *
Телепаты в курсе, что это миландровский К1986ВЕ92 попил мою кровушку.

И DSB/DMB не спасают?

Цитата(adnega @ Jun 21 2018, 16:56) *
Запишется-прочитается на HCLK, но реальное железо отработает, только когда на него клок придет с предделителя.

Тогда должны быть какие-то статусные биты, говорящие о завершении операции периферией.
juvf
Цитата
Правильно тут уже написали про Ваш стиль: Вместо подумать и понять как сделать правильно, замести проблему под ковёр.
Нет, не правильно. Есть задача - написать текст. Есть 2 карандаша. Один пишет, другой не пишет. Я не буду тратить время на выяснение, почему не пишет один карандаш, если я могу обойтись без него. Я другим карандашом текст напишу.
Вы выяснили и устранили, почему при вкл холодильника виснет CCS? Вы замелм пролему под ковёр заменили кабель усб и продолжили работать.

Цитата
Ещё горше тот, которому оптимизатор её нашёл
У меня оптимизатор ошибок не нашел.
Цитата
мне ваш код безразличен
Зачем вы просили код в студию? Хотели найти в нем ошибку. Нашли? Или чтоб написать "мне ваш код безразличен"?

Цитата
при включении/выключении оптимизации он то работает, то нет
Где я писал, что "то работает то нет"? У меня такого кода нет.
Цитата
А, ну да, зачем читать и думать, ведь всё уже выяснено - компилятор виноват!
Что компилятор виноват - это ваши слова, не нужно их мне приписывать.
Я же говорю вы не читаете мои посты, не вижу смысла дальнейшей дискуссии с вами по этому поводу.
adnega
Цитата(jcxz @ Jun 21 2018, 17:21) *
Нет, не желаю так как причина баг не найдена. Вы не доказали никак вину компилятора. Да собственно там у вас и не баг в выполнении программы, а ошибка компиляции.

Если компилятор не может собрать корректный код, то по вашему это не баг компилятора?
Вы понимаете, что компилятор, компилируя esp8266.c, создал временный s-файл, в котором смещение им же считается неверно?
А при эквивалентной перестановке строк в Си-исходнике он может собирать или не собирать исходник.
В этом я виноват?

Цитата(jcxz @ Jun 21 2018, 17:21) *
И DSB/DMB не спасают?

Очевидно же нет, т.к. у таймера как у периферийного блока своя собственная частота.

Пример из errata на этот проц привел в скрине.
"Обеспечивать необходимую задержку" тупо NOP`ами.

Насчет MDR_TIMER3->CH1_CNTRL там же есть бага 0013:
"В регистре есть бит, но он всегда читается как 1, при этом запись в него корректно задает режим".

Цитата(jcxz @ Jun 21 2018, 17:21) *
Тогда должны быть какие-то статусные биты, говорящие о завершении операции периферией.

А если их нет? В данном случае их нет, и производитель в аналогичной ситуации рекомендует "обеспечивать необходимую задержку".
VladislavS
Вместо стольких слов достаточно посмотреть листинг одной строчки, чтобы увидеть виноват ли оптимизатор.
jcxz
Цитата(VladislavS @ Jun 21 2018, 18:52) *
Вместо стольких слов достаточно посмотреть листинг одной строчки, чтобы увидеть виноват ли оптимизатор.

Я об этом неоднократно тут говорил. Но товарищ, винивший оптимизатор, так и не привёл этот самый листинг. Может он не знает что это такое? cool.gif
juvf
Цитата(jcxz @ Jun 21 2018, 12:05) *
Цитата(juvf @ Jun 21 2018, 09:24) *

Посмотрите сколько лишних операций в for у ТС! какие-то приведения типов, операторы, << и |, дополнительный j, операции j++!!! УЖАС!!!

И что? Современные оптимизаторы творят чудеса. И им по-барабану Ваши жалкие потуги заменить операции индексирования на указатели и подобное - они это и сами хорошо делают, даже ещё и лучше. Так что если бы код автора не был такой кривой, результат работы оптимизирующего компилятора мог быть лучше memcpy().


Цитата
Цитата
Попробуйте когда-нить

попробую обязательно.


Добрый день фантазёры, эльфы, а также программисты. Совсем недавно (2017-2018 год) занимался оптимизацией кода в STM8. Ручные потуги оптимизации давали очень хороший результат. Оптимизатор конечно оптимизировал код, но некоторый несложный рефакторинг давал значительно лучший результат. Может стм8 сырой? может арм действительно рулит? Проверил на арме.... собрал код ТС, улучшенный код ТС, а также просто memcpy(). В трёх случаях заполнял массив uin16_t [16] из массива uin8_t[32]. Измерял осциллографом.
улучшенный код ТС выглядит так:

Код
#define SIZ    32
uint8_t dataOut[SIZ+2];
uint16_t buffer[SIZ/2];
uint8_t *p1 = (uint8_t*)buffer;
uint8_t *p2 = (uint8_t*)&dataOut[0];
...
GPIO_SetBits(GPIOA, GPIO_Pin_5); //ТР2 = 1
//оптимизированный варинат ТС
for(int i = 0; i < SIZ; i++)
    p1[i] = p2[i];
GPIO_ResetBits(GPIOA, GPIO_Pin_5);


Результат - (код TC с "<<", "|", "++", "j") / (улучшенный код ТС) / (говноmemcpy() )
Не оптимизированный код дал результат 8/5/1.3 мкс
с оптимизацией по скорости -Ohs результат 3/0.5/0.5 мкс

кагбэ в примере всё выровнено к 4. Но серийные данные не всегда выровнены, поэтому усложнил задачу МК и приблизил к реальности, uint8_t *p2 = (uint8_t*)&dataOut[1];
получил без оптимизациии 8/5/2мкс, с оптимизацией -Ohs 3/2/1.7 мск

Результат на лицо. Априори. Вот вам и наряд в не очереди современные оптимизаторы!!!

ps проверял на стм32ф103, компилятор иар.
scifi
Цитата(juvf @ Jun 22 2018, 08:11) *
Добрый день фантазёры, эльфы, а также программисты. Совсем недавно (2017-2018 год) занимался оптимизацией кода в STM8. Ручные потуги оптимизации давали очень хороший результат. Оптимизатор конечно оптимизировал код, но некоторый несложный рефакторинг давал значительно лучший результат. Может стм8 сырой?

Кстати, стм8 - особый случай. Там нет выдающихся компиляторов. Яр на уровне исходника умеет выкидывать лишние переменные и т.д., но машинный код делает плохенький. Видимо, избрана плохая стратегия генерации кода, и/или реализация подкачала. Они там придумали виртуальные регистры, предположительно, чтобы компилятору было удобнее. Результат так себе. Недавно попробовал космик, там код генерится практически в лоб, строчка исходника - несколько инструкций. Каждая локальная переменная выделяется на стеке. Результат в целом лучше, чем у яра. Ну и зная о прямом соответствии исходника и машинного кода, простор для микрооптимизаций на уровне исходника огромный.
jcxz
Цитата(juvf @ Jun 22 2018, 08:11) *
ps проверял на стм32ф103, компилятор иар.

1.Не держите всех тут за дураков: эта ваша "проверка" - это для домохозяек аргумент.
В первом случае что именно проверили? Что в случае цикла и в случае memcpy() компилятор очевидно заменил и то и другое циклом типа:
Код
   MOVS Rn, #32/4
p: LDR Rx, [Ry], #4
   STR Rx, [Rz], #4
   SUBS Rn, Rn, #1
   BNE p

или вообще развернул цикл в линейный код?
Так я об этом ещё много постов назад говорил, что Ваш memcpy() в бОльшей части случаев не даст выигрыша. laughing.gif
И далее - нашли какой-то случай, когда определённый компилятор, при определённых ключах компиляции даст небольшой выигрыш?
Так я опять же уже давно говорил, что при определённых условиях и memcpy может быть быстрее.
А теперь попробуйте задать размер переменным и указатели переменными, так чтобы они не могли быть вычислены на этапе компиляции.
Измерить всю функцию а не какой-то непонятно как выбранный участок.
Вывод из этих "проверок" можно сделать только один: компилятор оказался умнее вас. laughing.gif

2.Измерять миллиметровые расстояния линейкой с метровыми делениями - это типичный ардуино-подход.
Позвольте узнать - сколько времени заняли ваши конструкции с установками/сбросами GPIO? Как они оптимизировались в случаях разных тестов?
У вас они дали больше погрешности чем весь "измеряемый" код.
Нормальное измерение длительностей (тем более таких малых) делают по таймеру, но никак не по GPIO.

Вся ваша проверка яйца выеденного не стоит. Этими проверками Вы как раз и показали всем тут свой "уровень" программирования и понимания сего процесса.
И проверять там нечего, достаточно взглянуть на листинг как Вам тут уже неоднократно говорили.
Впрочем похоже для вас это пустой звук. Так же как и о самом предмете оптимального программирования Вы не имеете никакого понятия.
juvf
ваш ответ - тоже априори. много слюней, воды, телепатии и всё мимо. Так ведут себя диванные эксперты.

Цитата(jcxz @ Jun 22 2018, 12:37) *
компилятор очевидно заменил и то и другое циклом типа:
Код
   MOVS Rn, #32/4
p: LDR Rx, [Ry], #4
   STR Rx, [Rz], #4
   SUBS Rn, Rn, #1
   BNE p
даже близко не угадали. ни одной строчки кода ))))

Цитата
или вообще развернул цикл в линейный код?
- опять мимо
Цитата
что Ваш memcpy() в бОльшей части случаев не даст выигрыша.
ещё раз мимо.

Цитата
Позвольте узнать - сколько времени заняли ваши конструкции с установками/сбросами GPIO?
Сначала проверил, сколько времени будет установка и сброс GPIO - с -Ohs составило 300 нс в каждом тесте. Результат показанный ранее, был с учетом погрешности GPIO.

Цитата
Нормальное измерение длительностей (тем более таких малых) делают по таймеру, но никак не по GPIO.
Нормальные измерения длительностей делают осциллографом, анализаторам, а не внутренними таймерами. Осциллограф даст более точное измерение (тем более он поверенный), нежели внутренний таймер МК, когда частота МК на порядок меньше полосы осциллографа. И генератор МК ±вагонИтележка, по сравнению с поверенными средствами измерения. Что ваш внутренний таймер, когда система должна среагировать на внешние прерывание/событие, обработать данные и выдать признак готовности, например дернуть регистр GPIO/DMA/UART? Это реальное время и реальный мир, а не ваша Нарния ваши фантазии с таймерами. Как раз таки осциллограф даст точность в мкм, а таймер в метрах.
Вы предлагаете Измерять миллиметровые расстояния линейкой с метровыми делениями - это типичный эльфо-подход.

Цитата
И проверять там нечего, достаточно взглянуть на листинг
Дак посмотрите, оторвитесь от дивана и посмотрите, вместо того чтобы тут сочинения писать. Я то посмотрел.... исходный код ТС с << | j более грамоздкий в асме, нежели чем без этих лишних операторов или memcpy(). Впрочем похоже для вас это пустой звук. Так же как и о самом предмете оптимального программирования Вы не имеете никакого понятия.

Оставайтесь прибывать в своих фантазиях. laughing.gif
jcxz
Цитата(juvf @ Jun 22 2018, 12:13) *
Нормальные измерения длительностей делают осциллографом, анализаторам, а не внутренними таймерами. Осциллограф даст более точное измерение (тем более он поверенный),

Да уж... цена вам как специалисту теперь уже достаточно ясна. Понятно почему все вокруг виноваты: и компиляторы и Тексас и другие виноваты в ваших проблемах - то CRC не считается, то SPI не работает, то процессор не отлаживается. Больше говорить с вами не о чем.... smile3046.gif
Из-за генератора МК видите ли неточность таймера возникает. А то что и работа GPIO и выполнение этой кучи кода (которая ещё и по-разному может скомпилиться) зависят от этого же самого генератора об этом конечно не подумали? А то что вместо прямого измерения, делается какое-то косвенное на которое кроме кучи разных факторов и режимы работы пинов влияют тоже не подумали? И поверенность осциллографа ещё сюда приплели. biggrin.gif
juvf
Цитата(jcxz @ Jun 22 2018, 14:31) *
Ну, даешь, ядрена вошь!
И олень тебе не гож?
А вчерась мытарил душу:
Вынь оленя да положь!..

То дай код, в нём ошибка! то новый вымыслы про стек... то внезапно код мой безразличен... то предложение проверить да проверь... то проверять там нечего... виртуоз-переобувальщик. а когда все таки проверил - вдруг проверка неугодная стала!!!
аргументы кончились, понеслось что-то абстрактное, типа "кучи разных факторов" и оскорбление негативная оценка оппонента, типичное поведения.... ну вы поняли кого...
Цитата
Попробуйте когда-нить не теоретизировать внустую, а скомпилировать и посмотреть разные варианты с копированием в цикле на разных компиляторах с включённой полной оптимизацией по скорости и с разными условиями цикла (короткий цикл/длинный, условия окончания и указатели - переменные или известны на этапе компиляции). И будете удивлены.
вот тут вы правы, соглашусь!!! Очень удивился. memcpy() на порядок быстрее for-loop. Перепробывал с разными вариантами, с переменными размерами массива и указателями, неизвестными на этапе компиляции. в тактах процессора примерно 90 к 700(без gpio, таймеров и прочей "кучи разных факторов"). Причем оптимизация практически не влияет на memcpy(). Он всегда быстрый. Вашим for даже и не снилась такая скорость.

устали вы меня.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.