Развенчание мифов об x32 ABI

от автора

Наверное, некоторые из вас слышали о халяве под названием x32 ABI.

Вкратце о x32 ABI

Если вкратце, то это возможность использовать все преимущества 64-хбитной архитектуры, но при этом сохраняя 32-хбитные указатели. Потенциально при этом приложение будет расходовать меньше памяти, хоть и не сможет адресовать более 4 ГиБ памяти.

Пример. В своём коде вы определяете массив целых чисел и заполняете его значениями. Сколько при этом вы расходуете памяти? Если очень грубо изобразить, то получится примерно так:
32 бита: Указатель + Счётчик числа элементов + N целых чисел = N+2 32-хбитных числа
64 бита: Указатель + Счётчик числа элементов + N целых чисел = N+2 64-хбитных числа = 2N+4 32-хбитных числа
Вот инженеры и задумались: а что если попробовать использовать 32-хбитные указатели на 64-хбитной архитектуре? Архитектура X86-64 имеет систему команд CISC и позволяет это сделать. В этом случае наш массив выше будет расходовать памяти 2N+3 вместо 2N+4. Экономия конечно же незначительная, но дело в том, что в современном коде количество разного рода указателей в структурах нередко доходит до десятка, и использование коротких указателей потенциально позволит экономить до 50% памяти (в идеальном случае).

Для тех кому надо расчёты точнее:
* Насколько большие массивы (и значения) в PHP? (Подсказка: ОЧЕНЬ БОЛЬШИЕ)
* Сколько памяти потребляют объекты в PHP и стоит ли использовать 64-битную версию?

Но как оказалось халявы не будет.

Перевод статьи Debunking x32 myths

Было много комментариев к моей предыдущей статье об x32 ABI. Некоторые из них интересные, другие же люди просто не понимают о чём пишут. У меня сложилось впечатление, что возникло что-то вроде культа карго вокруг этой темы. Люди думают: «Зачем-то же они это делают, так что я тоже смогу это использовать», при этом техническая грамотность, чтобы оценить эту самую пользу, отсутствует.

Так что в том же духе, который я использовал, чтобы пройтись по ccache`у почти четыре года назад (ух-ты, моему блогу уже столько лет, ну не молодец ли я?), я попробую развенчать мифы и заблуждения об этом x32 ABI.

x32 ABI код быстрее

Не совсем верно. Сейчас у нас только несколько результатов тестирования, выложенных теми, кто это самое ABI и создал. Конечно вы ожидаете, что те, кто потратил время, чтобы настроить систему, нашёл её интересной и более быстрой, но, честно говоря, у меня есть сомнения по поводу результатов, по причинам, которые будут ясны после прочтения нескольких следующих предложений.

Также интересно заметить, что, несмотря на то, что общие замеры оказались быстрее, разница — не принципиальная. И даже презентация Интела показывает большие отличия только в сравнении с оригинальным x86, который и так понятно, что хуже x86-64.

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

x32 ABI код компактнее

Новый ABI генерирует меньший код, что значит, что больше инструкций попадёт в кеш процессора, а также у нас будут меньше файлы. Это абсолютно неверно. Генерируемый код, в общем, такой же как и для x86-64, так как не изменяется набор инструкций, просто изменяется так называемая модель данных, которая означает, что вы изменяете размер для long (и связанных типов) и размер указателей (но также меняется и размер доступного адресного пространства).

Теоретически верно, что если вы собираетесь использовать меньшие структуры данных, то их больше влезет в кеш данных (но не в кеш инструкций, будьте уверены (прим. пер.: CISC внутри себя сразу преобразует все короткие инструкции в длинные)), но разве это верный подход? По моему опыту, лучше сосредоточится на написании кода, который оптимальнее расположится в кеше, если ваш код пожирает кеш. Вы можете использовать утилиты dev-util/dwarves от Арнальдо (acme). pahole, например, скажет вам как ваши структуры данных будут разделены в памяти.

Также помните, что для совместимости системные вызовы будут оставлены такими же как в x86-64, что значит, что весь код ядра и системные структуры данных, которые вы будете использовать, будут такими же как и для x86-64. Что означает, что большое количество структур не поменяют свой размер в новом ABI (прим. пер.: бинарного интерфейса).

Наконец, если снова обратится к презентации, вы можете увидеть на слайде 24, что код x32 ABI может быть длиннее, чем оригинальный x86-код. Хорошо бы было, если бы они включили ещё и пример для x86-64 кода (так как я не владею VCISC(прим. пер.: имеется ввиду группа 64-хбитных инструкций из CISC)), но я думаю, что это и так один и тот же код.

Давайте для интереса сравним размер файла libc.so.6. Вот вывод утилиты rbelf-size из моего набора Ruby Elf:

        exec         data       rodata        relro          bss     overhead    allocated   filename      1239436         7456       341974        13056        17784        94924      1714630   /lib/libc.so.6      1259721         4560       316187         6896        12884        87782      1688030   x32/libc.so.6 

Запускаемый код даже больше в x32 варианте. Большое изменение конечно в структуре данных (data, rodata, relro and bss), так как указатели теперь сокращённые. Я честно говоря даже обеспокоен: «Как можно для Си библиотеки иметь так много указателей в собственных структурах?»; но это вопрос не по теме. Даже с учётом того, что указатели короче, разница не такая большая. В общем, вы будете иметь экономию что-то вроде 30 КиБ, что навряд ли изменит картину маппинга памяти.

Снижение размера данных полезно

Ну да, это ведь главный вопрос. Конечно структуры данных меньше с x32, так как для этого он и делался, в конце концов. Но главный вопрос вероятно будет: «Это так важно?»; я не думаю. Даже в примере выше с Си библиотекой, где разница ощутима, она всего около 20% занимаемого места. И это Си библиотека! Библиотека, которая предполагает, что вы будете писать гораздо меньшие интерфейсы.

Сейчас если вы прибавите к этому все возможные библиотеки, то, возможно, вы можете сэкономить пару мегабайт данных, конечно же, но вы также должны учесть все проблемы портирования, которые я собираюсь обсудить скоро. Да, это правда, что С++ и большая часть языков с виртуальной машиной будут иметь меньше трудностей, особенно при копировании объектов, благодаря уменьшенным указателям, но пока мы может утверждать это с большой натяжкой. В особенности с тех пор как большинство ваших буферов данных должны быть выравнены хотя бы по 8 байт (64 бита), чтобы использовать новые инструкции. И вы уже выравниваете их по 16 байт (128 бит), чтобы использовать некоторые наборы инструкций SIMD.

И для тех, кто думает, что x32 сэкономит место на диске. Запомните, что вы не можете иметь «чистую» x32 систему, то что вы получите — будет смешение трёх подходов: x86, x86-64 и x32.

Это не имеет применения для приложений использующих более 4 ГиБ памяти

Да, конечно, это, возможно, правда. Но серьёзно, вы действительно беспокоитесь о размере указателей? Если вы реально хотите убедиться, что приложение не использует больше, чем определённое количество памяти, используйте системные лимиты! Они, безусловно, менее «тяжёлые» чем создание нового ABI в целом.

Интересно, что есть 2 разных, противоположных подхода для приложений в полном 64-хбитном адресном пространстве с памятью меньше чем 4 ГиБ:

  • ASLR (Address Space Layout Randomization), который может реально загружать различные объекты приложения по широкому диапазону адресов (прим. пер.: то есть как бы разбрасывать по памяти)
  • и Prelink, который делает так, что каждый уникальный объект в системе всегда загружается по одному и тому же адресу, и это действительно противоположно тому, что делает ASLR
  • Интересно, что только один процессор, который по утверждению Интела в презентации работает лучше на 32-хбитных инструкциях, — это Atom. Цитирую: «Задержки на 64-хбитных IMUL операциях вдвое выше, чем на 32-хбитных на Atom`е».

    Итак, что же такое IMUL? Это операция знакового умножения. Вы умножаете указатели? Это бессмысленно. Кроме того, указатели не знаковые. И вы говорите мне, что вы больше беспокоитесь о платформе (Atom`е), которая имеет большие задержки, когда люди используют 64-хбитные данные вместо положенных 32-хбитных? И ваше решение для этой проблемы — создание нового ABI, где тяжело использовать 64-хбитные типы. И всё это вместо того, чтобы просто исправить в программе то, что порождает эти проблемы?

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

ссылка на оригинал статьи http://habrahabr.ru/post/170407/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *