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

Кто быстрее? Тестируем скорость языков программирования на Эльбрусе

Уровень сложностиСредний
Время на прочтение8 мин
Количество просмотров15K

Приветствую! Я разработчик в компании НИЦ ЦТ. Мы разрабатываем операционную систему, адаптированную под российские процессоры Эльбрус. Процессоры Эльбрус работают на своей оригинальной архитектуре, которая имеет свои преимущества и недостатки. В частности, интерпретируемые языки программирования не блещут производительностью. Вот мы и решили провести сравнительное тестирование различных языков, компиляторов и интерпретаторов чтобы выяснить, что лучше использовать для разработки под Эльбрус.

В статье представлены результаты бенчмарка Programming language benchmark, основанного на решении набора задач идентичными алгоритмами, реализованными на разных языках. Это позволяет оценить эффективность генерируемого компиляторами (или интерпретаторами) кода для выбранной архитектуры, поскольку скорость выполнения напрямую зависит от архитектурных особенностей процессора. Учитывая использование одного ядра процессора в тестах, результаты отражают потенциал оптимизации кода на низком уровне для каждого языка программирования в рамках заданной аппаратной платформы. Полученные данные позволят разработчикам делать более обоснованный выбор языка программирования для задач, критичных к производительности, с учетом специфики целевой архитектуры.

Тестируемые железки

Процессоры Эльбрус 2С3 и 8С2 также известный как 8СВ — российские процессоры, разработанные компанией МЦСТ, основанные на архитектуре Эльбрус, которая существенно отличается от x86 и ARM. Вот основные характеристики тестируемых процессоров:

Характеристика

E2C3

E8C2

Производитель

Elbrus-MCST

Elbrus-MCST

Архитектура

e2kv6

e2kv5

Тип архитектуры

VLIW

VLIW

Порядок байтов

Little Endian

Little Endian

Количество ядер

2

8 x 2 = 16

Потоков на ядро

1

1

Базовая частота

1454.54 МГц

960.00 МГц

Максимальная частота

2000.00 МГц

1500.00 МГц

Кэш L1d

128 КБ (2 x 64 КБ)

1 МБ (16 x 64 КБ)

Кэш L1i

256 КБ (2 x 128 КБ)

2 МБ (16 x 128 КБ)

Кэш L2

4 МБ (2 x 2 МБ)

8 МБ (16 x 512 КБ)

Кэш L3

-

32 МБ (2 x 16 МБ)

NUMA узлы

-

2

Оперативная память

16 ГБ

256 ГБ

Важно отметить: Производительность процессоров Эльбрус нельзя напрямую сравнивать с x86 или ARM по тактовой частоте или количеству ядер из-за принципиальных отличий в архитектуре. Эффективность Эльбрус сильно зависит от качества компиляции и оптимизации программного обеспечения.

Данные тесты проводились без оптимизации на уровне кода при помощи сторонних библиотек (были взяты как есть и не подгонялись для оптимизации на 2с3 и 8с2) и только на процессорах Эльбрус.

Методика

В качестве набора тестов был выбран Programming language benchmark. Использовали не все тесты, потому что не всё получилось затащить под е2к.

Наша версия тестов и скрипты для их запуска.

Список доработок незначительный:

  • Добавил версии компиляторов/интерпретаторов прямо в название директории для упрощения работы скрипта-обвязки;

  • Были добавлены отдельные директории для lcc, fortran, clang, java и т.д., для того чтобы можно было одним скриптом запустить тесты сразу для всех версий;

  • Был доработан тест bedcov для go. Авторы оригинального теста использовали функцию мин макса (maxStart = max(maxStart, interval.start)), которую добавят только в версии 1.21. Добавил рукописные функции мин макса, чтобы запускать тесты на МЦСТшном go 1.17

  • Матмул для php отказывался работать, по причине того, что не хватает памяти. Добавил строку, которая увеличивает количество используемой памяти для теста. Не совсем православно выдавать всю память для работы, поэтому добавил возможные значения для функции.

  • Не смог починить судоку для javascript (NodeJS 12, в целом он у МЦСТ очень нестабильно работает, особенно если использовать его для сборки пакетов).

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

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

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

