Разделение кода на файлы и флаги O
При написании программ с кодом, который может выполняться параллельно на C, мы определенно используем O-флаги для оптимизации кода.
gcc -Olevel [options] [source files] [object files] [-o output file]
В больших проектах мы обычно разбиваем код на несколько файлов. Мой вопрос, на который я не нашел ответа, заключается в следующем:
Производительность программы падает вообще из-за того, что мы разбили код на файлы и O
У флагов недостаточно информации для дальнейшей оптимизации? Есть ли такая возможность?
2 ответа
Когда вы разбиваете код на отдельные файлы, он может потенциально разбить его на несколько единиц перевода, которые компилятор обычно не может оптимизировать.
Возьмем, к примеру, константу, определенную в одной единице перевода, но на которую ссылаются во многих других. Все вычисления, которые ссылаются на константу, должны выполняться во время выполнения, поскольку константа не может быть сложена в них во время компиляции.
Оптимизация времени соединения (-flto
) является одним из способов обойти ограничение.
Оптимизация одного блока
В качестве дополнения к ответу @Jason, я хотел бы опубликовать другую технику, чтобы избежать ограничений, возникающих при разбиении файлов.
Это называется Оптимизация одного блока:
Методика Single Compilation Unit использует директивы препроцессора для "склеивания" разных блоков перевода во время компиляции, а не во время компоновки. Это уменьшает общее время компоновки из-за устранения дублирования, но увеличивает время инкрементной компоновки (время, необходимое после внесения изменений в любой отдельный исходный файл, включенный в единый модуль компиляции), из-за необходимости полной перестройки весь блок, если какой-либо один входной файл изменяется.
Весь проект, даже если он разделен на файлы, можно оптимизировать так, как если бы все части программы были видны компилятору сразу, без необходимости повторного объединения файлов пользователем.
Как это применить?
Обычно проект содержит файл с основным файлом и включает все заголовочные файлы каждого разделенного файла:
main.c
#include "sub-program-1.h"
#include "sub-program-2.h"
...
#include "sub-program-n.h"
//rest of code
где каждый из тех .h
файлы соответствуют его .c
который компилируется самостоятельно (возможно, через make-файл).
Для того, чтобы применить SCU, мы удаляем включение, которое я упомянул выше, и вместо этого создаем новый файл (назовем его SCU.c
). Это будет следующим.
SCU.c
#include "sub-program-1.c"
#include "sub-program-2.c"
...
#include "sub-program-3.c"
#include "main.c"
//no more code in this file
И чтобы скомпилировать весь проект, мы просто скомпилируем SCU.c