Как стать автором
Обновить

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

Уровень сложностиСредний
Время на прочтение4 мин
Количество просмотров4.3K
Всего голосов 11: ↑9 и ↓2+11
Комментарии45

Комментарии 45

Какой же медленный этот эльбрус. Celeron G1820 - процессор 2014 года с весьма посредственной производительностью. Если сравнить с современным процессором разница производительности будет уже в десятки раз.

Для 99.9% процентов офисных задач достаточно.

8С вряд ли пропишется в каком-нибудь офисе. Это скорее ЦП для серверов. 2С3 для офисов больше подходит. У него и однопоточая производительность значительно выше, раза в два - три.

На данной задаче разница между 8С и 2С3 должна скалироваться согласно частоте, т.е. улучшение будет 2/1.2 = 1.67 раза.

Я, как бы, имел ввиду в общем...
Ну а в этой задаче, почему линейно частоте? У 2C3 пиковая производительность в два раза больше операций за такт. Вы смотрели исходники теста? По моему, самая затратная функция makeHoles() отлично разложится в широкую команду любой длины. Там блоки по 10000!

Ох уж эти операции за такт, было бы дело в них, Эльбрусу не было бы равных!)

В 2 раза больше операций в такт это за счёт векторизации, причем для плавающих инструкций в первую очередь. Здесь это вряд ли актуально.

Жаль, что нет образца потестить. Самое крутое, что есть в общем доступе, это E8C.

Ох уж эти операции за такт, было бы дело в них, Эльбрусу не было бы равных!)

на каждую такую операцию в интеле/амд найдется дополнительная стадия конвеера и преимуществ в итоге не видно.

Разница лишь в том что эльбрусу такая производительность дается относительно легко и дешево, тогда как над длинным конвеером в суперскаляре надо пыхтеть.

Вы понятия не имеете, о чём говорите. Впрочем, как обычно.

Особенно смешно читать про "не видно преимуществ", когда современные и не очень ОоО ядра, имея существенно меньшую площадь, обладают в разы большой производительностью по сравнению с Vliw

А вы не умеете читать, я говорил про то что эльбрус с его вроде бы много команд за такт, не имеет преимуществ перед интел/амд которые хоть и не имеют столько устройств зато имеют длинный конвеер который умеют очень плотно набивать, + имеют 256битные вектора против 64 битных например у 8С, и как следствие невозможность эмулировать два avx/такт

Другое дело что нигде и не заявляется что 25 операций/такт кого то там порвут, заявляется что они обеспечивают высокую производительность, тесты алгоритмов шифрования показывают что эльбрус вполне себе приближается по производительности к вполне себе современным intel/амд с задействованными avx -ами

И вот эта возможность пусть на некоторых задачах выступать на уровне флагманов досталась относительно дешево, это нужно тоже учитывать.

современные и не очень ОоО ядра, имея существенно меньшую площадь, обладают в разы большой производительностью по сравнению с Vliw

если бы это было так тогда бы все использовали OoO в dsp, но почему то когда нужно что то быстро считать, затрачивая минимум энергии все выбирают vliw

Я могу лишь повторить, что вы понятия не имеете, о чём говорите, поэтому вышенаписанное - это какой то винегрет, где спутаны глубина и ширина конвейера и много ещё чего другого. Давайте вы для начала хотя бы Харриса осилите. В конце концов, вы только на моей памяти уже минимум 3 года пытаетесь выступать со своими "идеями", но что-то прогресса в понимании не видно. Стыдно должно быть уже

Не нужно повторять, нужно приводить аргументы, я ничего не говорил про какую то глубину и ширину конвеера не надо мне приписывать какие то глупости которые я не говорил. Ни с какими идеями я так же не выступаю, просто читаю и отвечаю на комментарии. Все. Обратитесь к психотерапевту.

Когда Маслов пирамидит свои манипулятивные аргументы -- приходят действительно специалисты и показывают его место: http://habr.com/post/575302

Когда персонаж лечит про "стыдно" -- проецирует.