Тесты выполнялись без каких-либо фоновых процессов, которые могли бы "подъесть" ресурсы процессора и памяти.

Тесты запускались на разрабатываемой нами операционной системе CollabOS.

Описание тестов

Programming Language Benchmark включает в себя четыре теста, предназначенных для оценки производительности различных языков программирования в разных сценариях использования:

  1. Bedcov (Поиск перекрытий). Этот тест измеряет скорость поиска перекрывающихся интервалов между двумя массивами размером 1 000 000 элементов. Алгоритм использует структуры данных, подобные неявным интервальным деревьям, и выполняет частые обращения к массиву с помощью метода, похожего на бинарный поиск. Таким образом тест оценивает эффективность работы с большими массивами данных и алгоритмами поиска.

  2. Matmul (Умножение матриц). Данный тест измеряет производительность умножения двух квадратных матриц размером 1500x1500. Тест фокусируется на вычислительной мощности и эффективности работы с математическими операциями, типичными для научных вычислений и задач линейной алгебры.

  3. Nqueen (Задача о N ферзях). Этот тест оценивает скорость решения классической задачи о N ферзях для N=15. Алгоритм решения включает вложенные циклы и целочисленные битовые операции. Тест проверяет эффективность работы с рекурсивными алгоритмами, обработки битовых данных и общую производительность в задачах комбинаторного поиска.

  4. Sudoku (Решение судоку): Этот тест измеряет скорость решения 4000 сложных головоломок судоку (20 уникальных головоломок, каждая решается 200 раз). Используемый алгоритм активно задействует небольшие массивы и сложные логические проверки. Тест предназначен для оценки производительности в задачах с интенсивным использованием ветвлений, рекурсии и обработки небольших структур данных.

Опись компиляторов и интерпретаторов

  • Все версии компиляторов и интерпретаторов указаны в основных табличках снизу.

  • В силу специфики процессоров Эльбрус, часть компиляторов была взята нами в бинарном виде у компании МЦСТ. Например, gccgo. Там сидит портированный go и портированный gcc. Также любопытства ради проверил gcc-fortran. Всё, что идет из этого пакета и используетмя в тестах, я обозначил go-1.17, c-gcc-12 и fortran-gccgo-12.

  • В рамках задачи по портированию Gnome на Эльбрус был портирован GJS. Вслед за этим возникла идея посмотреть его производительность на Эльбрусах.

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

  • luajit (без jit компилятора, но разогнанный под е2к), nodejs-12 (судя по результатам тестов, спойлер, был также разогнан под е2к), nodejs-18 были взяты у МЦСТ.

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

В табличках результатов указаны 6 знаков после запятой, в силу того что погрешности очень малы.

  • Был взят логарифмический масштаб на общих графиках, потому что без него в общий график не влезают все результаты и картинка становится менее наглядной.

  • Ввиду того, что наш дистрибутив собирался исключительно на базе LCC 1.27 и Clang 13 (в очень редких случаях на 1.28), графики отражают только эти версии компиляторов.

  • На общих гистограммах я решил не отображать погрешности, т.к они очень малы - в пределах 1%. В качестве примера можно оценить график производительности для компилятора языка C - lcc-1.27 на 8СВ (для примера был приведен 1 график, остальные можно посмотреть тут и аналогично для 2с3):

Результаты выполнения тестов для Эльбруса 2с3

Все данные в виде markdown таблицы и json формате для 2с3, можно найти тут:

Language/Tests

matmul (sec)

bedcov (sec)

nqueen (sec)

sudoku (sec)

c-lcc-1.26

46.018477 ± 0.040755

6.554327 ± 0.013228

6.689998 ± 0.002236

11.995536 ± 0.006244

c-lcc-1.27

45.994242 ± 0.034278

6.619963 ± 0.008544

6.015713 ± 0.003316

