Pull to refresh

Сравнение эффективности компиляторов под Эльбрус на примере решета Эратосфена

Level of difficultyMedium
Reading time4 min
Views4.2K

На Хабре уже было тестирование Эльбрусов на разных языках программирования (например, здесь). И данный обзор стоит рассматривать как дополнение, с ещё одним тестом, новыми версиями компиляторов и новыми участниками (Rust, С++). Также обзор сделан с упором на тест возможностей именно компиляторов и настройки оптимизации.

Предыстория

Однажды получив доступ к серверу на базе Эльбрус 8С, появилось желание оценить эффективность его работы с Java. Я уже был осведомлён о сложности JIT-компиляции на e2k и о проделанной ребятами из УниПро работе. Но, сделав замеры, их нужно с чем-то сравнить. Для этого хорошо подходят C++ и Rust, компиляторы которых должны лучше справляться с оптимизацией под e2k. Особенно C++, компиляции которого уделено большое внимание в рекомендациях МЦСТ. В качестве тестов был выбран расчёт простых чисел с помощью решета Эратосфена (блочный вариант). Теоретически, алгоритм должен хорошо оптимизироваться под e2k. И тем интереснее посмотреть, как с этим справятся компиляторы на разных языках.

Тестовые стенды:

x86:

  • AMD FX-6300@3500 Мгц. (турбобуст отключен).

  • Intel Celeron (Haswell) G1820@2700 Мгц.

Софт:

Ubuntu 22.04.

Java: OpenJDK Runtime Environment (build 11.0.25+9-post-Ubuntu-1ubuntu122.04).

Rust: rustc / cargo v.1.83.0; LLVM version: 19.1.1.

C++: GCC v11.4.0; LLVM version 19.1.5.

e2k:

  • Эльбрус 8С@1200 Мгц.

Софт:

Elbrus Linux 7.2

Java: OpenJDK Runtime Environment (build 11.0.15-Unipro+0-adhoc.root.openjdk11-11.0.15).

Rust: rustc / cargo v.1.57.0.

C++: lcc:1.26.22:Jan-10-2024:e2k-v4-linux (gcc (GCC) 9.3.0 compatible)

Испытуемые: Java, Rust, C++(GCC, LСC).

Тестовая задача

В качестве теста выступает решето Эратосфена в блочном варианте. Один поток. На трёх языках реализовано максимально идентично. Программа в консольном варианте. Есть возможность повторного расчёта.

  • исходник и jar-архив Java;

  • исходник и исполняемые (Win, Linux) файлы (+ ассемблер) Rust;

  • исходник и исполняемые (Linux) файлы (+ ассемблер) C++.

Методика тестирования

Выполняем два запуска по пять прогонов поиска простых чисел в диапазоне 0 - 5*108. Первый прогон прогревочный и в расчёт не идёт. Для Java прогревочный проход обязателен. И, как показала практика, на C++ и Rust первый прогон тоже чуть медленнее. По оставшимся результатам двух прогонов вычисляется средний показатель.

Описание опций тестирования
  • gcc O0: $ g++ -march=native main.cpp -o eratosthenes_O0

  • gcc O2: $ g++ -O2 -march=native main.cpp -o eratosthenes_O2

  • gcc O3: $ g++ -O3 -march=native main.cpp -o eratosthenes_O3

  • gcc O4: $ g++ -O4 -march=native main.cpp -o eratosthenes_O4

  • gcc O4 +fast-math: $ g++ -O4 -march=native -ffast -ffast-math main.cpp -o eratosthenes_O4fast-math

  • gcc O4 +fast-math +PGO: двухфазная компиляция.

    1-я фаза.

    • g++ -O4 -march=elbrus-v4 -ffast -ffast-math -fprofile-generate -Wall -c -fmessage-length=0 -MMD -MP -MF"pgo-1.d" -MT"pgo-1.d" -o "pgo-1.o" "main.cpp"

    • g++ -fprofile-generate -o "pgo-1" pgo-1.o

    Сбор статистики: $ ./pgo-1 с диапазонами: 100 миллионов; 500 миллионов; 2 миллиарда.

    2-я фаза.

    • g++ -O4 -march=elbrus-v4 -ffast -ffast-math -fprofile-use -Wall -c -fmessage-length=0 -MMD -MP -MF"pgo-1.d" -MT"pgo-1.d" -o "pgo-1.o" "main.cpp"

    • g++ -fprofile-use -o "eratosthenes_O4fast-math+PGO" ./pgo-1.o

  • gcc O4 +fast-math +PGO +long_int: Все типы int в коде заменены на long int;

    перед циклом с вызовом "makeHoles(&block, curPnIdx);" ставим "#pragma swp".

    Затем выполняем двухфазную компиляцию.

    1-я фаза.

    • g++ -O4 -march=elbrus-v4 -ffast -ffast-math -fforce-loop-apb -fforce-vect -fforce-swp -fprofile-generate -Wall -c -fmessage-length=0 -MMD -MP -MF"pgo-1.d" -MT"pgo-1.d" -o "pgo-1.o" "main.cpp"

    • g++ -fprofile-generate -o "pgo-1" pgo-1.o

    Сбор статистики: $ ./pgo-1 с диапазонами: 100 миллионов; 500 миллионов; 2 миллиарда.

    2-я фаза.

    • g++ -O4 -march=elbrus-v4 -ffast -ffast-math -fforce-loop-apb -fforce-vect -fforce-swp -fprofile-use -Wall -c -fmessage-length=0 -MMD -MP -MF"pgo-1.d" -MT"pgo-1.d" -o "pgo-1.o" "main.cpp"

    • g++ -fprofile-use -o "eratosthenes_O4long_int+PGO" ./pgo-1.o

Результаты тестов

Некоторые неожиданности.

Опция -march=native ни на одной из платформ не дала профита по сравнению с -march=x86-64. При этом исполняемый файл, полученный с такой опцией на AMD FX, на Intel Celeron (Haswell) выпадал с ошибкой: "Недопустимая инструкция (образ памяти сброшен на диск)".

gcc/lcc O0

gcc/lcc O2

gcc/lcc O3

gcc/lcc O4

lcc O4 +fast-math

lcc O4 +fast-math +PGO

lcc O4 +fast-math +PGO +long_int

Rust
O2

Rust
O3

Java

Elbrus 8C @ 1.2Ghz

45712

4694

3912

3830

2479

2149

1968

4941

5033

19357

AMD FX @ 3.5Ghz

7743

2373

2208

2205

--

--

--

1818

1918

4635

Cel G1820 @ 2.7Ghz

7508

1648

1523

1543

--

--

--

1183

1213

5123

Пояснение к результатам тестов
  • Жирным выделены результаты самых удачных настроек компиляции для каждой машины.

  • Некоторые опции компиляции, указанные в таблице, не дали никакого прироста к производительности на x86. По этой причине полноценное тестирование с этими опциями не проводилось и данные в таблице не заполнены.

  • Обозначение gcc/lcc означает, что x86 использовался компилятор gcc, а на e2k - lcc (компилятор МЦСТ, совместимый с gcc).

Сравним на графике результаты компиляции C++. Сразу бросается в глаза разница между lcc O0 и lcc O2 на Эльбрусе. Такова плата за запуск неоптимизированных программ на e2k.

В отличие от x86, для Эльбруса оптимизация O4 даёт профит.

( ! ) К сожалению, на период проведения тестов и написания статьи двухфазный режим компиляции для Rust не доступен. Как появится такая возможность, результаты будут добавлены в таблицу.

Таким образом, для Rust везде лучший результат показала оптимизация O2.

Итак, лучшие настройки оптимизации для данного теста на платформах:

  • x86: Rust - O2, C++ - O3.

  • e2k: Rust - O2, C++ - O4 +fast-math +PGO +long_int.

P.S.

Не являюсь специалистом по Rust и C++. Код достаточно простой и там вряд ли будут серьёзные недочёты. Но мог недоработать в плане настроек компиляции.
Благодарю компанию МЦСТ за возможность ознакомления с ЦП семейства Эльбрус!

Tags:
Hubs:
Total votes 11: ↑9 and ↓2+11
Comments45

Articles