Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

На главную -> MyLDP -> Программирование и алгоритмические языки


Ulrich Drepper "Как писать разделяемые библиотеки"
Назад Оглавление Вперед

1.6. Итоговая оценка затрат для ELF

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

Размер кода: Как и везде, уменьшение размера кода с той же семантикой часто означает более высокую эффективность и производительность. Чем меньше файлы ELF, тем меньше во время выполнения потребуется памяти. Обычно компилятор будет всегда генерировать настолько хороший код, насколько это будет возможным, и мы в дальнейшем не будем рассматривать этот вопрос. Но нужно знать, что для каждого объекта DSO требуются определенные накладные расходы, связанные с данными и с кодом. Поэтому, чем меньше объекты, DSO, тем меньше текст.

Количество объектов: Тот факт, что чем меньше объектов реализуют одну и ту же функциональность, является преимуществом, уже упоминалось в нескольких местах:

  • Во время выполнения загружается меньше объектов. Это напрямую ведет к меньшему числу системных вызовов. В реализации динамического компоновщика в GNU для загрузки объекта DSO потребуется, по меньшей мере, восемь системных вызовов, причем все они могут быть потенциально весьма дорогостоящими.
  • С этим связано то, что в приложении и зависимостях, имеющих дополнительные зависимости, должны записывать имена зависимостей. Расходы на это не слишком большие, но если зависимостей много десятков, то это определенно может повлиять на итоговую оценку.
  • Увеличивается область поиска. Это один из доминирующих факторов в уравнении стоимости перемещений.
  • Чем больше объектов , тем больше таблиц символов, что, в свою очередь, обычно означает больше копирования. Неопределенные ссылки нельзя представить в виде одной и динамический компоновщик при обработке нескольких определений должен выполнять сортировку. Более того, символы часто экспортируются из одного объекта DSO в другой. Это не должно происходить в случае, если объекты DSO могут быть слиты вместе.
  • Сортировка блоков инициализации/финализации (initializers/finalizers) становится более сложной.
  • В целом у динамического компоновщика есть некоторые накладные расходы для каждого загружаемого объекта DSO, зависящие от процесса. Каждый раз, когда запрашивается новый объект DSO, нужно выполнить поиск в списке уже загруженных объектов DSO, что может занять довольно много времени поскольку объекты DSO могут иметь много алиасов.

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

Длина символьных строк: Большая длина символов часто является причиной ненужных затрат. На поиск символов в случае успешного совпадения потребуется проверять совпадение всей строки и потратить массу времени сравнение десятков или сотен символов. При неудачном поиске затраты будут большими в случае, если общие префиксы будут такими длинными, как в новой схеме, трансформации имен в языке C++. В любом случае, длинные имена символов могут быть причиной использования больших таблиц строк, которые должны присутствовать во время выполнения программы, и, тем самым, добавляя затраты на этапах загрузки и использования адресного пространства, что является проблемой в 32-разрядных машинах.

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

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

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

Ниже мы не будем рассматривать первые два указанных здесь пункта. Они зависят только от того, какое решение по этому поводу примет разработчик объектов DSO. Нет таких небольших дополнительных изменений, которые бы сделали поведение объекта DSO лучше, это фундаментальные проектные решения. Мы здесь выразили свое мнение вне зависимости от того, какой эффект оно будет иметь.


Предыдущий раздел:   Следующий раздел:
Назад Оглавление Вперед