8.606562 ± 0.005744

c-lcc-1.28

45.498233 ± 0.056595

6.559512 ± 0.005567

6.186297 ± 0.001732

8.788083 ± 0.004000

c-lcc-1.29

42.387339 ± 0.050149

6.547222 ± 0.007071

6.184709 ± 0.002828

8.747038 ± 0.003464

c-clang-13

41.851653 ± 0.057157

8.642329 ± 0.011747

6.802236 ± 0.003162

12.697818 ± 0.004690

go-1.17

94.441969 ± 0.152420

15.367779 ± 0.132393

20.853073 ± 0.007937

32.592677 ± 0.014899

c-gcc-12

86.795281 ± 0.041327

13.693220 ± 0.038832

16.618957 ± 0.007745

23.908464 ± 0.009327

fortran-lcc-1.26

0.914164 ± 0.036891

N/A

9.284363 ± 0.004472

14.037174 ± 0.027258

fortran-lcc-1.27

0.905918 ± 0.027549

N/A

7.701214 ± 0.018411

10.258484 ± 0.026229

fortran-lcc-1.28

1.002254 ± 0.030133

N/A

7.185685 ± 0.010198

10.431301 ± 0.008246

fortran-lcc-1.29

0.971973 ± 0.025000

N/A

8.778281 ± 0.003316

10.133026 ± 0.012288

fortran-gccgo-12

69.685218 ± 0.477292

N/A

33.878222 ± 0.288690

25.848793 ± 0.197517

rust-1.64

2.340310 ± 0.004123

11.070235 ± 0.032771

5.410572 ± 0.106808

12.566705 ± 0.021166

ruby-3.0.4

2709.607331 ± 1.185308

334.081656 ± 0.471810

1369.947277 ± 0.557911

1131.851663 ± 0.708690

perl-5.32

3234.667033 ± 3.431771

N/A

2345.188487 ± 1.365431

1457.432020 ± 1.323774

python3.9

4079.257241 ± 8.089523

668.885692 ± 4.851954

3033.103958 ± 0.760878

1363.447443 ± 0.382439

lua-5.1

1098.563232 ± 0.253872

385.296761 ± 1.397590

1825.991608 ± 0.149110

575.102830 ± 0.115490

luajit-2.1.17

299.184096 ± 0.135779

181.714955 ± 0.851839

531.698003 ± 0.030331

193.844777 ± 0.109585

java-8

2.476454 ± 0.024959

20.783304 ± 0.067638

8.335929 ± 0.034727

19.376261 ± 0.075808

java-11

3.638796 ± 0.019287

21.599611 ± 0.209442

10.766053 ± 0.720889

16.196009 ± 0.088960

java-21

11.431950 ± 22.693130

23.712936 ± 0.505195

12.262036 ± 1.922247

18.873130 ± 0.126043

nodejs-12

123.338045 ± 0.239576

54.898590 ± 0.247250

71.148237 ± 0.035749

N/A

nodejs-18

5409.541915 ± 0.233593

537.981153 ± 0.510904

1846.023857 ± 0.088718

N/A

gjs-1.68.6

6443.823039 ± 9.143257

1080.976614 ± 8.666105

2048.610810 ± 1.141611

N/A

Тут стоит отметить, что благодаря итерациям, как на 2с3, так и на 8с2, был выявлен интересный момент с Java 21 в тесте matmul. Примерно раз в несколько итераций, идет просадка по производительности в 20 раз (результаты для 100 итераций тут).

Результаты выполнения тестов для Эльбруса 8СВ

Все данные в виде таблички и json формате для 8СВ, можно найти тут:

Language/Tests

matmul (sec)

bedcov (sec)

nqueen (sec)

sudoku (sec)

c-lcc-1.26

50.107537 ± 0.667140

7.509413 ± 0.184808

8.365281 ± 0.005000

14.125620 ± 0.015000

c-lcc-1.27

45.371574 ± 0.469247

8.298999 ± 0.333499

8.023663 ± 0.002645

9.213383 ± 0.00105

c-lcc-1.28

40.955236 ± 0.345149

8.230248 ± 0.259353

8.141457 ± 0.005196

9.566796 ± 0.002000

c-lcc-1.29

41.049455 ± 0.241745

8.074247 ± 0.168330

8.139281 ± 0.002000

9.554030 ± 0.006000

c-clang-13

39.567161 ± 1.041576

7.953374 ± 0.022045

8.172353 ± 0.004582

9.258615 ± 0.003741

c-gcc-12

92.305233 ± 0.972707

14.405283 ± 0.118667

23.278070 ± 0.009433

30.298655 ± 0.021656

fortran-lcc-1.26

1.248038 ± 0.012569

N/A

11.489687 ± 0.003872

17.361722 ± 0.024576

fortran-lcc-1.27

1.237996 ± 0.012124

N/A

11.371770 ± 0.009949

11.489023 ± 0.019183

fortran-lcc-1.28

1.253795 ± 0.053000

N/A

11.594747 ± 0.005477

11.279128 ± 0.012961

fortran-lcc-1.29

1.320417 ± 0.012041

N/A

12.157142 ± 0.006164

11.125378 ± 0.019493

fortran-gccgo-12

71.728794 ± 0.500424

N/A

47.382606 ± 0.031543

34.709526 ± 0.034117

go-1.17

109.517956 ± 0.370909

17.113163 ± 0.304606

29.165977 ± 0.018761

45.227077 ± 0.044056

rust-1.64

3.369870 ± 0.045310

10.119645 ± 0.212652

7.018275 ± 0.003741

14.163828 ± 0.015905

ruby-3.0.4

2962.821228 ± 4.646511

389.381488 ± 2.069500

1514.496261 ± 7.839792

1269.840341 ± 2.069524

perl-5.30

2985.923036 ± 8.232634

N/A

2128.136913 ± 9.541525

1326.708822 ± 3.107975

python3.9

3961.747212 ± 13.633369

644.227212 ± 3.900435

2970.962179 ± 3.639336

1255.714441 ± 2.347436

lua-5.1

1269.630061 ± 1.870258

453.926534 ± 2.726461

2098.621698 ± 2.174081

702.495539 ± 1.167681

gjs-1.82.1

6296.648035 ± 4.253211

1071.168572 ± 5.486718

2055.754892 ± 1.025071

N/A

root-6.34.04

86.518659 ± 0.602703

350.379146 ± 1.674310

24.370312 ± 0.174186

N/A

luajit-2.1.17

331.189776 ± 0.197704

186.639189 ± 2.350201

479.280251 ± 0.530742

203.152896 ± 1.063096

php-8.0.30

1502.370196 ± 1.061911

N/A

473.953242 ± 0.160440

N/A

java-8

3.304341 ± 0.055865

23.330780 ± 0.673792

9.668329 ± 0.132109

16.858895 ± 0.079642

java-11

4.799246 ± 0.090609

29.248166 ± 0.273656

12.488790 ± 1.198363

17.025452 ± 0.067579

java-21

20.402550 ± 32.545856

24.561253 ± 0.678723

14.203131 ± 1.451524

20.962986 ± 0.750061

nodejs-18

5720.840235 ± 2.966322

557.281874 ± 0.658642

1907.709117 ± 0.996604

N/A

.

Общие графики результатов:

Также эти графики можно найти тут:

Без итогов

Целью данных тестов было показать, какой язык для разработки более предпочтителен на Эльбрусах, если важна скорость выполнения. Выводы делайте сами.
Лично я слегка удивлен результатами. Но, напоминаю, Эльбрусы очень чувствительны к оптимизации, поэтому отдельно я провел тестирование для оптимизированных тестов. Скоро опубликую результаты, поверьте, там есть над чем призадуматься.

Теги:
Хабы:
+37
Комментарии98

Публикации

Информация

Сайт
nicct.ru
Дата регистрации
Дата основания
2023
Численность
51–100 человек