Миш, ты забыл упомянуть, что на ту статью есть ответ, который объясняет даже для неспециалистов, почему в ней основные аргументы - притянуты за уши (и это мягко говоря).

Во-первых, Эльбрус 8С и Haswell практически одногодки. И с тех пор Эльбрусы прошли ещё два поколения. И по производительности они тоже хорошо прибавили. Во-вторых, Celeron G1820 не так уж и слаб в однопотоке. А тесты проводились как раз в однопотоке. Современные топовые ЦП, может, раза в три-четыре быстрее.
Хотя с тем, что Эльбрусы сильно не дотягивают по производительности до современных топовых ЦП, спорить не стану.

Этот Celeron на старте продаж стоил $42, причём в эту цену ещё входит графический ускоритель... Это сверхбюджетное решение, и сравнивать с ним что-то не сверхбюджетное - как минимум, некорректно.

Внимание! Мы тестим однопоток! Это раз.
Целерон тоже можно засунуть в четырёхпроцессорный сервер и получить в итоге 32 ядра? Он поддерживает ECC память? Статья не про "выбор самого выгодного ЦП на 2015 год". Это два.
Ядрён, батон, какая цена?

Эльбрус можно и с лампочкой сравнить, если речь пойдёт о содержании драг.металлов в электронных компонентах. Главное - оставаться в теме.

Тогда почему вы сравниваете с целероном и ещё более древним FX, а не с серверными процессорами с поддержкой ECC-памяти?

Вы все померяли или как обычно блаблабла

8C процессор 2015г

Конкретно эта машинка (видимо, sumireko или yukari) ещё и четырёхпроцессорная, поди -- у e8c был косяк при доступе процессора к "чужим" ОЗУ/DMA, программный обход которого стоит ~20--25% производительности (т.е. однопроцессорный 8С на 1300 МГц в однопотоке ощутимо быстрее четырёхпроцессорного на 1200).

Полечили это в 8СВ.

// отправлено с моего 16С

Это yukari. Т.е. просадки проявляются, если над многопоточным приложением трудятся ядра с разных ЦП?
В общем то, я подозревал, что при использовании нескольких ЦП могут быть просадки. Хотя для тестов одного ЦП в многопотоке эта проблема решается довольно просто. Особенно если нет задачи брать все 8 ядер, а ограничиться, например, четырьмя. Но здесь у меня тут не стояла задача тестить производительность всего проца. Акцент именно на компиляторах. На одном ядре точнее выходит.

Не увидел у вас ссылки на исходный код. Как мне проверить ваши измерения?

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

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

Как-то бедно вы смотрели. Откроем список опций в GCC https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html сделаем поиск по "-f" и получим 900+ результатов. Грубо говоря половина будет -fno. Грубая оценка даёт вам 450 опций управления компиляцией. А вы рассмотрели только одну. Также не пробовали режимы компиляции с профилем. Не пробовали опции -march=, которые на Эльбрусе дают большой прирост.

Я не понял какой компилятор вы использовали для Эльбруса.

В сравнении gcc и llc, gcc оказался чуть эффективнее, но разница очень маленькая

Это один и тот же компилятор. LCC является совместимым с GCC по опциям, чтобы облегчить жизнь пользователям по системе сборки. И на Эльбрусах gcc является алиасом lcc в системе. Так что если есть разница, то скорее всего это ошибка измерения.

У меня вызывает вопрос следующее:

C++: GCC v9.3.0 compatible; LLVM version 13.0.1.

Какая версия LLVM у lcc, если его там нет? Или вы тестировали clang? А если нет, то зачем написали?

Спасибо за дельный комментарий.
Ссылки на исходники находятся в конце статьи в разделе "Ресурсы".
Настроек компиляции действительно пробовал мало. Но -march=native пробовал и разницы не заметил. Предварительно почитал рекомендации МЦСТ. Из описанных там опций компиляции увидел смысл только в двухфазной компиляции с профилем. У прочих настроек не увидел пользы для моего кода. Компилировал двумя способами: 1) g++ -Ox -march=native main.cpp -o main; 2) cmake --build . Файл CmakeLists.txt можете найти в исходниках. g++ давал мизерный (десятые доли процента), но стабильный плюс со всеми режимами оптимизации. Так что ошибка измерений исключена.
Допускаю, что мог напутать с lcc/gcc. Тут мои познания достаточно скромные. А версию LLVM я указал не случайно. Путь к этой самой LLVM прописан в cmake-файле.

Благодарю. Поправил.

Я не спорю, что путь к LLVM прописан в CMakeLists.txt. Я не понимаю зачем. Вы сами написали, что собираете компилятором g++. LLVM никак не используется в вашем main.cpp. Зачем он тогда?

Вижу, что прописан project(LLVMPassSample) что подсказывает мне CMakeFiles.txt взят от балды из интернета от студенческого репозитория с реализацией своего pass'a.

cmake_minimum_required(VERSION 3.7)
project(LLVMPassSample)

set(CMAKE_CXX_STANDARD 17)

set(LLVM_DIST_PATH "/usr/local/opt/llvm-clang/current"
        CACHE STRING "LLVM distribution install path")

set(LLVM_DIR ${LLVM_DIST_PATH}/lib/cmake/llvm)
find_package(LLVM REQUIRED CONFIG)
message(STATUS "Using LLVM version ${LLVM_PACKAGE_VERSION}")
list(APPEND CMAKE_MODULE_PATH ${LLVM_CMAKE_DIR})

set(LLVM_RUNTIME_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/bin)
set(LLVM_LIBRARY_OUTPUT_INTDIR ${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/lib)
include(HandleLLVMOptions)
include(AddLLVM)
add_compile_options(-march=native)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3")

add_definitions(${LLVM_DEFINITIONS})
include_directories(${LLVM_INCLUDE_DIRS})

add_executable(sieve_of_Eratosthenes main.cpp)

Я же написал, ко компилировал двумя способами: g++ и cmake. И про мизерную разницу между компиляторами... как раз про это.

CMakeFiles.txt взят от балды из интернета

Не от балды, а как результат поиска вариантов использования LLVM в cmake. На статус спеца по C++ не претендую. И в статье об этом написал. У меня, как у java-разработчика с минимальными знаниями C++ и Rust, написав годный код на этих языках, стояла задача собрать годный исполняемый файл с применением самых профитных оптимизаций. Единственной ошибкой в этом вопросе пока неиспользование PGO. Исправляю этот момент.
Огромная просьба! Прочитайте внимательнее статью и мои комментарии. А то вы уже начинаете с меня спрашивать то, чего я не писал...
Даже тут:

В сравнении gcc и llc, gcc оказался чуть эффективнее, но разница очень маленькая

Это один и тот же компилятор. LCC является совместимым с GCC по опциям, чтобы облегчить жизнь пользователям по системе сборки. И на Эльбрусах gcc является алиасом lcc в системе.

У меня написано про llc - LLVM static compiler. А вы мне про LCC...

Смешались в кучу кони, люди,

Давайте я объясню подробнее в чём проблема.

У меня написано про llc - LLVM static compiler. А вы мне про LCC...


Возможно вы действительно не опечатались и пытались использовать транслятор llc, что уже само по себе вызывает вопрос. Это не полноценный компилятор для языка С++ на котором написана ваша программа. Это только бэкенд для трансляции LLVM-IR в ассемблер. У него нет фронтенда и запуска линкера. Вам нужен был драйвер компиляции. В проекте LLVM для языка C++ это clang++.

Я же написал, ко компилировал двумя способами: g++ и cmake. И про мизерную разницу между компиляторами... как раз про это.

cmake -- это не компилятор. Это система генерации файлов сборки для систем сборки (make, ninja, visual studio и т.д.). Она ничего не компилирует. Она создаёт инструкции для целевой системы сборки при выполнении которых и будет запущен компилятор.

Не от балды, а как результат поиска вариантов использования LLVM в cmake. На статус спеца по C++ не претендую. И в статье об этом написал. У меня, как у java-разработчика с минимальными знаниями C++ и Rust, написав годный код на этих языках, стояла задача собрать годный исполняемый файл с применением самых профитных оптимизаций. Единственной ошибкой в этом вопросе пока неиспользование PGO. Исправляю этот момент.Огромная просьба! Прочитайте внимательнее статью и мои комментарии. А то вы уже начинаете с меня спрашивать то, чего я не писал...

LLVM это не только компилятор. Это ИНФРАСТРУКТУРА для ПОСТРОЕНИЯ компиляторов. Я не просто так написал, что в CMakeFiles.txt у вас заготовка для своего пасса. И компилятор clang/LLVM (а именно так, так как вам нужен ещё и фронтенд) там не прописывается. Вы могли сами это проверить, но давайте я сделаю это за вас:

$ lscpu
Architecture:        e2k
...
CPU family:          4
Model name:          E8C
CPU MHz:             1300
$ git clone https://gitlab.com/vvsamd/the-sieve-of-eratosthenes-in-c
$ cmake --version
cmake version 3.15.4
$ mkdir build && cd build
$ cmake ..
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
...
-- Using LLVM version 9.0.1
...
$ cmake --build . -v
gmake[2]: Entering directory '/the-sieve-of-eratosthenes-in-c/build'
[ 50%] Building CXX object CMakeFiles/sieve_of_Eratosthenes.dir/main.cpp.o
/usr/bin/c++  -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS  -fPIC -fvisibility-inlines-hidden -Werror=date-time -std=c++11 -w -ffunction-sections -fdata-sections -O3   -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -march=native -std=gnu++1z -o CMakeFiles/sieve_of_Eratosthenes.dir/main.cpp.o -c /the-sieve-of-eratosthenes-in-c/main.cpp
[100%] Linking CXX executable sieve_of_Eratosthenes
/usr/bin/cmake -E cmake_link_script CMakeFiles/sieve_of_Eratosthenes.dir/link.txt --verbose=1
/usr/bin/c++   -fPIC -fvisibility-inlines-hidden -Werror=date-time -std=c++11 -w -ffunction-sections -fdata-sections -O3   CMakeFiles/sieve_of_Eratosthenes.dir/main.cpp.o  -o sieve_of_Eratosthenes 
gmake[2]: Leaving directory '/the-sieve-of-eratosthenes-in-c/build'

$ c++ --version 
lcc:1.25.10:Nov--7-2020:e2k-v4-linux
gcc (GCC) 7.3.0 compatible

Что здесь происходит?

  • Я выкачал с вашего gitlab ваш проект

  • Я выполнил его конфигурацию через cmake и получил сообщение, что будет использован компилятор lcc, совместимый с GCC 7.3.0

  • Я получил сообщение, что будет подключен проект LLVM (но не будет использован компилятор clang++/LLVM(!))

  • Я собрал проект и что видно по строкам компиляции, он собирался с помощью LCC

Вы НЕ собрали ваше решето компилятором, связанным с LLVM. Вы подключили с помощью строк, связанных с LLVM всю необходимую инфраструктуру (заголовочные файлы, библиотеки (libllvm?)) для разработки своей фазы компиляции в составе LLVM. Чувствуете разницу?

Чтобы собрать с clang/LLVM достаточно было выполнить:

$ clang++ -O3 main.cpp -o main

Тут даже cmake не нужен. Но если он вам так понравился, то можете написать CMakeLists.txt как-то так

cmake_minimum_required(VERSION 3.7)
project(the_sieve_of_eratosthenes_in_c)

add_compile_options(-march=native)
add_compile_options(-O3)

add_executable(sieve_of_eratosthenes main.cpp)

И собрать так проект так:

$ mkdir build && cd build
$ cmake .. -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang
-- The C compiler identification is Clang 9.0.1
-- The CXX compiler identification is Clang 9.0.1
-- Check for working C compiler: /usr/bin/clang
-- Check for working C compiler: /usr/bin/clang -- works
...
$ cmake --build . -v
[ 50%] Building CXX object CMakeFiles/sieve_of_eratosthenes.dir/main.cpp.o
/usr/bin/clang++    -march=native -O3 -o CMakeFiles/sieve_of_eratosthenes.dir/main.cpp.o -c /the-sieve-of-eratosthenes-in-c/main.cpp
/the-sieve-of-eratosthenes-in-c/main.cpp:168:5: warning: only one parameter on 'main' declaration [-Wmain]
int main(int endValue) {
    ^
1 warning generated.
[100%] Linking CXX executable sieve_of_eratosthenes
/usr/bin/cmake -E cmake_link_script CMakeFiles/sieve_of_eratosthenes.dir/link.txt --verbose=1
/usr/bin/clang++     CMakeFiles/sieve_of_eratosthenes.dir/main.cpp.o  -o sieve_of_eratosthenes 

Теперь мы собрали проект с помощью clang++/LLVM

Давайте я и проведу сравнение (5*10^8 чисел):
clang-9: -O3 3731мс
Но мне clang не интересен.

lcc 1.29: -O3 -march=elbrus-v4: 3364мс
lcc 1.29: -O4 -march=elbrus-v4 -ffast -ffast-math: 2351мс
Замечаем, что счётчики циклов 32-битные, когда мы работаем на 64-битах. Это заставит компилятор генерировать расширение. Замена int -> long int даёт:
lcc 1.29: -O4 -march=elbrus-v4 -ffast -ffast-math + long int 2135мс
Экспериментируем с опциями дальше
lcc 1.29: -O4 -march=elbrus-v4 -ffast -ffast-math -fforce-loop-apb + long int: 2058мс
lcc 1.29: -O4 -march=elbrus-v4 -ffast -ffast-math -fforce-loop-apb -fforce-vect -fforce-swp + long int: 2053мс

Заметим, что есть проблемы с циклом на main.cpp:100. Пометим его #pragma swp

lcc 1.29: -O4 -march=elbrus-v4 -ffast -ffast-math -fforce-loop-apb -fforce-vect -fforce-swp + long int + swp: 2033мс

Судя по perf железо занято на 90.1%. Дальше ускорять уже нет ни желания, ни времени

PGO тут не помогло. Здесь слишком мало кода и предсказатель профиля и так справился хорошо

О, спасибо! Поправлю статью с учётом этих данных.

cmake -- это не компилятор. 

Да я знаю. Я имел ввиду команду, которой запускаю компиляцию. Подразумевая, что настройки компиляции следует читать в CMakeLists.txt.

Вы могли сами это проверить, но давайте я сделаю это за вас:

Честно говоря, в представленном ниже выводе мне и сейчас не очевидно, что LLVM не работает. =)

-- Using LLVM version 9.0.1

...подключен же. Но, видимо, использование LLVM должно выглядеть по другому.

PGO тут не помогло. 

Кстати, получил результат C++ O3+PGO - 2447мс (без прочих -ffast -ffast-math). Пока не опубликовал, т.к. буксует компиляция Rust+PGO.
Не знаю, как вы делали двухфазную компиляцию, но у меня профит хороший получился. В статье укажу подробно как делал.
С вашими рекомендациями: long int, #pragma swp; -O4 -march=elbrus-v4 -ffast -ffast-math -fforce-loop-apb -fforce-vect -fforce-swp  PGO даёт результат 1970мс. (при 1200Мгц), что при пересчёте на 1300Мгц даст 1818мс.
Не хотел обновлять статью с результатом PGO, пока нет аналогичного на Rust. Но на Rust двухфазная компиляция недоступна по независящим от меня причинам и на неопределённое время. Так что выложу пока как есть.

Честно говоря, в представленном ниже выводе мне и сейчас не очевидно, что LLVM не работает. =)

-- Using LLVM version 9.0.1

...подключен же. Но, видимо, использование LLVM должно выглядеть по другому.

Потому что надо задаться вопросом, а что же вы подключили? Конкретно здесь заголовочные файлы и библиотеки для создания своего компилятора на основе LLVM. Чтобы вызывать драйвер компиляции clang/LLVM, достаточно указать -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang. Выше я привёл как это сделать.

Не знаю, как вы делали двухфазную компиляцию, но у меня профит хороший получился.

Компиляция в режиме -fprofile-generate, запуск программы на данных в 5*10^8, компиляция в режиме -fprofile-use, запуск ещё раз для замеров. Получилось то же время исполнения.

DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang. Выше я привёл как это сделать.

Да, спасибо. Позже, если буду дальше закапываться в C++, подойду к компиляции более серьёзно.

Компиляция в режиме -fprofile-generate, запуск программы на данных в 5*10^8,

Я конечно понимаю, что в данной программе скорее всего диапазоны: 0-100М, 0-500М, 0-1000М... дадут одну и ту же статистику. Но сам подход подстановки исключительно данных теста для сбора статистики больше похож на читерство. Нужно же, чтобы после профилирования программа получила бонус на произвольном диапазоне. Я поставлял последовательно: 100М, 500М, 2000М. Процесс подробно описал в разделе "Описание опций тестирования". Профит гарантирован.

... см. "Описание опций тестирования"

Очень странно, что Rust отстает от плюсов в 2 раза!

Я правильно Вас понял?

С++ и Rust компилируют код в промежуточную сущность, передающихся в llvm, на основе которой потом создаётся сам бинарник? И если разработчики Эльбруса настраивали llvm в т.ч. то производительность должна быть сопоставима.

П.С. Не являюсь разработчиком С++ или Rust, мог все напутать=)

Дело в том что llvm задумывался как проект в котором фронтенды и бакенды отдельно, а все это, да, стыкуется через промежуточную сущность.

Но на деле разработчики фронтендов её (сущность) как раз не используют, так как оно ограничивает им возможности по интеграции, они тупо форкают llvm и делают свои rustc ghc итп А вот разработчики железа уже такой возможности не имеют им приходится подстраиваться под "представление" которое llvm выдает для низкого уровня и там уже приходится как то изголяться. Особенно архитектурам отличным от arm и x86. Говорят что низкоуровневый бакенд для видеокарт AMD сумарно больше чем все остальные архитектуры вместе взятые, настолько там костылей пришлось наворотить. Эльбрус просто использует бакенд родного компилятора который научили понимать представление LLVM. Результат ожидаемо хуже родного компилятора, и в два раза это еще оптимистично.

На самом деле отставание может сократиться, когда будет доступен режим PGO для Rust. Для плюсов режим PGO дал шикарный профит, сопоставимый с опцией -ffast-math. Жду обновы ОС до 8.2 на тестовой машине. Может и GO добавлю, если будут адекватные результаты. Реализация на GO есть, но результаты на e2k сейчас совсем неприличные.

Я в этом тоже не силён. Но, как я понимаю, чтобы использовать LLVM при компиляции C++, нужно компилировать через clang. lcc не использует LLVM. Разница видна не только на Эльбрусах, и на x86 тоже. Только там наоборот Rust сильно вперёд ушёл. Но это под Линуксом!
Попробовал под Виндой компилировать. Там для Rust сишный компилятор вроде используется и результат получается уже ближе к сишному (Rust под Виндой медленнее, чем под Линуксом).
Пробовал под Линуксом собрать для Винды бинарник (кросс-компиляция). Бинарник собрался, но при запуске возникли проблемы. Толи библиотеки не хватало, не помню. Не стал в эту тему дальше закапываться.

К методике замеров нет смысла придираться, как говорится, что-то померяли и ладно. Единственное, было бы очень полезно хотя бы изначальный C/rust/Java код привести, а в идеале ещё и ассемблер для каждого варианта компиляции.

Так, вопрос по исходному коду снимается, в конце есть ссылки, но они сливаются с тегами в конце статьи, из-за чего их совсем не заметно. Лучше в начало вынести. По ассемблеру пожелание остаётся в силе

Сделал по отдельной ветке для тестов. Добавил туда исполняемые файлы и ассемблер.

Вы уверены, что использовали GCC? Просто я не встречал адекватного GCC на Эльбрус, а вот LCC (компилятор от МЦСТ) который совместим с GCC до некоторой степени, да.

Для Эльбруса используется lcc. В разделе "Софт" так и указал:

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).

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации