Еще раз про оптимизацию кода.
- Войдите на сайт для отправки комментариев
Есть стандартная проблема: написанный код не помещается в память МК. В моем случае используется Arduino Nano со стандартными 32кБ памяти на борту. Заменить ее на что-то более вместительное нет физической возможности, устройство уже собрано и переделывать его под новое железо дорогого стоит. Под все мои хотелки, по грубой оценке, памяти нужно раза в 1,5-2 больше. В природе, конечно, уже есть Arduino Nano Every, которая, судя по всему, могла бы стать выходом из положения (при условии ее полной электрической совместимости с обычной Nano), но во-первых китайцы ее еще не успели клонировать, а покупать оригинал не сильно хочется, и во-вторых эта плата еще не переболела детскими болезнями: ее пока чаще ругают чем хвалят. Да и 48кБ это не сильно больше.
Пытаюсь подойти со стороны оптимизации кода... раньше же и с куда меньшими мощностями как-то в космос летали. Свой код я уже утоптал практически до предела своей компетенции, как еще меньше сделать пока не знаю, но вот большую часть объема у меня съедают чужие внешние библиотеки. Копать каждую из них у меня нет особого желания (хотя минимум одну уже пришлось ручками править, т.к. там были ошибки). Но возникла такая идея: а что, если выдернуть из них только нужные мне функции и оптимизировать уже только их под мои конкретные задачи?
Отсюда вопрос: можно ли как-то увидеть, какую часть кода компилятор в итоге оставляет? Если я правильно понимаю, то при компиляции отбрасываются все лишние функции и переменные, которые, даже если они были объявлены в коде, нигде не используются. Можно ли как-то выдернуть этот полуфабрикат в человеко-читаемом виде для дальнейшего анализа? Покопавшись во временных файлах, которые генерит компилятор, лучшее, что я нашел, это файл, с моим кодом, где заменены все #define’ы и #if#endif’ы, но оставлен прочий «мусор». Можно ли как-то все таки увидеть собранный в одном месте, очищенный, но неоткомпилированный код?
Нет. И поменять мк гораздо дешевле
Дешевле чем что?
большую часть объема у меня съедают чужие внешние библиотеки. Копать каждую из них у меня нет особого желания (хотя минимум одну уже пришлось ручками править, т.к. там были ошибки). Но возникла такая идея: а что, если выдернуть из них только нужные мне функции и оптимизировать уже только их под мои конкретные задачи?
реально компилятор сам это и делает, в большинстве случаев "лишние" функции в код не попадают.
А вообще, если у вас не хвтает ресурсов контроллера не чуть-чуть - а в 1.5 - 2 раза - то тут только два варианта. Либо вы изначально выбрали неверный МК. либо очень неэффективно пишете код... Увы. других вариантов нет.
В качестве саморекламы могу сказать. что у меня обычно обратная ситуация - выбранный МК обычно превышает потребности кода в 2-3 раза. После опробования на Нано зачастую в конечное устройство ставлю Атмегу168, 88 или даже тини
Но правда надо отметить, что у меня ни в одном устройстве нет интерфейса управления - всяких там меню, экранчиков. энкодеров - обычно предпочитаю создавать автономные девайсы. не нуждающиеся во вмешательстве человека :)
Дешевле чем что?
чем тратить время на переписывание библиотек
У gcc есть опция -E, почитайте про неё. Включите в IDE вывод всех сообщений компилятора. И, по идее, куда-то обработанный препроцессором код должон промежуточно складываться, во временную папку.
Короче, надо пробовать. Сейчас не с рабочего компа, поэтому более предметно - не могу подсказать. Но Arduino IDE запускает тот же GCC, и передаёт ему параметры командной строки. В настроечных файлах это указано, возможно, там уже есть опция -E. Т.е. получить промежуточный выхлоп - вполне реально, я так натравливал на нужные файлы батник, чтобы поcмотреть, чего там по ассемблеру получается:
На *.o или *.elf-файл натравливается, и - всё. С препроцессором, думаю, подобную петрушку тоже можно совершить.
Но что-то мне подсказывает, что не сильно это и поможет - какой прок от файла, прошедшего через препроцессор? Что вы там планируете увидеть? Кмк - для начала гооораздо проще почитать документацию к используемым библиотекам, на предмет настроек тех же директив условной компиляции. Например, UTFT позволяет выключить поддержку некоторых контроллеров, что немного ужимает её код на выхлопе с препроцессора. И всё это описано в документации ;)
Но правда надо отметить, что у меня ни в одном устройстве нет интерфейса управления - всяких там меню, экранчиков. энкодеров - обычно предпочитаю создавать автономные девайсы. не нуждающиеся во вмешательстве человека :)
Ну вот как только пересядешь на использование цветных TFT, да на необходимость конфигурировать прошивку посредством софта на компе, да чтоб всё это было с фейерверками и завитушками (юзер нынче избалованный, млять) - вот тогда и увидишь, что 90% рабочего времени и чуть меньше (но не сильно) ресурсов МК - тратятся на всю эту невообразимую хрень :)
Ну вот как только пересядешь на использование цветных TFT, да на необходимость конфигурировать прошивку посредством софта на компе, да чтоб всё это было с фейерверками и завитушками (юзер нынче избалованный, млять) - вот тогда и увидишь, что 90% рабочего времени и чуть меньше (но не сильно) ресурсов МК - тратятся на всю эту невообразимую хрень :)
ты знаешь, я это понял уже 20 лет назад, когда первый раз полез писать UI под винду :)
"Поэтому я и не женюсь" (с) - то есть не работаю с интерфейсами... и теми кто их заказывает :)
RxMaxx, напиши мне завтра на почту. elf-basic@yandex.ru
"Поэтому я и не женюсь" (с) - то есть не работаю с интерфейсами... и теми кто их заказывает :)
Ээх, везуха... А у мну наоборот - всю жизнь с ними бок о бок.
Есть nucleo на stm32 сделанная по ногам точно под нану. Со всеми аналогичными выводами. Памяти море. Таймеров и прочей периферии море, аддон ардуиновский, если без прямого обращения к регистрам, почти всё нанино ест.
Assembler должен помочь с оптимизацией.
Документация многих библиотек оставляет желать лучшего. Увидеть я планирую именно тот код, который пойдет компилироваться, тем самым ограничить себе поле деятельности. Потом, к примеру, в библиотекe одна функция будет вызывать кучу других, в документации об этом явно сказано вряд ли будет, а полностью проследить логику работы библиотеки довольно сложно. А когда у меня перед глазами будет только тот код, который реально нежен, мне уже проще будет в нем разобраться и что-то подсократить или вовсе переделать.
На *.o или *.elf-файл натравливается, и - всё. С препроцессором, думаю, подобную петрушку тоже можно совершить.
*.o и *.elf-файлы я и сейчас вижу во временных файлах, но мне это ничего не дает, нужен все-таки читабельный код, даже ассемблер для меня перебор.
Есть nucleo на stm32 сделанная по ногам точно под нану. Со всеми аналогичными выводами.
Если речь о NUCLEO-L432KC, то она, судя по фоткам, длиннее Наны, а у меня ограничения не только по выводам и по габаритам, так что боюсь не пойдет, проще новые версии Наны рассматривать, если с оптимизацией ничего не выйдет.
Assembler должен помочь с оптимизацией.
Может быть, когда нибудь... не при моем нынешнем уровне знаний.
*.o и *.elf-файлы я и сейчас вижу во временных файлах, но мне это ничего не дает, нужен все-таки читабельный код, даже ассемблер для меня перебор.
тогда. как мне кажется, никаких шансов у вас нет. Разобраться в исходнике библиотеки - даже вообще без документации - имхо, в разы легче, чем в автоматически сгенеренном файле на выходе препроцессора. Библиотеки все-таки пишут люди... а препроцессор - это автомат
Вы исходники FLProg видели когда-нибудь? - здесь иногда народ выкладывает... это нереальное нагромождение формально правильных конструкций. в который не прослеживается никакой логики...
тогда. как мне кажется, никаких шансов у вас нет. Разобраться в исходнике библиотеки - даже вообще без документации - имхо, в разы легче, чем в автоматически сгенеренном файле на выходе препроцессора. Библиотеки все-таки пишут люди... а препроцессор - это автомат
Объясняю, что я хочу увидеть (не знаю бывает ли это в природе). Как я себе представляю, что сначала все файлы программы и библиотеки должны собраться в один общий файл. Т.е. текст библиотеки должен встать вместо #include, но при этом желательно только те части, которые реально используются. Но я плохо представляю на каком этапе происходит очистка от мусора, боюсь что уже на нечитабельном этапе.
В конце-концов, мне хотя бы бы свой код увидеть очищенным от мусора, за долгое время его переписыванию у меня уже накопилась куча переменных и функций, которые я уже сам не использую.
Проблема еще в том, что у меня некоторые функции, которые уже есть в библиотеках практически продублированы в основном коде, т.к. по тем или иным причинам я не смог их использовать их напрямую из библиотек.
В конце-концов, мне хотя бы бы свой код увидеть очищенным от мусора, за долгое время его переписыванию у меня уже накопилась куча переменных и функций, которые я уже сам не использую.
Проблема еще в том, что у меня некоторые функции, которые уже есть в библиотеках практически продублированы в основном коде, т.к. по тем или иным причинам я не смог их использовать их напрямую из библиотек.
простите, но судя по симптомам - вы свой код пишете как бесконечную простыню? Или не дай бог почти вся программа состоит из огромного ЛУП и небольшой кучки вспомогательных функций?
Тогда первое, что вам может помочь - структурирование кода. Разбивайте код на отдельные процедуры длиной, желательно, не более 50 строк - и обьединяйте их по функциям... (например, всю математику - в отдельный файл) или по используемому железу... или по частям алгоритма программы.
Смысл в том, чтобы вместо "простыни" в 3-5 тыс строк получить 10-20 файлов по 150-300 строк, каждый из которых в разы проще отлаживать и поддерживать в чистоте. Да и так называемое "повторное использование кода" очень облегчает жизнь. Написав один раз функции работы с кнопками. со сдвиговым регистром или с датчиком температуры м поместив их в отдельный файл - вы в следующем проекте не пишете их заново, а просто копируете файл в каталог скетча и все
простите, но судя по симптомам - вы свой код пишете как бесконечную простыню? Или не дай бог почти вся программа состоит из огромного ЛУП и небольшой кучки вспомогательных функций?
Не так, код сырой да, много раз переписывался, а потому там накопился мусор в виде лишних переменных и функций, но это не простыня. Коды я видел и писал куда длиннее. Но меня терзают смутные сомнения, что бОльшую часть памяти занимают чужие библиотеки, вот я и хочу понять какую именно. Может мне нужно другую библиотеку использовать или может вовсе без нее обойтись.
Не так, код сырой да, много раз переписывался, а потому там накопился мусор в виде лишних переменных и функций, но это не простыня. Коды я видел и писал куда длиннее.
тогда не совсем понятно, что мешает вам свой код почистить, раз вы точно знаете, что эти функции и переменные лишние. Если сомневаетесь - то хотя бы просто закомментируйте и соберите программу без них... все работает? - значит и правда лишние
тогда не совсем понятно, что мешает вам свой код почистить, раз вы точно знаете, что эти функции и переменные лишние. Если сомневаетесь - то хотя бы просто закомментируйте и соберите программу без них... все работает? - значит и правда лишние
Да не в этом дело, в своем коде я ориентируюсь, как это ни странно, да, там есть мусор и неиспользуемые функции которые не могу использовать из-за недостатка памяти...
Но сейчас я хочу разобраться с библиотеками, мне нужно увидеть, что реально из них используется в итоге, вот и ищу способ как бы это увидеть.
Но меня терзают смутные сомнения, что бОльшую часть памяти занимают чужие библиотеки, вот я и хочу понять какую именно. Может мне нужно другую библиотеку использовать или может вовсе без нее обойтись.
Код секретный? Имея перед глазами предмет обсуждения - гораздо легче предметнее вести беседу. Выкладывайте код на гитхаб, и дайте ссылку на репозиторий - глядишь, чего дельного и родится из обсуждения.
Можно просто на фрагмент(стиль) глянуть чтобы понять - сможете вы его улучшить или нет.
Нет, просто еще очень сырой и некрасивый, и чтоб его понять нужно очень много комментариев писать, когда упрусь, что уже сам не смогу двигаться дальше, придется наверное опубликовать.
Кусок кода? Без кучи комментов, боюсь будет нечитабельно. У меня к примеру вызов функции может выглядeть как-то так:
Но правда надо отметить, что у меня ни в одном устройстве нет интерфейса управления - всяких там меню, экранчиков. энкодеров - обычно предпочитаю создавать автономные девайсы. не нуждающиеся во вмешательстве человека :)
Ну вот как только пересядешь на использование цветных TFT, да на необходимость конфигурировать прошивку посредством софта на компе, да чтоб всё это было с фейерверками и завитушками (юзер нынче избалованный, млять) - вот тогда и увидишь, что 90% рабочего времени и чуть меньше (но не сильно) ресурсов МК - тратятся на всю эту невообразимую хрень :)
самым эффективным способом конфигурирования/управления программой оказалась командная строка в вэб запросе. Дальше ее парсю, извлекая команды и аргументы и меняю что предписано менять. Быстро дешево неёмко и заказчик принимает, если объяснить , что бантики, финтифлюшки и загогулинки увеличивают стоимость и железа и кода.
типо http://***.***.***.***/&reset_mod=55
Команда сбросить модуль мониторинга на 55м станке отдается агрегатору а он отсылает её в ответе на запрос в обмене с модулем при очередном сеансе.
Кусок кода? Без кучи комментов, боюсь будет нечитабельно. У меня к примеру вызов функции может выглядeть как-то так:
вы меня конечно извините :)))
но с таким стилем вам ничто не поможет. Вам остается только взять старую винтовки и застрелится. Мне кажется, лучше уж вообще не писать, чем так
Можно хотя бы спросить - вы наверно живете в стране. где каждый пробел в строке - платный? А переводы строк вообще доступны только олигархам? ибо ничего другого мне в голову не приходит, нормальный человек без очень веской причины так писать не будет...
А почему старую? Была б винтовка, я б ей лучшее применение нашел.
Стиль как раз продиктован необходимостью сильно экономит память. Как бы ужасно это не выглядело, это как раз раз позволило сильно сократить код (как в исходом виде, так и в откомпилированном). Для чужих глаз код не предназначался, сами просили показать...
Пробелы я при вставке кода сюда убрал...
вы правда думаете, что каждый лишний символ в исходнике - это лишний байт в прошивке? :))) У вас опыт программирования на Си есть? - или это первый проект?
Это как надо себя не уважать. чтобы так писать? - совершенно не удивительно, что вы в этой каше потеряли переменные и функции. И наверно раздули код больше, чем выиграли за счет этого стиля.
Эффективный код - это еще и красивый код.
На ASM так не извратиться ...
вы правда думаете, что каждый лишний символ в исходнике - это лишний байт в прошивке? :))) У вас опыт программирования на Си есть? - или это первый проект?
Это как надо себя не уважать. чтобы так писать? - совершенно не удивительно, что вы в этой каше потеряли переменные и функции. И наверно раздули код больше, чем выиграли за счет этого стиля.
Эффективный код - это еще и красивый код.
Код я показывать не собирался, я специально выбрал тот самый кусок, который скорее всего не понравится, т.к. тут в любом случае чужой код принято ругать за все, что только можно.
В своем коде я не путаюсь, повторяю еще раз. И вопрос у меня совершенно не касался моего кода.
Правил мне и на работе хватает, тут я пишу как хочу, не всем жe на BrainFucke отрываться.
И вопрос у меня совершенно не касался моего кода.
а чего же он касался? разве не про оптимизацию этого кода вы спрашивали? - так вот, на мой взгляд такой код лучше всего оптимизируется в мусорной корзинке.
Правил мне и на работе хватает, тут я пишу как хочу, не всем жe на BrainFucke отрываться.
ну тогда не спрашивайте, как вам расхлебывать последствия своего "пишу как хочу".
Вы напоминаете человека, который шел по незнакомой местности и решил срезать, да вот незадача - по дороге уперся в реку, а моста нет. И вот он спрашивает, как ему перебраться на тот берег, если он плавать не умеет - а на советы вернутся на дорогу отвечает, как вы - я же не об этом спрашиваю :)))
Мда, оптимизировать подобный код - такое себе. Налицо, кмк, подмена понятий: созданием совершенно нечитабельного кода - ну никак не подтолкнуть компилятор к тому, чтобы он начал делать результирующий файл меньшего размера. А вот через пару лет в этой простыне попробовать разобраться - алкоголиком можно стать :)
самым эффективным способом конфигурирования/управления программой оказалась командная строка в вэб запросе. Дальше ее парсю, извлекая команды и аргументы и меняю что предписано менять. Быстро дешево неёмко и заказчик принимает, если объяснить , что бантики, финтифлюшки и загогулинки увеличивают стоимость и железа и кода.
типо http://***.***.***.***/&reset_mod=55
Команда сбросить модуль мониторинга на 55м станке отдается агрегатору а он отсылает её в ответе на запрос в обмене с модулем при очередном сеансе.
Частный случай, не более того. Вы думаете, подобный подход не применяется? Ещё как. Но этого - всегда мало. Пока заказчика устраивает - жизнь легка и приятна. Но как только ему надоест вводить ручками (пусть и параметров немного) - вот тут в полный рост встаёт головняк. Благо, сейчас есть ведроид, междумордие на котором пишется довольно-таки бодро, и очень помогает.
Так что самых эффективных способов - не существует, строго говоря ;)
RxMaxx - посмотрите на проблему вот еще с какой стороны. Судя по тому, что вы планировали все уместить в Нано, а теперь ее очень не хватает - наверно вы для начала планировали относительно простой проект, а потом напихали в него самых разных функций?
Подумайте о том, что три отдельных инструмента всегда удобнее, чем комбинированный монстр, у которого с одной стороны молоток, с другой - топор - а вместо ручки полотно пилы с острыми зубьями :)
Знаете, какой самый активно обсуждаемый проект в местом разделе ? - генератор частоты Димакса. с кодом всего на полторы странички. А вовсе не навороченные проекты "умных домов", в которые их авторы напихали все, что им пришло в голову и которые были забыты через неделю после публикации.
Не совсем так, ардуино - это мое хобби, довольно сильно далекое от того, чем я обычно занимаюсь, и тут я делаю все так, как хочу: пишу нечитаемое, впихиваю невпхиуемое. Задача впихнуть как можно больше в том и состоит, что это сложно, заменить железку на более мощную - это слишком просто. Правильнее было бы все на AMSe делать, но порог вхождения великоват, карантин боюсь закончится раньше...
Пишите нормально, оптимизатор многое умеет. А вот эти ваши стотыщмильёнов тернарных операторов, которые превращаются в кучу джампов и иного жонглирования регистрами вместо одного человеческого if() {} else {}, обеспечивающий один джамп, сыканомит и progmem space и психическое здоровье.
А не выходит там одного человеческого if/else. У меня здесь вызов функции многих переменных, каждая из которых зависит от разных условий. Я могу для каждой переменной отдельно расписать условия через if/else, в итоге код визуально разрастется очень заметно, но при этом (для меня) не станет более читабельным (для внешних наблюдателей может и станет, но внешние наблюдатели как бы не предполагались), но при этом скомпилированный код будет будет только больше, как раз за счет того, что мне придется еще и лишние переменные заводить. Я тут за каждым байтом скомпилированного кода слежу, и такой вариант вызова функции оказался самым экономичным (из тех что пробовал).
Я тут за каждым байтом скомпилированного кода слежу, и такой вариант вызова функции оказался самым экономичным (из тех что пробовал).
очевидно, что эта "экономия каждого байта" все равно не позволит вам впихнуть 48К кода в 32. Так можно подпиливать последние 20 байтов, когда код не влезает чуть чуть в выбранный МК. А тут вы помаетесь еще с месяц или полгода - а потом все равно возьмете Мегу :)
Проблема в том, что вы же уже привыкнете так писать - отвыкать будет сложно
Я тут за каждым байтом скомпилированного кода слежу, и такой вариант вызова функции оказался самым экономичным (из тех что пробовал).
дабы ишобы нибыть_песд@болом давай-ка запость раздез твоих вариантофф функций и нормальном и твоём Ызвращенном виде ----- пасмотрим наризультатЪ.
дабы ишобы нибыть_песд@болом давай-ка запость раздез твоих вариантофф функций и нормальном и твоём Ызвращенном виде ----- пасмотрим наризультатЪ.
+100 кстати, давайте сравним
Я бы еще посмотрел на окружение этой функции, чтобы понять - какого дьявола ее нужно вызывать с 30 параметрами, да каждое еще с условием. Сдается мне что налицо ошибки проектирования алгоритма
очевидно, что эта "экономия каждого байта" все не позволит вам впихнуть 48К кода в 32. Так что вы помаетесь еще с месяц или полгода - а потом все равно возьмете Мегу :)
Проблема в том, что вы же уже привыкнете так писать - отвыкать будет сложно
Но вместо этого я пишу так:
На выходе имеем одно и тоже, как по размеру, так и по функционалу. При этом я вызываю эту функцию с различным сочетанием переменных много раз. Какой же мне способ предпочесть, так чтоб сам код был более читаемый?
При этом я вызываю эту функцию с различным сочетанием переменных много раз.
Вы сейчас опять будете ругаться, что тут все обсирают, но только функции стольких аргументов, еще и вызываемые с жестко забитыми в коде значениями типа (10, pos, 3, 1, 1, sepbl , 0, ldot, BLINK, 255) - это однозначный признак неумения проектировать программу. В программе должно быть как можно меньше т.н. "hard-coded" констант - и это правило не на пустом месте придумано. Каждая такая константа в коде - это какбы роспись автора в том, что он не осилить рассмотреть закономерность кода, в котором эта константа превратилась бы в вычисляемую переменную .
Что я имею в виду - можно записать вот так
а можно циклом for от 1 до 17 в одну-две строки
Чувствую что то мне эта упертость ТС напоминает ...
Нашел - http://arduino.ru/forum/programmirovanie/etyudy-dlya-nachinayushchikh-blink-i-bez-delay-i-bez-millis?page=7#comment-532312
RxMaxx - а вы случаем не участник с ником b612 ?
Очень на вас похож. Тоже приходил сюда и показывал свой своеобразный код. Проблема у него была таже - не хватало места в контроллере. У него код светодиодных часов 6 тыс строк занимал...
Вы с ним интересные феномены
О каких константах речь вообще? Я лишь пример привел, когда часть аргументов не меняется. Я бы мог первый пример расписать, но мне лень. И в чем проблема многих переменных? Ну, вот функция такая, которая очень, часто используется. И вычислить одну переменную из другой либо нельзя либо нерационально.
И в чем проблема многих переменных? Ну, вот функция такая, которая очень, часто используется.
ну хотя бы в том, что вместо 1 функции с 30 переменными обычно эффективнее написать 5 функций с пятью параметрами. Разбивая задачи на меньшие составляющие, у вас будет больше шансов повторно использовать код.
Посмотрите профессиональный софт, те же библиотеки на ГИТхабе - больше пяти параметров как правило имеют только конструкторы классов. Все остальные функции - 2-3 параметра, редко больше.
Потому что аргументы через стек передаются, а чем больше аргументов это рост стека, время на вход выход. Меньше аргументов - быстрее и меньше щансов что при вложенности функций на границу стека нарвешся.
Не, не он, я проверил. У меня в отличии от b612 нет привычек обзывать переменные транслитом, выкладывать большие куски кода и описание устройств и материться в комментариях. Может еще различия есть.