Русский
Русский
English
Статистика
Реклама

E2k

Эльбрус VS Intel. Сравниваем производительность систем хранения Аэродиск Восток и Engine

28.09.2020 06:06:32 | Автор: admin


Всем привет. Мы продолжаем знакомить вас с системой хранения данных Аэродиск ВОСТОК, выполненной на базе российского процессора Эльбрус 8C.


В этой статье мы (как и обещали) детально разберем одну из популярнейших и интереснейших тем, связанной с Эльбрусами, а именно производительность. На тему производительности Эльбруса есть достаточно много спекуляций, причем абсолютно полярных. Пессимисты говорят, что производительность Эльбруса сейчас никакая, и чтобы догнать топовых производителей потребуются десятилетия (т.е. в условиях нынешней реальности никогда). С другой стороны, оптимисты говорят, что уже сейчас Эльбрус 8C показывает хорошие результаты, а в ближайшие пару лет с выходом новых версий процессоров (Эльбрус 16С и 32С) мы сможем догнать и перегнать ведущих мировых производителей процессоров.


Мы в Аэродиске люди практичные, поэтому пошли самым простым и понятным (для нас) путем: протестировать, зафиксировать результаты и только потом делать выводы. В итоге мы провели довольно большое количество тестов и обнаружили ряд особенностей работы Эльбруса 8С архитектуры e2k (в том числе, и приятных) и, конечно же, сравнили это с аналогичными СХД на процессорах Intel Xeon архитектуры amd64.


Кстати, более подробно о тестах, результатах и о будущем развитии СХД на Эльбрусах мы поговорим на нашем очередном вебинаре "ОколоИТ" 15.10.2020 в 15 00. Зарегистрироваться можно по ссылке ниже.


РЕГИСТРАЦИЯ НА ВЕБИНАР


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


Мы создали два стенда. Оба стенда состоят из сервера с Linux-ом, подключенного через 16G FC-коммутаторы к двум котроллерам СХД, в которой установлено 12 SAS SSD 960 ГБ дисков (11,5 ТБ сырой емкости или 5,7 ТБ полезной емкости, если используем RAID-10).


Схематично стенд выглядит следующим образом.



Стенд 1 e2k (Эльбрус)


Конфигурация оборудования следующая:


  • Linux-сервер (2xIntel Xeon E5-2603 v4 (6 cores, 1,70Ghz), 64 GB DDR4, 2xFC-адаптер 16G 2 порта) 1шт.
  • Коммутатор FC 16 G 2 шт.
  • СХД Аэродиск Восток 2-Э12 (2xЭльбрус 8С (8 cores, 1,20Ghz), 32 GB DDR3, 2xFE FC-adaptor 16G 2 port, 12xSAS SSD 960 GB) 1 шт

Стенд 2 amd64 (Intel)


Для сравнения с аналогичной конфигурации на e2k использовалась похожая конфигурация СХД с похожим процессором по характеристикам на amd64:


  • Linux-сервер (2xIntel Xeon E5-2603 v4 (6 cores, 1,70Ghz), 64 GB DDR4, 2xFC-адаптер 16G 2 порта) 1шт.
  • Коммутатор FC 16 G 2 шт.
  • СХД Aerodisk Engine N2 (2xIntel Xeon E5-2603 v4 (6 cores, 1,70Ghz), 32 GB DDR4, 2xFE FC-adaptor 16G 2 port, 12xSAS SSD 960 GB) 1 шт

Важное замечание: используемые в тесте процессоры Эльбрус 8С поддерживают оперативную память только DDR3, это конечно плохо, но не долго. Эльбрус 8СВ (в наличие его у нас пока нет, но скоро будет) поддерживает DDR4.


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


Для генерации нагрузки мы использовали популярную и проверенную временем программу Flexible IO (FIO).


Обе СХД сконфигурированы согласно нашим же рекомендациям по настройке, исходя из требований к высокой производительности на блочном доступе, поэтому используем дисковые пулы DDP (Dynamic Disk Pool). Чтобы не искажать результаты тестирования, на обеих СХД отключаем, компрессию, дедупликацию и RAM-кэш.


Созданы 8 D-LUN-ов в RAID-10 по 500 ГБ, каждый, суммарный полезный объём составляет 4 ТБ (т.е. примерно 70% от возможной полезной емкости данной конфигурации).


Выполняться будут основные и популярные сценарии использования СХД, в частности:


первые два теста эмулируют работу транзакционной СУБД. В этой группе тестов нам интересны IOPS-ы и задержка.


1) Случайное чтение маленькими блоками 4k
a. Размер блока = 4k
b. Чтение/запись = 100%/0%
c. Количество работ = 8
d. Глубина очереди = 32
e. Характер нагрузки = Full Random


2) Случайная запись маленькими блоками 4k
a. Размер блока = 4k
b. Чтение/запись = 0%/100%
c. Количество работ = 8
d. Глубина очереди = 32
e. Характер нагрузки = Full Random


вторые два теста эмулируют работу аналитической части СУБД. В этой группе тестов нам также интересны IOPS-ы и задержка.


3) Последовательное чтение маленькими блоками 4k
a. Размер блока = 4k
b. Чтение/запись = 100%/0%
c. Количество работ = 8
d. Глубина очереди = 32
e. Характер нагрузки = Sequential


4) Последовательная запись маленькими блоками 4k
a. Размер блока = 4k
b. Чтение/запись = 0%/100%
c. Количество работ = 8
d. Глубина очереди = 32
e. Характер нагрузки = Sequential


третья группа тестов эмулирует работу потокового чтения (пример онлайн трансляции, восстановление резервных копий) и потоковой записи (пример видеонаблюдение, запись резервных копий). В этой группе тестов нам уже интересны не IOPS-ы, а MB/s и также задержка.


5) Последовательное чтение большими блоками 128k
a. Размер блока = 128k
b. Чтение/запись = 0%/100%
c. Количество работ = 8
d. Глубина очереди = 32
e. Характер нагрузки = Sequential


6) Последовательная запись большими блоками 128k
a. Размер блока = 128k
b. Чтение/запись = 0%/100%
c. Количество работ = 8
d. Глубина очереди = 32
e. Характер нагрузки = Sequential


Каждый тест будет длиться один час без учета времени прогрева массива в 7 минут.


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


Результаты тестов сведены в две таблицы.


Эльбрус 8С (СХД Аэродиск Восток 2-Э12)



Intel Xeon E5-2603 v4 (СХД Аэродиск Engine N2)



Результаты получились крайне интересные. В обоих случаях мы хорошо утилизировали процессорные мощности СХД (70-90% утилизации), и при таком раскладе явно бросаются в глаза плюсы и минусы обоих процессоров.


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


Если говорить о случайной нагрузке небольшими блоками, то:


  • с точки зрения случайного чтения Intel, безусловно, впереди Эльбруса, разница в 2 раза;
  • с точки зрения случайной записи однозначно ничья, оба процессора показали примерно равные и достойные результаты.

В последовательной нагрузке небольшими блоками картина другая:


  • и при чтении, и при записи Intel существенно (в 2 раза) опережает Эльбрус. При этом, если у Эльбруса показатель IOPS ниже чем у Intel, но выглядит достойно (200-300 тысяч), то с задержками явная проблема (они в три раза выше чем у Intel). Вывод, текущая версия Эльбруса 8С очень не любит последовательные нагрузки небольшими блоками. Явно есть над чем работать.

А вот в последовательной нагрузке большими блоками картина прямо противоположная:


  • оба процессора показали примерно равный результат в MB/s, но есть одно НО. Показатели задержек у Эльбруса в 10 (в десять, Карл!!!) раз лучше (т.е. ниже), чем у аналогичного процессора от Intel (0,4/0,5 ms против 5,1/6,5 ms). Вначале мы подумали, что это глюк, поэтому мы перепроверили результаты, сделали повторный тест, но повторный тест показал ту же картину. Это серьезное преимущество Эльбруса (и архитектуры e2k в целом) перед Intel (и, соответственно, архитектуры amd64). Будем надеяться, что этот успех получит дальнейшее развитие.

Есть ещё одна интересная особенность Эльбруса, на которую внимательный читатель может обратить внимание, посмотрев на таблицу. Если взглянуть на разницу показателей чтения и записи у Intel, то во всех тестах чтение опережает запись в среднем примерно на 50%+. Это норма, к которой все (в том числе и мы) привыкли. Если посмотреть на Эльбрус, то показатели записи значительно ближе к показателям чтения, чтение опережает запись, как правило, на 10 30%, не более.


О чем это говорит? О том, что Эльбрус очень любит запись, а это, в свою очередь, говорит о том, что этот процессор будет очень полезен в задачах, где запись явно преобладает над чтением (кто сказал закон Яровой?), что также является несомненным преимуществом архитектуры e2k, и это преимущество нужно развивать.


Выводы и ближайшее будущее


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


Intel сильно превзошел Эльбрус в случайном чтении небольшими блоками, а также в последовательном чтении и записи небольшими блоками.


При случайной записи небольшими блоками оба процессора показывают равные результаты.


По показателям задержки Эльбрус выглядит значительно лучше Intel-а в потоковой нагрузке, т.е. в последовательном чтении и записи большими блоками.


Кроме того, Эльбрус в отличии от Intel, одинаково хорошо справляется как с нагрузками чтения, так и с нагрузками записи, в то время как у Intel чтение всегда значительно лучше записи.
Исходя из полученных результатов можно сделать вывод о применимости систем хранения данных Аэродиск Восток на процессоре Эльбрус 8С в следующих задачах:


  • информационные системы с преобладанием операций записи;
  • файловый доступ;
  • онлайн-трансляции;
  • видеонаблюдение;
  • резервное копирование;
  • медиа-контент.

Коллективу МЦСТ есть ещё над чем работать, но результат их работы виден уже сейчас, что, конечно, не может не радовать.


Данные тесты проводились на ядре Linux для e2k версии 4.19, на текущий момент в бета-тестах (в МЦСТ, в Базальт СПО, а также у нас, в Аэродиске) находится ядро Linux 5.4-e2k, в котором, кроме всего прочего, серьезно переработан планировщик и много оптимизаций под скоростные твердотельные накопители. Также специально для ядер ветки 5.х.х АО МЦСТ выпускает новый компилятор LCC версии 1.25. По предварительным результатам, на том же процессоре Эльбрус 8С, собранное новым компилятором новое же ядро, окружение ядра, системные утилиты и библиотеки и, собственно, ПО Аэродиск ВОСТОК позволит получить ещё более значительный прирост производительности. И это без замены оборудования на том же процессоре и с теми же частотами.


Мы ожидаем выхода версии Аэродиск ВОСТОК на базе ядра 5.4 ближе к концу года, и как только работа над новой версией будет завершена, мы обновим результаты тестирования и также опубликуем их здесь.


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


Эльбрус уже сейчас показывает хорошие результаты, если сравнивать его с процессорами amd64 среднего уровня. До верхних в линейке моделей серверных процессоров Intel или AMD 8-ке Эльбруса, конечно, далеко, но она туда и не целилась, для этого будут выпущены процессоры 16С и 32С. Вот тогда и поговорим.


Мы понимаем, что после этой статьи вопросов про Эльбрус станет ещё больше, поэтому мы решили организовать ещё один онлайн-вебинар ОколоИТ, чтобы в прямом эфире на эти вопросы дать ответы.


В этот раз у нас в гостях будет заместитель генерального директора компании МЦСТ, Константин Трушкин. Записаться на вебинар можно по ссылке ниже.


РЕГИСТРАЦИЯ НА ВЕБИНАР


Всем спасибо, как обычно ждем конструктивной критики и интересных вопросов.

Подробнее..

Нагрузочное тестирование СХД на Эльбрусе на базе нового ядра Линукс версии 5.4

31.05.2021 06:09:55 | Автор: admin


Тестирование СХД Аэродиск Восток на базе процессоров Эльбрус 8С на новом ядре 5.4 показало крайне позитивный результат: 1,4 миллиона IOPS! Пока оптимисты верили и надеялись, а пессимисты снисходительно улыбались, программисты работали писали код. В итоге новая версия ядра Линукс v5.4 для архитектуры Эльбрус позволила в разы улучшить производительность подсистемы ввода-вывода и полностью реализовать процессора Эльбрус 8С/СВ для систем хранения данных.


По этому прекрасному поводу мы в Аэродиске, предварительно обновив боевую версию встроенного Альт-Линукса в СХД ВОСТОК до ядра 5.4, повторно выполнили нагрузочное тестирование СХД, которое мы публиковали полгода назад. С прошлым отчетом можно ознакомиться по данной ссылке.


Новые тесты проводились на долгожданном ядре Линукс для e2k версии 5.4, которое появилось начале 2021 года, за что хотим сказать огромное спасибо коллективам разработчиков МЦСТ, Базальт СПО, а также Михаилу Шигорину лично.


В ядре 5.4 изменений много, но нас интересуют только основные изменения с точки зрения СХД, а их можно разделить на следующие группы:


Общие обновления:


  • переработан планировщик ввода-вывода, что позволяет лучше параллелить IO между дисками;
  • много мелких оптимизаций под скоростные твердотельные накопители;
  • и самое главное изменение новый компилятор от МЦСТ (LCC версии 1.25).

Обновления от Аэродиска:


  • обновлённый таргет-драйвер, который позволяет лучше параллелить IO между процессорными ядрами;
  • обновление логики работы связки ядро процессора диск для систем на Эльбрусе.

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


