Разбить размер кода C ++ - PullRequest
11 голосов
/ 24 марта 2010

Я ищу хороший ответ в стиле переполнения стека на первый вопрос в старом сообщении блога Размер кода C ++ , который я повторю ниже:

Мне действительно нужен какой-то инструмент (в идеале, на основе g ++), который показывает мне, какие части скомпилированного / связанного кода генерируются из каких частей исходного кода C ++. Например, чтобы увидеть, создается ли конкретный шаблон для сотен различных типов (исправимо с помощью специализации шаблона), или чрезмерно встроен код, или же конкретные функции больше ожидаемых.

Ответы [ 7 ]

7 голосов
/ 25 марта 2010

Если вы ищете источники раздувания кода в вашем коде C ++, я использовал для этого 'nm'. Следующая команда выведет список всех символов в вашем приложении с самыми большими блоками кода и данных вверху:

nm --demangle --print-size --size-sort --reverse-sort <executable_or_lib_name> | less
5 голосов
/ 24 марта 2010

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

Сначала некоторые вещи, которые вы, возможно, уже знаете:

Команда addr2line принимает адрес и может сказать вам, где находится исходный код, который реализует машинный код. Исполняемый файл должен быть собран с отладочными символами, и вы, вероятно, не захотите много его оптимизировать (-O0, -O1 или -Os, вероятно, так же высоки, как вы бы хотели сначала). У addr2line есть несколько флагов, и вы захотите прочитать его страницу руководства, но вам определенно нужно будет использовать -C или --demangle, если вы хотите видеть имена функций C ++, которые имеют смысл в выводе.

Команда objdump может распечатать все виды интересных вещей о материале во многих типах объектных файлов. Одна из вещей, которую он может сделать, это распечатать таблицу, представляющую символы в объектном файле или на которые они ссылаются (включая исполняемые файлы).

Теперь, что вы хотите сделать с этим:

Вам нужно, чтобы objdump сообщал вам адрес и размер секции .text. Вот где живет настоящий исполняемый машинный код. Есть несколько способов сделать это, но самый простой (для этого, во всяком случае), вероятно, для вас, чтобы сделать:

objdump -h my_exe | grep text

Это должно привести к чему-то вроде:

 12  .text       0000049  000000f000  0000000f000 00000400  2**4

Если бы вы не взяли его, он бы выглядел как:

Idx  Name        Size     VMA         LMA         File off  Algn

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

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

addr2line -e my_exe <address>

Выходными данными будут путь / имя файла, двоеточие и номер строки. Если бы вы должны были подсчитать вхождение каждого уникального пути / файла: num, вы сможете посмотреть те, которые имеют наибольшее количество. Perl хэширует, используя путь / файл: num в качестве ключа и счетчик в качестве значения, это будет простой способ реализовать это, хотя есть более быстрые способы, если вы обнаружите, что работает слишком медленно. Вы также можете отфильтровать вещи, которые, как вы можете определить, не нужно включать заранее. Для отображения выходных данных вы можете отфильтровать разные строки из одной и той же функции, но вы можете заметить, что разные строки в одной функции имеют различное число, что может быть интересно. В любом случае, это может быть сделано либо с помощью addr2line, сообщающей вам имя функции, либо с помощью objdump -t на первом шаге и работающего по одной функции за раз.

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

Если вы не знали, objdump и addr2line из пакета GNU binutils , который включает в себя несколько других полезных инструментов.

4 голосов
/ 03 февраля 2012

Я недавно написал инструмент bloat-blame , который делает нечто похожее на то, что nategoose предложил .

1 голос
/ 26 марта 2010

В большинстве компиляторов Си есть способ создать файл .map. В этом файле перечислены все скомпилированные библиотеки, их адрес и размер. Вы можете использовать этот файл карты, чтобы определить, какие файлы вам следует сначала оптимизировать.

1 голос
/ 25 марта 2010

Я не знаю, поможет ли это, но есть флаг gcc для записи кода сборки, который он генерирует, в текстовый файл для проверки.

" -S Используется вместо -c для генерации исходного файла на ассемблере с использованием .s в качестве расширения вместо объектного файла. Это может быть полезно, если вам нужно изучить сгенерированный код сборки. «

0 голосов
/ 25 марта 2010

В Visual C ++ это, по сути, файлы .PDB.

0 голосов
/ 24 марта 2010

Я не знаю, как отобразить код-> сгенерированную сборку в целом.

Для создания экземпляров шаблона вы можете использовать что-то вроде «strings -a | grep | sort -u | gc ++ fil», чтобы получить грубое представление о том, что создается.

Два других упомянутых вами элемента кажутся довольно субъективными. Что такое «слишком много» встраивания? Вы обеспокоены тем, что ваш бинарный файл раздувается? Единственное, что нужно сделать - это зайти в gdb и разобрать вызывающую программу, чтобы посмотреть, что она сгенерировала, и вообще ничего не нужно проверять на «чрезмерную» вставку.

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

...