Разбить размер кода на С++

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

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

Ответ 1

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

Прежде всего, некоторые вещи, которые вы уже знаете:

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

Команда 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, который включает в себя несколько других полезных инструментов.

Ответ 2

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

nm --demangle --print-size --size-sort --reverse-sort <executable_or_lib_name> | less

Ответ 4

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

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

Ответ 5

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

Ответ 6

Я не знаю, как нарисовать сборку сгенерированного кода → вообще.

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

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

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

Ответ 7

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