Тестирование мы выполняли на том же железе, что и в прошлый раз. Стенд состоит из сервера с Линуксом, подключенного через FC-коммутатор к двум контроллерам СХД Восток, в которой установлено 12 SAS SSD дисков.


Конфигурация оборудования следующая:


  • Linux-сервер (2xIntel Xeon E5-2603 v4 (6 cores, 1,70Ghz), 64 GB DDR4, 2xFC-адаптер 16G 2 порта) 1шт.
  • Коммутатор FC 16G 1 шт.
  • СХД Аэродиск Восток 2-Э12 (2xЭльбрус 8С (8 cores, 1,20Ghz), 32 GB DDR3, 2xFE FC-adaptor 16G 2 port, 12xSAS SSD 960 GB) 1 шт

Ниже схема стенда.



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


Также как и в прошлый раз для нагрузочных тестов мы использовали популярную и проверенную временем программу Flexible IO (FIO).


СХД сконфигурирована исходя из наших рекомендаций к высокой производительности на блочном доступе или просто настройки для ALL-Flash систем. Поэтому используем не менее двух дисковых пулов DDP (Dynamic Disk Pool). Чтобы не бить в одну точку и максимально реализовать вычислительный потенциал платформы создаем несколько LUN-ов в RAID-10 (8 шт. по 500 ГБ каждый).


Все LUN-ы презентуем двум контроллерам (пополам, по 4 каждому), чтобы максимально утилизировать все ресурсы СХД.


В ходе тестирование будут выполняться следующие популярные сценарии использования СХД, в частности:


Последовательная нагрузка маленькими блоками 4k


  • 100%_read_4k_sequential
  • 100%_write_4k_sequential

Случайная нагрузка маленькими блоками 4k


  • 100%_read_4k_random
  • 100%_write_4k_random

Последовательная нагрузка большими блоками 128k


  • 100%_read_128k_sequential
  • 100%_write_128k_sequential

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


Во всех тестах мы, чтобы не искажать результаты тестирования, намеренно отключаем RAM-кэш СХД, который используется для ускорения ввода-вывода, компрессии и дедупликации. Забежим вперед и отдельно скажем про утилизацию оперативной памяти СХД в целом (чтобы к этому вопросу больше не возвращаться). Во всех тестах RAM утилизируется практически одинаково, т.е. слабо, т.к RAM-кэш, дедуп и компрессия отключены. Вся утилизация RAM это внутренние системные операции СХД. Если бы мы включили RAM-кэш, то результаты были бы заметно лучше, но тогда тест был бы не совсем честным. При этом график утилизации оперативки мы для порядка все-равно приводим в отчете ниже.


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


100%_read_4k_sequential

[global]
blocksize=4k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=128
group_reporting
rw=read
numjobs=16
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/read-iodepth-128-numjobs-16
write_iops_log=./logs/read-iodepth-128-numjobs-16
write_lat_log=./logs/read-iodepth-128-numjobs-16
[job-1]
filename=/dev/sdj
[job-2]
filename=/dev/sdc
[job-3]
filename=/dev/sdd
[job-4]
filename=/dev/sde
[job-5]
filename=/dev/sdf
[job-6]
filename=/dev/sdg
[job-7]
filename=/dev/sdh
[job-8]
filename=/dev/sdi


100%_write_4k_sequential

[global]
blocksize=4k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=128
group_reporting
rw=write
numjobs=16
runtime=2400
time_based=1


write_bw_log=./logs/4k-seq-write.results


write_iops_log=./logs/4k-seq-write.results


write_lat_log=./logs/4k-seq-write.results


[job-1]
filename=/dev/sdj
[job-2]
filename=/dev/sdc
[job-3]
filename=/dev/sdd
[job-4]
filename=/dev/sde
[job-5]
filename=/dev/sdf
[job-6]
filename=/dev/sdg
[job-7]
filename=/dev/sdh
[job-8]
filename=/dev/sdi


100%_read_4k_random

[global]
blocksize=4k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=64
group_reporting
rw=randread
numjobs=2
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/4k-rand-read.results
write_iops_log=./logs/4k-rand-read.results
write_lat_log=./logs/4k-rand-read.results
[job-1]
filename=/dev/sdc
[job-2]
filename=/dev/sdd
[job-3]
filename=/dev/sde
[job-4]
filename=/dev/sdf
[job-5]
filename=/dev/sdg
[job-6]
filename=/dev/sdh
[job-7]
filename=/dev/sdi
[job-8]
filename=/dev/sdj


100%_write_4k_random

[global]
blocksize=4k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=16
group_reporting
rw=randwrite
numjobs=2
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/4k-rand-write.results
write_iops_log=./logs/4k-rand-write.results
write_lat_log=./logs/4k-rand-write.results
[job-1]
filename=/dev/sdc
[job-2]
filename=/dev/sdd
[job-3]
filename=/dev/sde
[job-4]
filename=/dev/sdf
[job-5]
filename=/dev/sdg
[job-6]
filename=/dev/sdh
[job-7]
filename=/dev/sdi
[job-8]
filename=/dev/sdj


100%_read_128k_sequential

[global]
blocksize=128k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=128
group_reporting
rw=read
numjobs=16
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/128k-seq-read.results
write_iops_log=./logs/128k-seq-read.results
write_lat_log=./logs/128k-seq-read.results
[job-1]
filename=/dev/sdj
[job-2]
filename=/dev/sdc
[job-3]
filename=/dev/sdd
[job-4]
filename=/dev/sde
[job-5]
filename=/dev/sdf
[job-6]
filename=/dev/sdg
[job-7]
filename=/dev/sdh
[job-8]
filename=/dev/sdi


100%_write128k_sequential

[global]
blocksize=128k
size=80%
direct=1
buffered=0
ioengine=libaio
iodepth=16
group_reporting
rw=write
numjobs=2
runtime=2400
time_based=1
per_job_logs=0
log_avg_msec=30000
write_bw_log=./logs/128k-seq-write.results
write_iops_log=./logs/128k-seq-write.results
write_lat_log=./logs/128k-seq-write.results
[job-1]
filename=/dev/sdj
[job-2]
filename=/dev/sdc
[job-3]
filename=/dev/sdd
[job-4]
filename=/dev/sde
[job-5]
filename=/dev/sdf
[job-6]
filename=/dev/sdg
[job-7]
filename=/dev/sdh
[job-8]


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


Последовательная нагрузка маленькими блоками 4k


100%_read_4k_sequential
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


100%_write_4k_sequential
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


Результат:


Результаты теста с использованием последовательного характера нагрузки небольшими блоками 4k нас впечатлили, получилось !1,4 миллиона! IOPS на чтение и 700k на запись. Если сравнивать это с предыдущим нашим тестом на ядре 4,19 (371k и 233k IOPS), то это скачек в четыре раза при том, что железо мы не меняли.


Также отмечаем довольно небольшую утилизацию CPU, она примерно на 20% ниже предыдущего теста (69/71% против 76/92%).
Задержки при этом остались на том же уровне, что и полгода назад, это не значит, что с этим мы думаем мириться, это значит, что над этим мы ещё будем работать. В конце статьи, будет итоговая таблица сравнения с тестом полугодовой давности на ядре 4,19.


Случайная нагрузка маленькими блоками 4k


100%_read_4k_random
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


100%_write_4k_random
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


Результат:


Показатели случайной нагрузки маленькими блоками, характерной для транзакционных СУБД остались практически без изменений по сравнению с прошлым тестом. СХД Восток на Эльбрусе вполне нормально справляется с подобными задачами, выдавая 118k IOPS на чтение и 84k IOPS на запись при довольно высокой утилизации CPU.


Отмечаем, что для Эльбруса в отличии от других процессоров работа в режиме постоянной загрузки близкой к 100% является штатной ситуацией (он для этого создавался). Мы это проверяли, оставляя СХД Восток с нагруженным процессором под 95% на несколько дней и результат был следующий: 1) процессор был холодный; 2)процессор и система в целом работали в нормальном режиме. Поэтому к высокому уровню утилизации процессоров Эльбрус следует относиться спокойно.


Также с прошлого ядра сохранилась приятная особенность. Если посмотреть на задержки при случайной нагрузке маленькими блоками, то внимание привлекает то, что задержки на запись ниже, чем на чтение (3 мс против 8 мс), когда мы все привыкли, что должно быть наоборот. Эльбрус с точки зрения случайного характера нагрузки по-прежнему любит запись больше чем чтение, что несомненно является отличным преимуществом, которое грех не использовать.


Последовательная нагрузка большими блоками 128k


100%_read_128k_sequential
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


100%_write_128k_sequential
График загрузки CPU СХД и RAM СХД


Ввод-вывод СХД, IOPS и latency


Результат:


Ещё полгода назад СХД Восток на базе процессоров Эльбрус показала отличный результат в тесте последовательной нагрузки большими блоками, что актуально для видеонаблюдения или трансляций. Особой фишкой Эльбруса были ультранизкие задержки при работе с большими блоками (0,4-0,5 мс против 5 6 мс у аналогичного процессора архитектуры x-86).


При чтении данных большими блоками данное преимущество удалось не только закрепить, но и развить. Максимальную скорость на новом ядре удалось поднять в два раза (5,7 ГБ/с на ядре 5.4 против 2,6 ГБ/с на ядре 4.19) при задержках 0,3 мс! Также нагрузка на процессор при данном тесте тоже выглядит лучше (52% на 5,4 против 75% на 4,19).


А вот с записью не так все радужно. К сожалению, в новой версии ядра получить ультранизкие задержки на запись уже не удается, во всяком случае пока. Они находятся на уровне 11 мс (а было 0,5 мс), что в целом не плохо, т.к. примерно такой же уровень задержек при таком тесте мы видим на процессорах других архитектур. Так или иначе это наше домашнее задание, над которым мы будем работать. При этом позитивный момент все-таки есть. Как и в других тестах утилизация процессора значительны снижена (74% против 95%).


Итоговые результаты тестирования АЭРОДИСК ВОСТОК на базе процессоров Эльбрус 8 С, ядро 5.4


Улучшение в 5.4 зеленые, ухудшения 5.4 оранжевые


Для сравнения, результаты тестирования АЭРОДИСК ВОСТОК на базе процессоров Эльбрус 8С, ядро 4.19


Улучшение в 5.4 зеленые, ухудшения в 5.4 оранжевые


Прогресс виден не вооруженным глазом! Новая версия ядра 5.4 для архитектуры Эльбрус позволила выжать практические максимумы из совсем не нового процессора Эльбрус 8С (2016 г. выпуска). На данный момент даже у самых ярых пессимистов уже не повернется язык назвать процессор Эльбрус медленным, все таки полтора миллиона IOPS это много.


В очередной раз мы убедились в отличной работе СХД на Эльбрусе среде, где преобладает последовательная нагрузка, а это аналитические СУБД, онлайн-трансляции, видеонаблюдение, обработка больших данных и т.п.


Кроме того, Эльбрус отлично себя показывает в случайной нагрузке на запись, показывая минимальные задержки, что актуально для классических транзакционных СУБД.


Безусловно есть ещё над чем работать (те же задержки при записи больших потоков), но за прошедшие полгода коллектив МЦСТ проделал титаническую работу, и она дала видимый результат, что не может не радовать.


В конце этого 21-ого года мы ожидаем новый процессор Эльбрус 16С, который, кроме того что будет намного быстрее, ещё будет поддерживать аппаратную виртуализацию, а это значит что у нас в России наконец-то появится полностью отечественные не только СХД, но и системы виртуализации, и гиперконвергентные системы (кто сказал АИСТ и vAIR?))).


Кстати о птичках! В течение этой недели мы определимся с датами следующего технического вебинара ОколоИТ про нашу систему виртуализации АИСТ и гиперконвергентную систему vAIR, ссылка на регистрацию появится в этой статье (следите за обновлением), а также в нашем телеграмм-чате.
Ну и само собой, не можем не напомнить о бесплатных курсах по системам Аэродиск, на которые можно записаться тут.


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

Подробнее..

История портирования Reindexerа как покорить Эльбрус за 11 дней

15.06.2021 18:13:51 | Автор: admin

Всем привет! На связи Антон Баширов, разработчик из ИТ-кластера Ростелекома. Импортозамещение набирает обороты, а российский софт всё глубже проникает в нашу повседневную ИТ-шную сущность бытия. Процессоры Эльбрус и Байкал становятся более востребованными, комьюнити расширяется, но мысли о необходимости портировать весь наш любимый технологический стек на неизведанную архитектуру E2K звучат страшнее рассказов про горящий в пламени production-кластер.

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

Итак, гость в студии база данных Reindexer, разработка нашего ИТ-кластера.

Стоит сказать, почему выбор пал именно на Reindexer, а не другую БД. Во-первых, всеми любимый и известный Postgres уже есть в составе пакетов ОС Эльбрус. Переносить его нет необходимости. Во-вторых, наш гость уже прошел испытания на ARM, следовательно, пришло время ему покорить Эльбрус.

Стоит упомянуть, что Reindexer появился на свет как продуктвыбора между Elastic и Tarantool. Это определенно хочется попробовать завести на отечественном процессоре.

День 0. Знакомство с гостем

Несколько слов про нашего гостя:

Имя:NoSQL in-memory database Reindexer с функционалом полнотекстового поиска
Возраст:на момент испытаний версия БД была 3.1.2
Происхождение:Россия
Место рождения:пытливый ум разработчика Олега Герасимова@olegator99
Место жительства:https://github.com/Restream/reindexer
Место работы:Ростелеком
Строение:основная составляющая C++, имеются примеси из языка Ассемблера и немного CMake
Особенности:- Ассемблерные вставки;
- Много С++11 и C++14;
- Используются корутины.

Деятельность:- Хранение данных в памяти и на диске;
- Выполнение SQL запросов со скоростью 500K queries/sec для PK запросов;
- Выполнение запросов типа full-text search (почти как Elastic, только не тормозит);
- Работа в режиме server и embedded;
- Общение с крутыми парнями: Go, Java, Rust, .NET, Python, C/C++ и (да простит меня Хабр) PHP.

Заскучали? На этом нудная часть закончилась. В эфире рубрика Ээээксперименты!

День 1. А ты думал, в сказку попал?

Для начала попробуем нашего друга собрать из того, что есть.Идем на тестовый сервер Эльбрус 8C с ОС Эльбрус 6.0.1, клонируем туда репозиторий и запускаем CMake.

Хорошие новости, мы нашли компилятор! Новость действительно хорошая, ведь у Эльбруса свой компилятор LCC.

К счастью, создатели Эльбрус сделали LCC полностью совместимым с GCC и наши любимые нативные программки и сборщики смогут чувствовать себя хорошо без особых манипуляций. LCC уже сделал за вас нужные линки:gcc -> /opt/mcst/bin/lcc*.

Зачем Эльбрусу свой компилятор?

Дело в том, что компилятор у Эльбруса не такой, как все. Он выполняет много работы, связанной с анализом зависимостей и оптимизацией:

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

Ключевая идея архитектуры давайте попробуем выполнить несколько операций за один присест. Эльбрусы позволяют реализовать параллельные выполнение кода без применения многопоточности. Достигается это путем одновременного выполнения разных инструкций внутри одной широкой команды на разных устройствах процессора. Но для того, чтобы процессор понимал, что от него хотят и мог правильно распределить инструкции, ему нужно дать на вход оптимизированный поток больших команд. Именно в формировании этого потока и заключается назначение LCC компилировать код так, чтобы широкие команды содержали параллельно выполняемые инструкции с целью задействовать все устройства CPU. Подробнеетут.

Но вернемся к нашему гостю и тому, что не понравилось CMake.

В скриптах сборки, в CMakeLists.txt выполняется определение операционной системы и архитектуры процессора, на которой собирается Reindexer. Нужно это для того, чтобы подключать правильные исходники ассемблера, ведь как говорится Write once, run anywhere.

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

Программисты люди ленивые, поэтому:

Попытка 2:

А что так можно было? На самом деле да для того, чтобы завелся CMake, этого было достаточно. Теперь ударим в бубен и запустимmake -j8:

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

Поэтому, в некоторые места кода Reindexer понадобилось добавить парочку новых условий для__E2K__и__LCC__:

После колдовства с макросами нас ждал монстр пострашнее:

Вот что бывает, когда игнорируешь messages у CMake.

Из-за того, что CMake не нашел подходящих исходников, компилятор не смог найти реализации двух функций:jump_fcontextиmake_fcontext. Про назначение этих функций я расскажу чуть позже, а пока что давайте успокоим нашего гостя и подсунем ему пару пустышек:

Этих операций оказалось достаточно, чтобы Reindexer собрался.

Поздравляю, у вас двойня!

Вот они, наши два долгожданных файла:

# file reindexer_serverreindexer_server: ELF 64-bit LSB executable, MCST Elbrus, version 1 (GNU/Linux
# file reindexer_toolreindexer_tool: ELF 64-bit LSB executable, MCST Elbrus, version 1 (GNU/Linux), dynamically linked, interpreter /lib64/ld-linux.so.2, for GNU/Linux 2.6.33, with debug_info, not stripped

Это можно считать успехом. Мы смогли собрать наш первый Эльбрус-бинарник. Даже два бинарника: reindexer_server и reindexer_tool.

Подведем итоги. Чтобы собрать Reindexer, мы:

  • Поправили CMake-скрипты;

  • Добавили несколько условий в макросы препроцессора;

  • Заглушили ASM функции.

День 3. Наш Гость, попав на Эльбрус, начал подавать признаки жизни

Первый запуск прошел успешно - сервер поднялся, и даже открылся web-ui.

Я привык не останавливаться на достигнутом и решил немного поработать над Reindexer.

Результат меня порадовал - Гость устал и прилег отдохнуть:

Такое поведение наблюдалось только на Эльбрус. На i5 все работало штатно.

Давайте разбираться. Вооружившись отладчиком (gdb кстати под E2K работает прекрасно) и CLion, мне удалось докопаться до истины.

Пару запросов к Reindexer смогли воспроизвести ошибку:

Падает в деструкторе. Интересный момент - упало на free (в данном случае free реализуется через jemalloc). Видимо, здесь идет высвобождение памяти по некорректному указателю. Ошибку эту я исправлял в два этапа:

  1. work around - дело в том, что QueryEntry лежит в объекте ExpressionTree, в самом классе примечательного я не нашел, поэтому копнул в сторону родителя. Оказалось, что до вызова деструктора был вызван вот такой копирующий конструктор, в котором есть интересный MakeDeepCopy(), реализованный с помощью библиотечкиmpark-variant.

    Подробнее про expression tree рассказываюттут.

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

    Итог - оно заработало.

  2. TODO: Исправление тоже есть, но рассказ про него уже выходит за рамки данной статьи. Небольшой спойлер (код из mpark-variant с патчем под e2k):

inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs)#ifdef E2K //Fix for Elbrus    -> decltype(detail::visitation::variant::visit_value(lib::forward<Visitor>(visitor),                                                 lib::forward<Vs>(vs)...))    {     return detail::visitation::variant::visit_value(lib::forward<Visitor>(visitor),                                                 lib::forward<Vs>(vs)...);    }#else    DECLTYPE_AUTO_RETURN(        (detail::all(             lib::array<bool, sizeof...(Vs)>{{!vs.valueless_by_exception()...}})             ? (void)0             : throw_bad_variant_access()),        detail::visitation::variant::visit_value(lib::forward<Visitor>(visitor),                                                 lib::forward<Vs>(vs)...))#endif

День 5. Он ожил! Ну почти

Сервер у нас, действительно, работает, даже удалось получить первые результаты бенчмарков.

Но все это время я упорно игнорировал один компонент.

Помните, как мы убрали завязку на ASM и функцииmake_fcontext и jump_fcontext?

Так вот, ASM исходники в Reindexer нужны для реализации C++ корутин, а эти функции - ключевые для корутин из библиотеки boost/context.

Кто такая эта ваша Корутина?

Корутина это функция, которая может быть приостановлена и возобновлена в любой момент. Для реализации достаточно трех основных компонентов:
- функция
- механизм для ее паузы (suspend)
- механизм для возобновления ее с той точки, в которой была сделана пауза (resume).

Реализацию корутин можно увидеть в таких языках и библиотеках, как:

  • Libcoro(корутины на C/С++)

  • Koishi(тоже корутины, тоже на С/С++)

  • Boost(и это тоже корутины, тоже на С/С++, корутин много не бывает!)

  • Node-fibers(корутины для NodeJS на базе libcoro)

  • Tarantool(fibers на базе libcoro)

  • Kotlin(свои корутины, не на C++)

  • C++20

  • Goroutine

Для наглядности вот скрин теста корутин из Koishi:

Последовательность следующая:

  1. Создали корутину, выделили стек, задали функцию;

  2. Возобновили корутину - в этот момент вызвалась наша функция;

  3. Приостановили корутину с помощьюkoishi_yield здесь мы вернули управление в test1 сразу после строчкиkoishi_resume;

  4. Если мы еще раз сделаемkoishi_resumeна нашей корутине мы вернемся на строчку функции cofunc1 сразу после первого вызоваkoishi_yield.

Без корутин не будет работать reindexer_tool, но не можем же мы оставить Reindexer без такой важной конечности. Будем исправлять.

Начнем с анализа ситуации. Ожидаемо, что ASM Эльбруса бустовские корутины не поддерживают (пока что), а значит нам нужно реализовать их самим. Подробности и реализацию бустовских корутин можете посмотретьздесь, а сейчас наступило время скрещивать ужа с ежом.

Есть несколько вариантов реализовать корутины:

  • Вариант 1:написать ASM реализацию. Самый очевидный, но при этом самый сложный вариант. У нас есть в планах попробовать именно этот вариант, так как ASM корутины - самые быстрые.

  • Вариант 2: забить. Нет, это не наш путь.

  • Вариант 3: использовать библиотеку.

По счастливой случайности Koishi оказалось той самой библиотекой, поддерживающей реализацию корутин с помощью встроенных E2K функций:makecontext_e2k()иfreecontext_e2k().

Koishi, Koishi, что это вообще такое?

Если коротко это библиотека, предоставляющая удобный API по использованию корутин на C/C++ с несколькими вариантами реализации:

  • ucontext

  • ucontext_e2k (наша прелесть)

  • fcontext

  • win32fiber

  • ucontext_sjlj

  • emscripten

Там, где стандартная медицина бессильна, в дело вступает генная инженерия.

Для начала внедрим Koishi в организм Reindexer:

Заменим больной орган на здоровый:

Стараемся не повредить то, что уже работает:

Одним из backend-ов Koishi для корутин выступает fcontext (те же самые boost исходники, что в Reindexer). Последуем древней мудрости работает не трогай! и оставим как есть в случае, если у нас не E2K архитектура. Для Эльбруса мы будем использоватьucontext_e2k.c

И вот он, наш мутант с корутинами полностью здоров и функционален (и на amd64, и на E2K):

День 11. Проводим финальные испытания

Две половинки нашего Франкенштейна собраны вместе, даже сторонняя библиотека прижилась и отлично себя показала. Пришло время для финальных тестов.

Всего в Reindexer около 300 функциональных тестов, и мне не терпится запустить их все.

Тесты бежали, бежали и не добежали. Один из тестов вызвал Segmentation Fault.

Всему виной оказались вот эти строчки:

struct ConnectOpts {  /* тут тоже код, но он не такой интересный */  uint16_t options = 0;  int expectedClusterID = -1;};

Обычный код, что тут такого? скажете вы. Но не все так просто. Запоминаем, что здесь два поля, которые инициализируются при объявлении.

Попробуем воспроизвести на изолированном более простом примере.

ASM, настало твое время

Внимание на скриншот:

Ошибка проявляется именно в том случае, когда отсутствуют не проинициализированные поля. Другими словами, если все ваши поля инициализируются при объявлении вы счастливчик, поймавший Segmentation Fault.

Баг заключается в том, что скомпилированное создание структуры выглядит как странныйaddd. Именно эта строчка и вызывает segfault. Кстати, если вместоbool anyField = falseнаписать простоbool anyField, то код совершенно другой и ошибки нет.

Семь бед, один ответ обновитесь!

Разгадка тайны оказалась проста. На момент работы с Reindexer последней версией компилятора LCC была v.1.25.16, однако в состав пакетов ОС Эльбрус по умолчанию входит 1.25.14, на котором я и запускал тесты. Добрые люди из сообщества подсказали нам, что уже в 15 версии данный баг был исправлен. Я решил обновиться на 16-ую и посмотреть, что будет.

Вот что нам принес новый компилятор LCC v.1.25.16:

C++ код такой же, однако ASM совсем другой, и что самое главное он работает! Последовательно (заранее прошу прощения за мой ломаный asm-русский переводчик):

  1. gestp - выделяем стек и кладем его в %dr3

  2. setwd - задаем текущее окно в регистровом файле

  3. setbn - задаем подвижную базу регистров в текущем окне регистрового файла

  4. addd - кладем "дно" стека (стек размером 0x20) в %dr2

  5. addd - выделяем на стеке нашу структуру

  6. ldb - достаем из констант наш false и кладем его в %r5

  7. stb - кладем наш false из регистра %r5 в наше поле anyField1

  8. addd - подготовили локальный указатель на структуру для вызова метода

  9. addd - передаем указатель в базовый регистр для передачи при вызове anyMethod (в anyMethod мы достаем указатель из регистра %dr0)

  10. disp - подготавливаем регистр перехода на anyMethod

  11. call - вызываем anyMethod

Дальше все просто пересобрать, перезапустить, обрадоваться.

Тесты прошли успешно, и теперь у нас есть полностью рабочий и протестированный Reindexer на Эльбрусе.

На этом все ?

На самом деле нет. Сейчас мы смогли:

  • собрать Reindexer Server

  • запустить Reindexer Server

  • собрать Reindexer Tool

  • запустить Reindexer Tool

  • переписать кусочек Reindexer Tool

  • уронить Reindexer и поднять его

  • добиться 100% проходимости Reindexer тестов

Мы научились:

  • собирать C++ софт на Эльбрус

  • переписывать C++ софт под особенности и отличия Эльбрусов

  • разбираться в ASM E2K

  • превозмогать трудности

  • разбираться в C++ корутинах даже на Эльбрусе

Что в планах:

  • корутины на ASM E2K (может быть даже сравнить fcontext ASM на i5 и ucontext/ASM на E2K)

  • оптимизировать Reindexer под архитектуру Эльбрус

  • перенести еще несколько интересных приложений на Эльбрус

  • дополнить базу библиотек и пакетов Эльбрус

  • организовать E2K инфраструктуру и песочницу

Что же можно сказать про Эльбрус со стороны простого разработчика?

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

На сегодня это всё, что хотелось бы вам рассказать, но я еще вернусь с новыми интересными подробностями про портирование и оптимизацию, и да прибудет с вами сила Эльбруса!

Подробнее..

На пути к вершине Магма и Кузнечик на Эльбрусе

17.06.2021 16:13:58 | Автор: admin

В последнее время всё чаще появляются статьи о производительности российских процессоров Эльбрус на различных задачах. Тема криптографии пока что остаётся за кадром, хотя в разное время были упоминания то о высоких возможностях Эльбруса (некий ГОСТ лучше в 9 раз на Эльбрус-4С, чем на Intel Core i7-2600), то о плохой оптимизации компилятора и, соответственно, крайне низкой скорости реализованных алгоритмов (Кузнечик в 100 раз медленнее, чем на Intel?). Предлагаю наконец разобраться, что может Эльбрус, на примере двух ГОСТ алгоритмов симметричного шифрования.

Чтобы статья не вышла слишком большой, будем считать, что читатель имеет общее представление об архитектурах процессоров, в том числе знает об Эльбрусе. Если же нет, на сайте разработчика (компании МЦСТ) есть отличное руководство по программированию и книга об архитектуре в целом. Именно с этих материалов и началось моё знакомство с Эльбрусами. Также отмечу, что в современных процессорах очень много различных механизмов и особенностей, так что в статье буду касаться только тех, которые, на мой взгляд, важны при реализации выбранных алгоритмов.

Что может предложить архитектура Эльбрус

Для выполнения арифметических операций у Эльбруса есть 6 АЛУ (арифметико-логических устройств), способных выполнять операции параллельно. Начиная с версии 5 архитектуры появилась поддержка упакованных (SIMD) инструкций над 128-битными регистрами.

Для хранения промежуточных результатов присутствует большой регистровый файл: суммарно в процедуре можно использовать более 200 (64-битных) регистров общего назначения. Для SIMD вычислений используются те же самые регистры, а не отдельные, как это часто бывает. Соответственно, с 5 версии архитектуры все регистры стали 128-битными.

Задачу симметричного шифрования можно отнести к потоковой обработке массива данных. Для таких ситуаций в Эльбрусе есть механизм асинхронной подкачки данных из памяти APB (Array Prefetch Buffer). Использование этого механизма позволяет вовремя подгружать данные из памяти, не теряя время на кэш-промахи.

Выбор реализаций

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

Правда, о производительности ГОСТ алгоритмов обычно говорят только в контексте семейства x86-64, другие архитектуры мало кого интересуют. Но это не беда: мне показалось, что при знании команд ассемблера x86-64 ознакомиться с набором целочисленных и логических инструкций Эльбруса проще, чем, скажем, с ARM-овым. То есть прослеживаются определённые параллели, особенно, в области SIMD инструкций, и даже прямые аналоги. В остальном, конечно, у них нет ничего общего.

Итак, для Магмы известна эффективная реализация режимов, допускающих параллельную обработку блоков, то есть когда несколько блоков могут шифроваться независимо друг от друга. Это, например, режимы ECB, CTR, MGM. При этом скорость конкурирует с AES, для которого на x86-64 есть аппаратная поддержка. Реализация заточена именно под параллельную обработку, в случае последовательной (режимы с зацеплением) используются другие подходы. Мне интересно добиться максимальной скорости, поэтому я ограничился только случаем параллельной обработки.

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

Тестовые машины

То же самое в текстовом виде

Процессор

Версия арх-ры

Кол-во ядер

Тактовая частота

L1d

L1i

L2

L3

Эльбрус-4С

E2Kv3

4

0.75 ГГц

4 x 64 КБ

4 x 128 КБ

4 x 2 МБ

Нет

Эльбрус-1С+

E2Kv4

1

0.985 ГГц

1 x 64 КБ

1 x 128 КБ

1 x 2 МБ

Нет

Эльбрус-8С

E2Kv4

8

1.2 ГГц

8 x 64 КБ

8 x 128 КБ

8 x 512 КБ

16 МБ

Эльбрус-8СВ

E2Kv5

8

1.55 ГГц

8 x 64 КБ

8 x 128 КБ

8 x 512 КБ

16 МБ

Эльбрус-2С3

E2Kv6

2

2 ГГц

2 x 64 КБ

2 x 128 КБ

2 x 2 МБ

Нет

Эльбрус-16С

E2Kv6

16

2 ГГц

16 x 64 КБ

16 x 128 КБ

8 x 1 МБ

32 МБ

Магма

В случае x86-64 быстрая реализация Магмы опирается на использование расширений AVX и AVX2. При этом учитывается наличие в процессоре нескольких АЛУ и возможность параллельного исполнения до 3 векторных инструкций за один такт. Естественно, планирование параллельного исполнения остаётся на откуп процессора.

В случае же Эльбруса есть возможность явно распланировать параллельное исполнение. Опуская некоторые детали, можно считать, что на 3 и 4 поколении возможно исполнить 6 целочисленных векторных операций над 64-битными регистрами, а начиная с 5 поколения 4 векторных операции уже над 128-битными регистрами.

Для Эльбруса я написал собственную реализацию Магмы. Она использует те же идеи, что и исходная под x86-64, но при этом адаптирована под другой набор инструкций. Рассматривал перспективу написания на ассемблере и даже пробовал, но довольно быстро осознал, что ассемблер у Эльбруса достаточно сложный в плане программирования на нём (например, есть много нюансов по размерам задержек и зависимостям инструкций, которые тяжело учесть вручную). При этом оптимизирующий компилятор делает свою работу действительно хорошо: переставляет инструкции в рамках большого окна и при подборе опций компиляции выдаёт плотность кода, которая не отличается от теоретических оценок на количество инструкций и тактов. Так что я остановился на реализации на языке Си с использованием intrinsic функций для доступа к некоторым инструкциям процессора.

Для измерения скорости был выбран режим ECB. Обычно именно он (или даже его упрощения) используется при сравнении производительности, а скорость других режимов можно оценить на базе полученных результатов, отличия несущественны. Речь идёт о реализации базового алгоритма шифрования, поэтому накладные расходы от смены ключа также не учитываются. Объём данных для замера порядка 1 ГБ. Естественно, шифрование на одном ядре. Для многоядерной машины можно умножить результат на количество ядер и получить близкую к реальности оценку скорости. По крайней мере, во всех сравнениях я видел именно такую зависимость. Полученные результаты в таблице ниже:

То же самое в текстовом виде

Процессор

Скорость на невыровненных данных

Скорость на выровненных данных

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

Эльбрус-4С

116 МБ/с

137 МБ/с

5.2 такт/байт

Эльбрус-1С+

151 МБ/с

179 МБ/с

5.2 такт/байт

Эльбрус-8С

185 МБ/с

220 МБ/с

5.2 такт/байт

Эльбрус-8СВ

402 МБ/с

520 МБ/с

2.8 такт/байт

Эльбрус-2С3

669 МБ/с

670 МБ/с

2.8 такт/байт

Эльбрус-16С

671 МБ/с

672 МБ/с

2.8 такт/байт

Здесь под выровненными данными подразумевается выравнивание по границе 8 байтов для E2Kv3/E2Kv4 и 16 байтов для E2Kv5/E2Kv6. При наличии такого выравнивания (на версиях до 6) работает механизм APB и данные для шифрования эффективно подкачиваются из памяти. При этом с версии 6 APB уже не требует выравнивания данных, поэтому при любом расположении данных достигается максимальная скорость. Для невыровненных данных на предыдущих версиях архитектуры я не провёл достаточно исследований, так что значения в этом столбце таблицы можно считать нижней границей.

Для сравнения приведу результаты из статьи с описанием базовой реализации на Intel Core i3-7100 @ 3.9 ГГц. При использовании AVX 458 МБ/с, 8.1 такт/байт; AVX2 1030 МБ/с, 3.6 такт/байт. Так что по абсолютной скорости Эльбрус достаточно близок к современным процессорам Intel (это при значительной разнице в тактовой частоте!) и превосходит x86-64 с AVX в тактах более чем в 1.5 раза (для 3 и 4 поколения), а x86-64 с AVX2 в 1.3 раза (для 5 поколения).

Кузнечик

По сравнению с Магмой, структура Кузнечика является более сложной. Несмотря на то, что удалось декомпозировать нелинейное преобразование S, техники реализации, основанные на широком использовании SIMD-инструкций, пока что отстают от "классической" реализации со склеенным LS (линейным и нелинейным) преобразованием и таблицей предвычислений размером 64 КБ (упоминается в статье под именами с LS или более простое описание на Хабре).

В случае x86-64 Кузнечик эффективнее всего реализуется с использованием AVX-инструкций (удобно работать со 128-битными регистрами, так как длина блока и размер значений в таблице равны в точности 128 битам). При этом для вычислений адресов в таблице не удаётся воспользоваться эффективной адресацией Scale-Index-Base-Displacement (именование из статьи), так как в качестве Scale нужно значение 16, а максимально возможное 8. На Эльбрусе можно ожидать конкурирующих результатов за счёт большого кэша L1d (64 КБ) и наличия 4 АЛУ, обеспечивающих произвольный доступ к памяти (насколько мне известно, у абсолютного большинства процессоров x86-64 2 порта для загрузки данных).

Как и в случае с Магмой, для Кузнечика я написал отдельную реализацию на Си под Эльбрус, чтобы добиться максимальных результатов. Начиная с 5 версии архитектуры я явным образом использовал тип __v2di (см. e2kintrin.h в составе компилятора), чтобы быть уверенным, что получится использовать регистры как 128-битные.

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

Итак, в случае строго последовательной обработки данных:

То же самое в текстовом виде

Процессор

Скорость на невыровненных данных

Скорость на выровненных данных

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

Эльбрус-4С

52 МБ/с

69 МБ/с

10.4 такт/байт

Эльбрус-1С+

63 МБ/с

90 МБ/с

10.4 такт/байт

Эльбрус-8С

80 МБ/с

110 МБ/с

10.4 такт/байт

Эльбрус-8СВ

95 МБ/с

150 МБ/с

9.9 такт/байт

Эльбрус-2С3

170 МБ/с

171 МБ/с

11 такт/байт

Эльбрус-16С

171 МБ/с

172 МБ/с

11 такт/байт

Для сравнения результаты из статьи (лучшие из опубликованных) на Intel Core i7-6700 @ 4 ГГц 170МБ/с, 22.4 такт/байт. В отличие от Магмы, можно говорить о сопоставимой абсолютной скорости и преимуществе в тактах более чем в 2 раза.

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

С параллельной обработкой ситуация намного интереснее:

То же самое в текстовом виде

Процессор

Скорость на невыровненных данных

Скорость на выровненных данных

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

Эльбрус-4С

78 МБ/с

83 МБ/с

8.6 такт/байт

Эльбрус-1С+

102 МБ/с

108 МБ/с

8.7 такт/байт

Эльбрус-8С

126 МБ/с

133 МБ/с

8.6 такт/байт

Эльбрус-8СВ

248 МБ/с

291 МБ/с

5.1 такт/байт

Эльбрус-2С3

453 МБ/с

454 МБ/с

4.2 такт/байт

Эльбрус-16С

454 МБ/с

455 МБ/с

4.2 такт/байт

И традиционное сравнение с Intel Core i7-6700 @ 4 ГГц: на нём достигается 360 МБ/с, 10.6 такт/байт. В отличие от случая последовательной обработки, у E2Kv3 и E2Kv4 преимущество Эльбруса не такое большое, предположительно из-за того, что реализация обработки нескольких блоков вместе обладает более высокой степенью параллельности и планировщику на x86-64 легче справиться с выявлением независимых операций. А вот появление у 5 поколения Эльбруса 128-битных регистров и загрузок из памяти позволяет ему сохранить преимущество в тактах более чем в 2 раза.

Сравнивать E2Kv6 с i7-6700 оказалось несолидно, поэтому я взял ассемблерную реализацию режима ECB и провёл собственный замер. В статье с описанием результатов на i7-6700 данные шифруются на месте, без работы с памятью, поэтому у честного режима ECB результат чуточку хуже: на самом мощном из доступных мне процессоров Intel Core i7-9700K @ 4.7 ГГц вышло 411 МБ/с, 10.9 такт/байт. Эльбрус оказался быстрее, обеспечивая преимущество в тактах в 2.5 раза.

Заключение

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

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

С другой стороны, сложившаяся похожесть ряда инструкций упрощает разработку и оптимизацию под Эльбрус. Можно сказать, что эта статья предлагает простой способ портирования и оптимизации алгоритмов под Эльбрус: достаточно взять хорошо зарекомендовавший себя на Intel/AMD алгоритм и немного адаптировать его под Эльбрус. Я искренне верю, что в результате практически любой алгоритм должен работать по крайней мере не хуже, чем в разницу тактовых частот.

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

P.S.

Эта статья написана по мотивам моего устного доклада на конференции РусКрипто. По ссылке можно найти презентацию, которая является краткой выжимкой с основными результатами на тот момент. К моменту же написания статьи удалось улучшить некоторые результаты, а также проверить реализации на новом поколении процессоров.

Несмотря на то, что для получения описанных результатов мне удалось разобраться с Эльбрусом на основании только открытой информации и документации к компилятору, я хочу выразить благодарность сотрудникам МЦСТ, в особенности, Александру Трушу, за ответы на периодически возникавшие у меня вопросы и, конечно, за предоставление удалённого доступа к новым процессорам.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru