2009-03-19 2 views
11

У меня есть устаревшее приложение прошивки, которое требует новых функций. Размер приложения был уже около ограниченной мощности вспышки устройства, и несколько новых функций и переменных переместили его по краю. Включение оптимизации компилятора делает трюк, но клиент настороженно относится к этому, потому что в прошлом они вызвали неудачи. Итак, каковы некоторые общие вещи, которые нужно искать, когда рефакторинг кода C создает меньшую производительность?Какие методы рефакторинга уменьшают размер скомпилированного кода?

+0

Я думаю, что в вопросе следует сказать «использование памяти» или «размер вывода» вместо «размер кода». – Angel

+0

Использование памяти не является проблемой. Это размер изображения, который записывается во внутреннюю флеш-память MCU. –

+0

Я думаю, что «размер скомпилированного кода» менее двусмыслен. –

ответ

17
  • функции Использование поколения вместо таблиц данных, где возможно
  • Отключить встроенные функции
  • Turn часто используемые макросы в функции
  • Уменьшите разрешение для переменных больших, чем размер родной машины (т.е. 8 бит микро, попробуйте избавиться от 16 и 32 битных переменных - удваивает и увеличивает число кодовых последовательностей)
  • Если микро имеет меньший набор инструкций (большой палец руки), включите его в компилятор
  • Если mem ORY сегментирован (то есть, выгружаемого или нелинейный), то
    • Перестановка код так, что меньше глобальных вызовов (большие инструкции вызова) необходимо использовать
    • переставить код и использование переменных для устранения глобальной памяти вызовов
    • ПЕРЕУСТАНОВКИ оценить глобальное использование памяти - если он может быть помещен в стек, то тем лучше
  • Убедитесь, что вы собираете с отладкой выключена - на некоторых процессорах большой разницы
  • Сжатия данных, которые могут генерируется o n fly - затем распакуйте в ram при запуске для быстрого доступа
  • Перейдите в параметры компилятора - возможно, каждый вызов является автоматически глобальным, но вы можете безопасно отключить его в файле по файлу для уменьшения размера (иногда значительно)

Если вам все еще нужно больше места, чем при включенном compile with optimizations, посмотрите на сгенерированную сборку по сравнению с неоптимизированным кодом. Затем перепишите код, в котором произошли самые большие изменения, так что компилятор генерирует те же оптимизации, что и на основе сложной перезаписи C с отключенной оптимизацией.

Например, вы можете иметь несколько «если» заявление, которые делают подобные сравнения:

if(A && B && (C || D)){} 
if(A && !B && (C || D)){} 
if(!A && B && (C || D)){} 

Затем воссозданию переменным и делают некоторые сравнения заранее спасет компилятор из дублирующего кода:

E = (C || D); 

if(A && B && E){} 
if(A && !B && E){} 
if(!A && B && E){} 

Это одна из оптимизаций, которую компилятор делает для вас автоматически, если вы включите ее. Есть много и многие другие, и вы можете подумать о том, чтобы прочитать немного теории компилятора, если вы хотите научиться делать это вручную в коде C.

+1

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

+0

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

+0

Если вы отключите встроенные функции и включите макросы в функции, не увеличивайте использование памяти во время выполнения (больше вызовов функций = новые стековые кадры). Однако я не уверен в этом. – DevinB

2

Рефакторинг duplicate code должен оказать наибольшее влияние на объем памяти вашей программы.

0

Обратите внимание на макросы. Они могут генерировать много кода только из одного расширения макроса. Если вы найдете такие макросы, попробуйте переписать их так, чтобы их размер был минимизирован, а функциональность была перенесена в функции.

Обратите внимание на дублирующий код - оба с копированием и логическим дублированием. Попробуйте разделить дублирующий код на функции.

Проверьте, поддерживает ли компилятор встроенную вставку и ее можно отключить.

0

Оптимизация компилятора, которая вызывает ошибку? Это странно. Получите карту своей программы и посмотрите, следует ли указывать данные или код. Ищите дублированный код. Ищите код с аналогичной целью. Одним из примеров этого является код busybox, который предназначен для небольшого объема памяти.

Он предпочитает размер по читаемости, поэтому он иногда становится довольно уродливым, с gotos и так далее.

+1

Это совсем не редкость для встроенных компиляторов иметь ошибки. Чем менее широко используется этот чип, тем вероятнее, что у компилятора возникнут проблемы. Сегодня это реже, чем в прошлые времена (особенно если gcc является вашим компилятором), но по-прежнему беспокоит необычные (менее проверенные) платформы. –

7

Как правило: используйте карту компоновщика или инструменты, чтобы выяснить, какие ваши самые большие/самые многочисленные символы, а затем, возможно, взгляните на них, используя дизассемблер. Вы будете удивлены тем, что найдете таким образом.

С небольшим количеством perl и т. Д. Вы можете сделать короткую работу файла .xMAP или результатов «objdump» или «nm» и повторно отсортировать его различными способами для соответствующей информации.


Специфическая для небольших наборов инструкций: Часы для literal pool использования. При изменении, например, команда ARM (32 бит на инструкцию), установленная для набора команд THUMB (16 бит на инструкцию), может быть полезна для некоторых процессоров ARM, она уменьшает размер «немедленного» поля.

Внезапно что-то, что было бы прямой нагрузкой от глобальной или статической, становится очень косвенным; он должен сначала загрузить адрес глобального/статического в регистр, а затем загрузить с него, а не просто кодировать адрес непосредственно в инструкции. Поэтому вы получите несколько дополнительных инструкций и дополнительную запись в литеральном пуле для чего-то, что обычно было бы одной инструкцией.

Стратегия борьбы с этим заключается в объединении глобальных группировок и статики в структуры; таким образом, вы сохраняете только один литерал (адрес вашей глобальной структуры) и вычисляете смещения от него, вместо того, чтобы хранить много разных литералов, когда вы получаете доступ к нескольким статам/глобальным переменным.

Мы перевели наши классы «singleton» из управления своими указателями на экземпляры только в качестве членов в большой «структуре GlobalTable», и в некоторых случаях они заметно меняют размер кода (несколько процентов), а также производительность ,


В противном случае: следите за статическими структурами и массивами нестандартных данных. Каждый из них обычно генерирует огромное количество кода .sinit («невидимые функции», если хотите), которые запускаются до того, как main() будет правильно заполнять эти массивы. Если вы можете использовать только тривиальные типы данных в своей статистике, вам будет намного лучше.

Это снова то, что можно легко идентифицировать с помощью инструмента по результатам «nm» или «objdump» или тому подобное. Если у вас есть тонна .sinit, вам нужно исследовать!


О, и - если ваш компилятор/компоновщик поддерживает его, не бойтесь выборочно включить оптимизацию или меньшие наборы инструкций для только определенных файлов или функций!

+0

+1 Хороший подход к резиновым покрытиям. –

+0

+1 Файл компоновщика карт - это место для начала. Он покажет вам, где используется пространство. –

0

Вышеупомянутые ответы утверждают: «Включение оптимизации компилятора [уменьшен размер кода]».Учитывая всю документацию и опыт, которые у меня были в встроенных системах TI DSP, я знаю, что включение оптимизации будет УВЕЛИЧИТЬ размер вашего кода (для чипа DI DSP)!


Поясню:

ТИ TMSCx6416 DSP имеет 9 компилятора флаги, которые будут влиять на размер кода.

  1. 3 различных флагов для оптимизации
  2. 3 различных флагов для отладки
  3. 3 различных флагов для размера кода

Для моего компилятора, когда вы поворачиваете на уровне оптимизации три документаций состояний:

  1. Автоматическая встраивание для определенных функций -> увеличит размер кода
  2. Программная конвейерная обработка включена -> увеличит размер кода

Что такое конвейерная обработка программного обеспечения?

Это то, где компилятор будет делать вещи в сборке, которые заставляют циклы for выполнять значительно быстрее (до пары раз быстрее), но ценой большего размера кода. Я предлагаю прочитать около software pipelining at wikipedia (ищите развертку цикла, пролог и эпилог).

Поэтому проверьте свою документацию, чтобы убедиться, что оптимизация не делает ваш код более крупным.


Другое предложение искать флаги компилятора, которые относятся к размеру кода. Если у вас есть флагов компилятора размера кода, убедитесь, что они подняли их до самого высокого значения. Обычно компиляция для размера кода означает, что ваш код будет работать медленнее ... но вам, возможно, придется это сделать.

+0

Использование оптимизации высокого уровня для размера IAR EW430 для цели TI MSP430 уменьшило размер скомпилированного кода, но это не то решение, которое я выбрал. –

+0

Глядя на флагов компилятора, которые генерирует этот параметр, среди них есть возможность отключить инкрустацию и разворот цикла. Это действия, уже отмеченные в текущих ответах. –

+0

Похоже, ваша проблема уже решена. Для моего собственного любопытства, при оптимизации вашего компилятора оптимизация привела к отключению inline/loop unrolling/etc? –

Смежные вопросы