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

Обзор и сравнительное тестирование ПЭВМ «Эльбрус 401‑PC». Часть четвёртая — бенчмарки

Время на прочтение 27 мин
Количество просмотров 74K
Заключительная часть статьи посвящена сравнению производительности нового российского компьютера с зарубежными конкурентами и собственными предшественниками.

Вид системного блока Эльбрус 401-PC спереди и сбокуРезультаты теста Pgbench (Postgresql) в упрощённом виде

Осторожно: много букв и картинок!



Напоминаем содержание предыдущих частей:

  1. обзор аппаратного обеспечения:
    • процесс приобретения;
    • аппаратное обеспечение;
  2. обзор программного обеспечения:
    • запуск операционной системы;
    • штатное программное обеспечение;
  3. обзор средств разработки:
    • особенности архитектуры;
    • машинный язык;
    • средства разработки;
  4. сравнительное тестирование производительности:

Приятного чтения!

Disclaimer


Автор долгое время находился в глубоком заблуждении, полагая, что данный компьютер приобретается фирмой для собственных нужд — в дополнение к эксплуатируемой технике более раннего поколения. И только в момент получения выяснилось, что новинка предназначена для дальнейшей поставки в составе комплекса. Поэтому, вместо запланированного изначально вдумчивого чтения документации, практического ознакомления со всеми тонкостями, тщательного подбора средств тестирования и прочей медитативной деятельности, пришлось действовать быстро, если не сказать хаотично. Градус неадекватности дополнительно повысился благодаря пред‑ и посленовогоднему авралу, в посильном устранении которого автор параллельно участвовал.

«Сделать правильное тестирование можно только одним способом. Сделать неправильное тестирование можно бесконечным числом разных способов. И сами угадайте, что чаще всего случается». (nutanix)

Достичь какого‑то «истинно правильного» результата, прицельно раскрывающего уникальные достоинства или недостатки той или иной платформы, мы перед собой не ставили. Хотелось просто получить обиходное представление о вычислительных мощностях нового «Эльбруса» на фоне ранее известных образцов отечественной и западной электроники, — с позиции рядового пользователя, использующего готовые программы в собранном виде или компилирующего их из исходных кодов без применения эзотерических знаний по оптимизации и портированию. Поэтому в статье не будет сенсаций вида «Эльбрус порвал Xeon при шифровании по алгоритму ГОСТ» или «Эльбрус в режиме эмуляции x86 работает даже быстрее, чем исполняя нативный код» (что можно тут и там прочитать в Интернете, и всегда почему‑то без раскрытия подробностей). Впрочем, истины и интриги ради, стоит заметить, что в одной серии тестов главный герой данного обзора действительно продемонстрировал в несколько раз более высокие результаты, чем аналогичный компьютер на базе Core i7.

Участники тестирования


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

Компьютер архитектуры x86‑64 на базе Intel Atom
Вид материнской платы Intel D2500CC и системного блока Chieftec IX-01B с северо-востокаВид материнской платы Intel D2500CC с юго-запада

Пожалуй, идеальным соперником для «Эльбруса» был бы какой-нибудь современный Intel Celeron или Atom с четырьмя ядрами и низкой частотой, либо аналог под маркой AMD; но из того, что имелось в закромах, нашёлся только двухъядерный Atom D2500, распаянный на материнской плате Intel D2500CC формата mini‑ITX. Конфигурация этого компактного и заведомо не слишком резвого компьютера, наверное, не нуждается в дополнительных пояснениях; у неё был только один нетипичный компонент — 3,5‑дюймовый жёсткий диск (правда, начальной серии), но, так как производительность ввода-вывода не находилась в фокусе исследования, этим фактом можно пренебречь. Для обеспечения максимальной схожести в программном плане, в качестве операционной системы был выбран дистрибутив Debian 7.9.0 для архитектуры x86‑64 с ядром Linux 3.2.0 (тем более, что установка и обновление более старых версий Debian — квест не для слабых духом).

Компьютер архитектуры x86‑64 на базе Intel Core i7
Вид системного блока Dell OptiPlex 990 спереди и сбокуВид системного блока Dell OptiPlex 990 со снятой боковинойВид системного блока Dell OptiPlex 990 сзади

Вторым естественным участником стал компьютер с противоположного полюса функций и быстродействия — настольная мини-башня Dell OptiPlex 990 с процессором Core i7‑2600 и оригинальной материнской платой на базе чипсета Q67. Система работала в своём повседневном режиме — с отключённой функцией разгона (Turbo Boost), но с включённой технологией многопоточности (Hyper-Threading), под управлением openSUSE 13.2 для архитектуры x86‑64 с ядром Linux 3.16.7.

Компьютер «Эльбрус‑90микро» на базе МЦСТ R500
Вид системного блока Эльбрус‑90микро в конструктиве «башня» спереди и сбокуВид системного блока Эльбрус‑90микро в конструктиве «башня» со снятой боковинойВид системного блока Эльбрус‑90микро в конструктиве «башня» сзади

Однако было бы некорректным проводить сравнение только с мейнстримом, так как новый «Эльбрус‑4С» — это в первую очередь замена старым представителям продуктовой линейки «Эльбрус», включающей в себя не только компьютеры архитектуры E2K, но также SPARC. К сожалению, наша фирма не располагает техникой современной архитектуры SPARC V9, такой как МЦСТ R1000, зато «имеем счастье» возиться с целым выводком R500 — из поколения SPARC V8, которое ещё 32-битное. Первым представителем старой гвардии стал компьютер «Эльбрус‑90микро» в формате обычной мини-башни с двумя распаянными процессорами R500, дискретной видеокартой собственной разработки, обычным жёстким диском и оптическим приводом. Операционной системой этого компьютера является МСВС 3.0 для архитектуры SPARC с ядром Linux 2.4.25, компилятором GCC 3.3.6 и библиотекой GNU LibC 2.2.5.

Другой компьютер архитектуры SPARC V8 на базе R500 (примерный вид, фото с сайта МЦСТ)
Примерный вид системного блока Эльбрус‑90микро в конструктиве «Евромеханика» спередиПримерный вид вычислительного модуля Эльбрус‑90микро в конструктиве «Евромеханика» сзади

Другой компьютер тоже оснащён парой процессоров R500, но выполнен в модульном конструктиве «Евромеханика 6U», имеет всего 512 Мбайт оперативной памяти и флэш-карту промышленного уровня в качестве основного накопителя (модель Meltron P7 гордо именуется «SSD», но фактическая производительность в составе данного компьютера скорее ближе к старым, медленным флэшкам). Принципиальное отличие от предыдущего участника — в том, что здесь установлена операционная система «Эльбрус» (ОС 311‑03), датированная началом 2011 года, с ядром Linux 2.6.16, компилятором LCC 1.16.12 (заявлена совместимость с GCC 3.4.6) и библиотекой GNU LibC 2.16.0. Как будет видно далее, эти программные отличия от МСВС иногда приводят к существенной разнице в быстродействии, причём чаша весов склоняется то в одну сторону, то в другую. Поэтому ниже приведены обе серии результатов, обозначенные соответственно «R500/E» для компьютера с системой «Эльбрус» и «R500/M» для компьютера с системой МСВС.

CoreMark


Как уже вкратце упоминалось, в состав программного обеспечения входит довольно обширная коллекция тестовых утилит для проверки корректности функционирования аппаратуры и системных библиотек, а также для измерения производительности. Часть этих утилит является собственной разработкой фирмы МЦСТ, часть — известные программы сторонних авторов. Среди последних также встречаются версии, адаптированные специально для «Эльбруса»: например, CoreMark требует для каждой платформы реализовать свой интерфейс, учитывающий особенности компилятора и библиотек, системных вызовов и структур данных, многопоточности, средств измерения времени. Никаких скрытых преимуществ это портирование не даёт, впрочем, тем более что результаты основного прогона затем перепроверяются с использованием профилировщика.

Тест CoreMark создан Консорциумом по измерению производительности встраиваемых микропроцессоров (EEMBC) и состоит из нескольких синтетических задач, включающих обработку матриц и связанных списков, переключение состояний конечного автомата, вычисление контрольной суммы. Видимо, по той причине, что для скачивания исходных кодов и публикации полученных результатов требуется регистрация, этот тест не снискал большой популярности: всего в базе на данный момент 406 записей.

Диаграмма результатов теста CoreMark

Режим i7‑2600 D2500 E2S-800 R500/E R500/M
одно ядро 15'218 3'595 2'260 602 434
все ядра 88'570 7'108 8'850 1'214 850


Результат, достигнутый процессором «Эльбрус‑4С» в однопоточном режиме, находится чуть выше старого AMD Athlon XP‑M с той же тактовой частотой, а при задействовании всех четырёх ядер — близок к двухъядерным Athlon 64 X2 QL‑65, Intel Atom 330, D525, D2500, Core 2 Duo E4300, у которых частота минимум вдвое выше.

Странное поведение продемонстрировал R500 с операционной системой  «Эльбрус»: при использовании двух потоков или двух процессов, оба они делили одно ядро поровну, и только третий и последующие потоки или процессы распределялись и на второе ядро тоже, а насыщение происходило только при степени параллелизма, равной 8. Поэтому на диаграмме пунктиром также нанесены дополнительные результаты при количестве потоков, превышающих количество ядер того или иного компьютера: как можно видеть, у всех прочих участников тестирования эти пунктиры складываются в горизонтальную линию — так и должно быть, когда каждый поток поглощает все доступные ему ресурсы. Причины аномалии выяснить не удалось: возможно, таковы особенности настройки планировщика задач в системе «Эльбрус» на том компьютере.

7‑Zip


Идея включить в программу испытаний встроенный тест архиватора созрела после прочтения обзора на CNews 2014 года, где так же сравнивалась производительность Core i7‑2600 (без Hyper-Threading, но с Turbo Boost, видимо) и «Эльбрус‑4С», правда, на частоте 700 МГц, а также «Эльбрус‑2С+», у которого всего два ядра и частота 500 МГц, зато есть ещё четыре ядра сигнальной обработки ElCore9 DSP фирмы «Элвис» (впрочем, они никак не были задействованы в том тестировании). Судя по приведённым там значениям, автор запускал «7z b» и делил результат на количество ядер. Мы публикуем результаты в первозданном виде, причём на диаграмме в качестве меры быстродействия выбрано оценочное количество целочисленных операций на всех ядрах за единицу времени (MIPS), а в таблице указана абсолютная скорость обработки данных и относительный рейтинг одного ядра, учитывающий фактическую загруженность процессора в том или ином режиме работы.

Диаграмма результатов теста 7-Zip Benchmark

Показатель i7‑2600 D2500 E2S-800 R500/E R500/M
сжатие, Мбайт/с 17'200 1'300 2'144 228 247
распаковка, Мбайт/с 211'282 24'738 38'894 3'227 2'430
рейтинг, MIPS 18'781 1'823 2'920 269 241
рейтинг ядра 2'662 1'000 843 263 243


Здесь мы можем наблюдать, как новый «Эльбрус» почти не отстаёт от Atom даже в однопоточном режиме, а суммарная производительность всех ядер превосходит показатели оного уже существенно — в полтора раза.

Нежелание масштабироваться при двух потоках на этот раз показали оба компьютера на базе R500. Более того, 7‑Zip в системе МСВС почему‑то не мог определить степень загруженности ядер при распаковке, — пришлось принять её равной 99 % по аналогии со сжатием и вычислять рейтинг вручную.

OpenSSL


Аналогично предыдущему тесту, решение погонять OpenSSL естественным образом пришло после неоднократного столкновения с тезисами типа «Отечественные процессоры очень эффективны в криптографии, особенно на алгоритмах ГОСТ» (какие реализации алгоритмов при этом используются, увы, не уточняется). Поиски файлов, содержащих слово «gost» в своём имени, увенчались довольно скромным результатом:

/usr/include/nettle/gosthash94.h
/usr/include/php/ext/hash/php_hash_gost.h

Поставляемый вместе с системой самый обычный OpenSSL 0.9.8zc также не мог ничем похвастаться. Поэтому для тестов были выбраны более популярные алгоритмы хеширования, симметричного шифрования и вычисления цифровой подписи.

Диаграмма результатов теста OpenSSL Speed для алгоритма хэширования MD5 в однопоточном режимеДиаграмма результатов теста OpenSSL Speed для алгоритма хэширования MD5 в многопоточном режиме

Диаграмма результатов теста OpenSSL Speed для алгоритма хэширования SHA-1 в однопоточном режимеДиаграмма результатов теста OpenSSL Speed для алгоритма хэширования SHA-1 в многопоточном режиме

Диаграмма результатов теста OpenSSL Speed для алгоритма хэширования SHA-512 в однопоточном режимеДиаграмма результатов теста OpenSSL Speed для алгоритма хэширования SHA-512 в многопоточном режиме

Алгоритм i7‑2600 D2500 E2S-800 R500/E R500/M
MD5 615 / 3546 320 / 635 125 / 500 10 / 19 30 / 59
SHA-1 534 / 2181 192 / 381 165 / 658 6,3 / 13 17 / 34
SHA-512 301 / 1227 119 / 237 89 / 355 0,7 / 1,4

Здесь и ниже приведены максимальные показатели, выраженные в «десятичных» мегабайтах в секунду. Через дробь указаны результаты при задействовании одного ядра и всех ядер. Прочерк означает, что данный алгоритм не поддерживается в штатной версии OpenSSL: у старой системы «Эльбрус» это 0.9.8b, у МСВС — 0.9.7b (да, мы не уязвимы к Heartbleed!).

Диаграмма результатов теста OpenSSL Speed для алгоритма симметричного ширования RC4 с ключом 128 бит в однопоточном режимеДиаграмма результатов теста OpenSSL Speed для алгоритма симметричного ширования RC4 с ключом 128 бит в многопоточном режиме

Диаграмма результатов теста OpenSSL Speed для алгоритма симметричного ширования AES в режимах CBC и IGE с ключом 256 бит в однопоточном режимеДиаграмма результатов теста OpenSSL Speed для алгоритма симметричного ширования AES в режимах CBC и IGE с ключом 256 бит в многопоточном режиме

Алгоритм i7‑2600 D2500 E2S-800 R500/E R500/M
RC4 797 / 4060 202 / 401 61 / 246 5,8 / 12 12 / 24
AES-CBC 81 / 351 43 / 79 32 / 128 2,1 / 4,1 5,1 / 10
AES-IGE 78 / 341 20 / 40 43 / 170

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

Алгоритм i7‑2600 D2500 E2S-800 R500/E R500/M
RSA-4096, подпись 105 / 477 11 / 22 6,6 / 27 0,8 / 1,7 0,8 / 1,5
RSA-4096, проверка 6496 / 30'176 700 / 1400 453 / 1790 56 / 126 49 / 98
DSA-2048, подпись 2396 / 11'200 267 / 534 157 / 634 20 / 40 18 / 37
DSA-2048, проверка 2052 / 9531 220 / 440 136 / 534 17 / 34 15 / 29
ECDSA-p384, подпись 4896 / 22'480 782 / 1560 273 / 1085 55 / 108
ECDSA-p384, проверка 1135 / 4994 157 / 312 49 / 198 10 / 21
ECDH-p384, обмен 1367 / 6014 187 / 374 58 / 233 12 / 25

Суммарная производительность «Эльбрус‑4С» в этих тестах тоже находится на уровне Atom D2500, демонстрируя то преимущество, то отставание от алгоритма к алгоритму. Результаты R500 с операционной системой «Эльбрус» приведены для 4-х потоков, — именно в таком режиме он выходил на максимум, при этом всё равно сильно проигрывая своему же собрату под управлением МСВС на хешировании и шифровании, но слегка реабилитируясь на задачах асимметричной криптографии.

UnixBench


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

Тест i7‑2600 D2500 E2S-800 R500/E R500/M
Dhrystone 2 3240 / 13'735 595 / 1190 185 / 738 67 / 132 59 / 118
Whetstone 820 / 5344 171 / 382 126 / 505 27 / 52 23 / 46
Execl 886 / 5630 257 / 524 82 / 314 47 / 85 88 / 136
File, 1024/2000 3040 / 2994 451 / 683 287 / 373 44 / 47 37 / 32
File, 256/500 1983 / 1890 307 / 479 185 / 232 34 / 34 30 / 23
File, 4096/8000 4273 / 5664 807 / 1112 618 / 904 55 / 57 38 / 42
Pipe 1747 / 8922 419 / 851 209 / 824 59 / 115 107 / 181
Context 585 / 4865 214 / 428 175 / 688 51 / 99 62 / 116
Fork 1260 / 4537 264 / 570 63 / 222 78 / 85 83 / 120
Shell, 1 1968 / 6990 458 / 703 210 / 551 45 / 65 123 / 183
Shell, 8 5465 / 7113 670 / 684 490 / 562 68 / 68 166 / 166
SysCall 2978 / 6584 781 / 1183 333 / 1082 79 / 152 133 / 223
итого 1920 / 5550 403 / 682 203 / 519 52 / 76 66 / 92

Следует заметить, что в комплекте программного обеспечения «Эльбрус 401‑PC» имелась версия UnixBench 5.1.2, но для единообразия везде использовалась актуальная версия 5.1.3, тем более что штатный вариант демонстрировал те же показатели (в рамках погрешности измерения).

Pgbench (Postgresql)


Трудно было пройти мимо статьи об ускорении Postgresql на IBM Power8, где описывался процесс оптимизации программного кода для этой архитектуры в частности и была дана положительная оценка развития проекта в целом, не заразившись желанием проверить, насколько далека более скромная техника от приведённых там фантастически высоких показателей производительности. Другое дело, что выбранные для тестирования персональные компьютеры не претендуют на роль серьёзного сервера баз данных не только потому, что имеют гораздо меньше процессорных ядер и потоков исполнения, но и меньше кэша, оперативной памяти, «никакую» дисковую систему. Однако объём тестовой базы (менее 0,5 Гбайт) вполне укладывается в рамки личного хранилища данных, уместного на личном компьютере и, более того, полностью умещается в оперативной памяти большинства выбранных машин. Поэтому данный тест можно считать комплексным мерилом быстродействия всего компьютера в целом, которое, в отличие от UnixBench, имеет реалистичный, хотя и однобокий, характер нагрузки.

Операционная система компьютера «Эльбрус 401‑PC» имеет в своём составе Postgresql 9.2.3, и данную версию решено было сделать точкой отсчёта для всех остальных участников, не забыв при этом о более актуальных версиях. Скопировав репозиторий разработчиков по состоянию на 3 декабря 2015 года, мы попытались самостоятельно собрать текущую версию, далее обозначаемую «9.6devel», но ещё на этапе конфигурирования выяснилось, что для каждой архитектуры требуется платформенно-зависимая реализация спинлоков (о том, что это такое, и чем отличается от остальных видов блокировок, используемых Postgresql, рассказывается в упомянутой выше статье), и для E2K в мейнлайне её нет, конечно же. В качестве запасного варианта можно использовать режим «‑‑disable-spinlocks», однако, как и предупреждает документация, ценой ощутимого — хотя и не катастрофического — падения производительности. Причём, если самостоятельно собранная версия 9.6devel оказалась медленнее штатной 9.2.3, то собранная затем также из публичных исходных текстов версия 9.2.3 оказалась ещё медленнее, чем 9.6devel. А повторный запуск штатной версии 9.2.3 после окончания всех прочих тестов подтвердил, что падение производительности нельзя объяснить одними только особенностями SSD-накопителя (хотя и без них тоже не обошлось в комбинированном тесте на чтение и запись). Отсюда напрашивается вывод, что программисты МЦСТ внесли в штатную версию необходимые поправки, то есть выполнили полноценное портирование, и потому мы будем обозначать эту версию суффиксом «e2k», а самосборный вариант без спинлоков — суффиксом «ds».

Напротив, никаких проблем при сборке версии 9.2.3 из публичных исходных текстов не возникло на платформе SPARC, так как она поддерживается официально. Однако попытка закрепить успех с версией 9.6devel потерпела неудачу на этапе компиляции, так как memory barriers (механизм обеспечения строгого порядка операций с памятью на процессорах с внеочередным исполнением инструкций) теперь поддерживаются только на SPARC V9. Та же ошибка возникала при сборке версии 9.4.5 (основной стабильной ветки на тот момент), хотя в документации и поныне заявлена поддержка старой архитектуры.
Методика тестирования была максимально прямолинейной: СУБД запускалась с настройками по умолчанию сразу после инициализации хранилища, там создавалась тестовая база данных, которая заполнялась утилитой Pgbench в расчёте на 32 параллельных потока, и затем проводилась серия запусков Pgbench по 60 секунд каждый с меняющимся количеством имитируемых клиентов, каждый из которых работал в своём потоке (так результаты получались выше, чем когда несколько клиентов делило один поток). Количество запросов, переданных в рамках каждого сеанса, оставалось по умолчанию (10 запросов на одно соединение), а поскольку клиенты функционировали на той же машине, что и сервер, затраты времени на установление соединений не учитывались.

Основной нагрузочный сценарий Pgbench подражает набору тестов TPC‑B, разработанному Советом по производительности обработки данных ещё в 90‑х годах, и состоит из различных запросов на выборку и изменение данных. Очевидно, что узким местом в данном случае становится дисковая подсистема, что для нас не показательно. Поэтому мы также провели тесты только на чтение (SELECT-only), — как уже говорилось, вся база данных при этом целиком умещается в оперативной памяти; к тому же, именно этот сценарий использовался авторами патчей для Power8 и их предшественниками из стана x86‑64 при демонстрации своих улучшений.

Диаграмма результатов теста Pgbench по сценарию TPC-BДиаграмма результатов теста Pgbench по сценарию SELECT-only

Сценарий i7‑2600 D2500 E2S-800 R500/E R500/M
TPC-B 307 / 542 248 / 285 991 / 991 16 / 16 87 / 87
SELECT 82'304 / 83'280 4076 / 4076 8732 / 8732 650 / 650 766 / 766

Таблица результатов содержит максимально достигнутые показатели, выраженные в количестве обработанных запросов в секунду: через дробь указаны значения, полученные с помощью версии 9.2.3 и во всех протестированных версиях вообще. Этот максимум обычно соответствует количеству параллельно обслуживаемых клиентов, равному числу ядер процессора, когда дело ограничивается только чтением данных; когда также производится запись данных на диск, то максимум достигается при большем параллелизме, видимо, за счёт переупорядочения команд диском (или системным кэшем, если тест такое позволяет).

Соотношение результатов первых трёх участников — вполне ожидаемое: «Эльбрус 401‑PC» опередил всех в смешанном режиме благодаря своему шустрому SSD, и это лишний раз напомнило о том, что центральный процессор не является единственно важным для отзывчивости компьютера. Картина при выборке данных совсем иная, но и тут нельзя не заметить, что процессор «Эльбрус‑4С» выступает на равных с Atom D2500 даже при количестве потоков в рамках числа ядер последнего, — несмотря на более чем двойное преимущество оного по частоте; видимо, играет свою роль разница в объёме кэш-памяти второго уровня (8 Мбайт против 1 Мбайт). Не вчера придуманная формула успеха «Много памяти и быстрый накопитель» не теряет своей актуальности!

Отдельного пояснения требуют обрывочные результаты компьютера на базе R500 с операционной системой «Эльбрус». То ли по причине нехватки оперативной памяти, то ли в силу иных обстоятельств, утилита Pgbench просто переставала подавать признаки жизни после прогона в 2-поточном режиме на запись или 3-поточном на чтение. Причём ситуация не исправлялась даже при понижении объёма тестовой базы (за счёт уменьшения параметра scaling factor; результат обозначен пунктиром на диаграмме) и, соответственно, появлении достаточного количества свободной памяти. Что характерно, однако, стек вызовов «уснувшей» программы выглядел следующим образом:

#0  0x00.... in __lll_lock_wait_private () from /lib/libc.so.6
#1  0x00.... in __lll_lock () from /lib/libc.so.6
#2  0x00.... in free () from /lib/libc.so.6
#3  0x00.... in doCustom ()
#4  0x00.... in main ()

Ох уж эти блокировки!

Что же до плачевных показателей в тестах этого компьютера на запись, то ожидать от флэш-карты высокой производительности было бы наивно.

Комментируя результаты в целом, можно отметить, что такой революционной разницы в производительности между протестированными версиями Postgresql, какая была показана в упомянутой ранее статье, в нашем эксперименте заметить не удалось: не считая самостоятельно собранной в неоптимальном виде версии для E2K, расхождения были в рамках погрешности измерения, — в том числе при смешанной нагрузке, когда скорость работы жёсткого диска была статистически плохо предсказуемой при выбранной длительности проведения теста.

Также в планах было протестировать родную для МСВС, хотя и не входящую в штатный набор программного обеспечения, СУБД «Линтер ВС» (не путать с «Линтер»), версия 707.3.4 которой основана на Postgresql 8.4.3 с оригинальными расширениями для поддержки мандатного управления доступом. Однако опциональная утилита Pgbench в комплект поставки этого продукта не входит, а самостоятельно собранный вариант из публичных исходных кодов оказался несовместимым с используемой моделью прав и привилегий.

LCC, GCC


Сборка Postgresql оказалась неплохим бенчмарком сама по себе: это не слишком мелкий проект, чтобы настройка и компиляция промелькнули на экране в мгновение ока, и в то же время не слишком большой, чтобы процесс растянулся надолго или завершился с ошибкой из‑за отсутствующих зависимостей либо платформенной несовместимости. Единственный недостаток с точки зрения всестороннего тестирования состоит в том, что Postgresql написан целиком на языке Си — нет ни одного модуля на C++.

Измерению подвергалось полное время компиляции версии 9.2.3 в многопоточном режиме с различными уровнями оптимизации: приведённые в таблице результаты выражены в часах, минутах и секундах по астрономическому времени, а также в скобках указаны суммарные затраты процессорного времени пользователя во всех потоках (системные затраты сравнительно малы и связаны, скорее всего, с файловым вводом-выводом, который нам не очень интересен в данном контексте). Время на конфигурирование сборки не учитывалось: хотя оно может быть существенным и даже сопоставимым с длительностью компиляции, всё же конфигурирование обычно выполняется однократно на том или ином этапе работы над проектом, тогда как компилятор вызывается часто при внесении правок. Кроме того, следует иметь в виду, что при сборке стабильной версии с настройками по умолчанию не выполняется компилирование опциональных утилит, таких как Pgbench, — в отличие от сборки текущей версии из репозитория.

Режим i7‑2600 D2500 E2S-800 R500/E R500/M
-O0 0:00:17 (0:01:15) 0:03:00 (0:05:08) 0:02:00 (0:06:17) 0:25:51 (0:42:09) 0:14:18 (0:23:53)
-O1 0:00:24 (0:02:12) 0:04:31 (0:07:56) 0:05:25 (0:15:18) 1:33:35 (2:02:02) 0:19:14 (0:33:10)
-O2 0:00:32 (0:03:01) 0:06:02 (0:10:47) 0:13:12 (0:34:50) 1:38:30 (2:46:51) 0:27:31 (0:46:57)
-O3 0:00:38 (0:03:37) 0:07:02 (0:12:41) 0:33:04 (1:22:04) 2:17:38 (4:05:42) 0:30:20 (0:51:40)

Данные результаты демонстрируют только то, как быстро будет выполнена компиляция конкретной версии конкретного проекта с настройками по умолчанию — конкретной версией штатного компилятора на той или иной платформе. Представители архитектуры x86‑64 использовали компилятор GCC 4.8.3 и 4.7.2 соответственно, компьютер под управлением МСВС использовал GCC 3.3.6 для архитектуры SPARC, а участники с операционной системой «Эльбрус» имели в распоряжении LCC 1.16.12 и 1.19.18 соответственно, причём оптимизирующий компилятор LCC для архитектуры SPARC и для архитектуры E2K — это два совершенно разных компилятора, которые проделывают разный объём работы и выдают разный по эффективности код. Поэтому прямое сравнение тут невозможно, и никаких выводов о быстродействии аппаратуры на основании результатов данного теста делать нельзя. Другое дело, что хорошо было бы исследовать эффективность оптимизаций, но для этого нужна недюжинная квалификация, — чтобы не получилось, что мы измеряем скорость инкремента и делаем на основании этого космического масштаба выводы.

Java Micro Benchmark


Имея весьма смутное представление о Java, автор решил просто пробовать все результаты гуглинга по порядку, и первым делом остановил взгляд на этом проекте, который оказался довольно компактным и простым в запуске. В нём реализованы базовые оценки быстродействия процессора и жёсткого диска, которые также комбинируются в сценариях «Desktop» и «Server»: первый создаёт нагрузку в большей степени последовательно, а второй старается взяться за много задач одновременно.

Сценарий i7‑2600 D2500 E2S-800
CPU, млн. 3927 196 356
Disk 2546 164 126
Desktop 3238 181 241
Server 7568 378 405

Если не обращать внимание на оценку дисковой производительности, результаты кажутся правдоподобными, — приблизительное соотношение 10:1 между Core i7 и «Эльбрус‑4С», наблюдаемое в других тестах (с нативными приложениями), здесь также просматривается, а большее различие в сценарии «Server» можно было бы объяснить особенностями нагрузки или объективными свойствами испытуемых платформ. Однако такое же соотношение скорости файловых операций, — при том, что компьютер «Эльбрус 401‑PC» оснащён быстрым SSD, а в остальных компьютерах установлены обычные диски начального уровня, — заставляет усомниться в адекватности самого теста или формулы вычисления рейтинга. И действительно, заглянув в подробный журнал сценария «Disk», можно видеть, что скорость чтения жёсткого диска Seagate Barracuda 7200.9 якобы составляет 325 Мбайт/с в каждом из двух потоков на Atom D2500, а скорость чтения WD Caviar Blue — вообще, страшно сказать, — 1650 Мбайт/с в каждом из восьми потоков на Core i7. Такие показатели превышают скорость интерфейса SATA‑2, по которому подключены диски, а потому не могут отражать даже скорость обращения к буферу диска, — ну разве что к системному кэшу.

Дальнейшие тесты покажут, что и оценка производительности процессора в Java Micro Benchmark, видимо, реализована некорректно. Этот случай в очередной раз напоминает нам, что писать правильные бенчмарки не так‑то просто, и слепо верить первому встречному, не сверяясь с другими источниками, будет ошибкой.

SPECjvm


Корпорация стандартизованной оценки производительности (SPEC), — разработчик ставших эталонными тестов SPEC CPU и многих других, — в представлении, пожалуй, не нуждается, и профессионализм её программистов сомнению не подлежит. Обычно их продукты стоят больших денег, но для SPECjvm98 и SPECjvm2008 они сделали исключение и распространяют совершенно бесплатно, — грех было не воспользоваться.

Тест i7‑2600 D2500 E2S-800
compiler 533,11 34,24 4,54
compress 292,94 21,48 2,74
crypto 269,87 19,14 3,10
derby 427,77 24,85 5,00
mpegaudio 184,79 12,48 2,29
scimark.large 45,88 5,46 1,13
scimark.small 414,42 20,43 4,02
serial 207,05 13,86 1,45
startup 32,31 5,19 0,69
sunflow 110,51 6,85 0,89
xml 621,66 36,76 5,25
итого 206,50 15,03 2,30

Теперь соотношение между Core i7 и «Эльбрус‑4С» — порядка 100:1, причём во всех тестах единогласно, без исключения. Да что уж, 4‑ядерный «Эльбрус» здесь безнадёжно отстал даже от 2‑ядерного Atom! Учитывая предыдущий неудачный опыт Java-бенчмаркинга, в этот результат было сложно поверить: вроде нагрузка идёт только на процессор и память, а картина столь разительно отличается от нативных программ.

Гипотеза о том, что Core i7 получает преимущество за счёт использования более новой версии Java — 1.7.0, тогда как «Эльбрус» имеет в своём распоряжении только 1.6.0, — была опровергнута тестированием той же версии 1.6.0 на Atom; правда, JVM в последнем случае была версии 23.25 против 20.0 (автор не в курсе, насколько это существенно). Также было проверено предположение, что слишком большой объём выделенной памяти для Java — так же плохо, как и слишком малый: в точном соответствии с документацией, было выделено по 512 Мбайт на ядро, но результат лишь осциллировал в рамках погрешности по сравнению с тем, когда выделялось вдвое больше, и когда вчетверо.

Повторимся, сомневаться в квалификации разработчиков теста не приходится: как минимум, они знают, что «Java настолько серьёзна, что её надо прогревать перед запуском», — эта подготовка длится по 2 минуты на каждый тест, чего не было ни в одном другом рассмотренном Java-бенчмарке. Такое впечатление, что прогрев не даёт никакого эффекта, и виртуальная машина продолжает интерпретировать псевдокод, вместо того чтобы транслировать его в машинные команды.

Хотя, если честно, поначалу некоторое недоверие всё же возникло, когда выяснилось, что тест не совместим с более новыми версиями Java, такими как 1.8.0, и что диаграммы результатов тестирования сохраняются в формате JPEG. Но дальнейшее исследование показало, что производительность Java, видимо, действительно такая, какая есть.

Дополнение от 05.02.2016. Чтобы окончательно подтвердить или опровергнуть гипотезу об отсутствии двоичной трансляции на «Эльбрусе», по советам в комментариях мы попробовали принудительно запретить её использование на компьютере с Core i7, передавая виртуальной машине дополнительный параметр «-Djava.compiler=NONE». Увы, это сделало невозможной работу самого бенчмарка SPECjvm, потому что серия тестов «compiler» является его неотъемлемой составляющей. Процесс просто замирает на первых же (проверочных) прогонах: нагрузка на центральный процессор падает до нуля, и за 12 часов так ничего и не происходит, в то время как в обычном режиме целиком на всё тестирование тратится 2 часа.

SciMark


Этот тест используется как составная часть SPECjvm2008, но известен и сам по себе. На сайте авторов предлагается запустить SciMark 2.0 прямо в браузере как апплет, но даётся предупреждение, что этот способ может быть сопряжён с некоторым падением производительности. Поэтому, а также потому, что Firefox в системе «Эльбрус» не имеет соответствующего плагина, мы выбрали консольную версию теста.

Размер задачи i7‑2600 D2500 E2S-800
default, итого 1715,45 / 76,60 206,06 17,92
FFT (1K) 996,14 / 23,80 123,85 16,89
SOR (100) 1435,35 / 153,27 375,48 32,87
Monte Carlo 745,65 / 15.92 97,12 4,24
Sparse matmult (1000, 5000) 1579,66 / 85,78 206,61 15,15
LU (100) 3820,45 / 104,22 227,25 20,44
large, итого 1562,90 / 78,49 176,90 14,65
FFT (1M) 171,20 / 21,69 26,68 9,11
SOR (1000) 1314,13 / 151,12 365,33 28,46
Monte Carlo 745,40 / 16,03 95,94 4,25
Sparse matmult (100k, 1M) 1329,01 / 90,91 180,85 13,26
LU (1000) 4254,75 / 112,73 215,68 18,20

Как видим, принципиальная разница на два порядка проявляется и в этом тесте. Но ещё следует учитывать, что данный тест самостоятельно выполняется только в однопоточном режиме, — в отличие от работы в составе SPECjvm. Кроме того, длительность выполнения теста гораздо меньше, и это позволило поэкспериментировать с параметрами JVM: запускать с явным указанием режима client или server, задавать стартовый и максимальный объём выделяемой памяти, — на результат всё это никак не влияло.

Дополнение от 05.02.2016. Для Core i7 после дроби также указаны результаты, полученные при отключённой трансляции. Нетрудно видеть, что соотношение сил при этом меняется до привычных 4:1 – 6:1. Значит, причина низкой производительности Java на платформе «Эльбрус» действительно кроется в том, что байт-код всегда интерпретируется виртуальной машиной, а не переводится в машинные команды процессора по мере необходимости.

JavaLinpack


Вообще‑то именно данный тест был опробован первым, — благодаря знакомому слову «Linpack» в названии. Однако найденная версия оказалась датирована 1997 годом, не умела распределять нагрузку по ядрам процессора и имела захардкоженные значения параметров, актуальные на тот «доисторический» период, в результате чего длительность выполнения исчислялась долями секунды максимум. Поэтому данная программа показалась бесполезной и не стоящей даже упоминания. Но противоречивые результаты других тестов заставили пересмотреть вердикт и принять к сведению хотя бы и такое свидетельство. Чтобы хоть как‑то увеличить статистическую значимость, мы просто усреднили показания 100 запусков (на самом деле, серьёзные колебания были только на Core i7 — похоже, гранулярность измерения времени оказалась недостаточной, чтобы чётко фиксировать столь малые интервалы).

Показатель i7‑2600 D2500 E2S-800
MFLOPS 236,33 / 70,44 14,69 2,25

Эти результаты окончательно убедили нас, что Java в том виде, к каком она сейчас есть на «Эльбрусе», годится разве что для написания пользовательского интерфейса или иных вещей, минимально завязанных на быстродействие компьютера: например, графический интерфейс инсталлятора SPECjvm вёл себя вполне отзывчиво.

Дополнение от 05.02.2016. Для Core i7 после дроби также указан результат, полученный при форсированной интерпретации. Соотношение при этом всё ещё очень большое (30:1), но не стоит забывать, что данный тест нельзя считать точным из-за несерьёзно малой длительности.

SunSpider, JetStream, Peacekeeper


После бенчмаркинга Java, следующим логичным шагом виделось тестирование производительности JavaScript, тем более что эта технология куда как чаще встречается в жизни типового пользователя, если только ему окончательно не заблокировали доступ почти ко всем веб-сайтам в Интернете. Однако тут нас постигла неудача. При запуске на «Эльбрусе», тест SunSpider сразу же после окончания разогрева выдавал таблицу результатов, где напротив каждого сценария значилось, что он аварийно завершился. Его рекомендуемый правопреемник — JetStream — зацикливался в середине первого из трёх прогонов. Тест Peacekeeper, разработанный в Futuremark, так же по сути переставал чем‑либо заниматься, когда дело доходило до параллельной обработки фотографий. Поэтому мы публикуем частичные результаты JetStream, чтобы составить хоть какое‑то представление об уровне быстродействия скриптов в браузере.

Тест i7‑2600 D2500 E2S-800
Latency 80,45 12,80
3d-cube 45,73 7,08 0,74
3d-raytrace 64,40 7,11 1,17
base64 50,22 12,11 0,83
cdjs 60,29 12,70 н/д
code-first-load 78,59 13,87 5,55
code-multi-load 77,03 12,96 4,73
crypto-aes 66,67 11,97 1,20
crypto-md5 72,29 11,58 0,71
crypto-sha1 63,78 10,04 0,50
date-format-tofte 100,60 15,61 1,84
date-format-xparb 70,15 9,90 1,79
mandreel-latency 145,80 10,16
n-body 107,80 14,77 0,33
regex-dna 108,30 27,95 0,50
splay-latency 294,30 54,03 3,57
tagcloud 77,28 11,09 1,63
typescript 59,16 9,25 1,86
Throughput 244,16 36,68
bigfib.cpp 246,60 48,82 зависание
mandreel 219,40 23,81 NaN
splay 195,20 31,15 0,70
Geometric Mean 150,47 23,18

Сравнивая результаты разных участников, следует помнить, что, хотя сам Firefox — приложение многопоточное, выполнение скриптов с одной страницы происходит в одном потоке. Кроме того, «Эльбрус» тестировался со штатным Firefox 3.6.28, тогда как остальные компьютеры имели браузер современной версии (38.5.0 и 42.0.0) с оптимизированным движком JavaScript. Впрочем, несправедливым такой поединок назвать нельзя, так как заполучить более актуальную версию браузера на платформе «Эльбрус» вряд ли удастся, — разве что собрать её самостоятельно, но это задача явно не для рядового пользователя, учитывая размер проекта и сложную цепочку его зависимостей.

Mplayer


Мультимедийного проигрывателя в операционной системе «Эльбрус» не то чтобы совсем нет — он есть, но только с интерфейсом командной строки, и потому в меню графического окружения не упоминается. Версия mplayer 1.1 оказалась способна в чисто программном режиме, без помощи со стороны аппаратного ускорителя видеокарты, воспроизводить динамичный материал качества Full HD, закодированный в формате MPEG‑4.10 (AVC). Правда, для этого потребовалось при запуске проигрывателя указывать параметр -lavdopts threads=4, чтобы декодирование задействовало все ядра. Двух потоков оказывалось недостаточно: временами видео «подтормаживало». В однопоточном режиме это уже начинало походить на замедленную съёмку, — mplayer почти сразу выдавал предупреждение, что система слабовата и не справляется. А вот чтобы воспроизводить видео обычной чёткости (SD), мощность одного ядра оказывается более чем достаточной: загруженность обычно находится в районе 10 %.

Изначально мы планировали количественно проиллюстрировать вышеописанное поведение итоговой статистикой mplayer с опцией -benchmark, однако выводимые значения показались, мягко говоря, странными. Например, в однопоточном режиме «Эльбрус‑4С» тратит на декодирование видеодорожки Full HD почти 98 % ядра; остальные крохи уходят на декодирование звука и вывода всего этого на экран и в аудиокарту. Когда используется 2 потока, mplayer докладывает о суммарных затратах в 85 %, а когда 4 потока, — то 15 %. Даже если эти показатели надо умножить на количество потоков, всё равно что‑то тут явно не сходится. Поэтому придётся ограничиться словесными впечатлениями: воспроизведение HD-видео — не проблема для нового «Эльбруса». И это действительно большой прогресс на фоне R500, который в связке с адаптером МГА в наших прошлых экспериментах едва тянул 352×288 MJPEG со скоростью 8–9 кадров в секунду.

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

FIO, DD


Смысла измерять производительность дискового ввода-вывода, как уже говорилось, мы не видели. Во‑первых, потому что накопители серии Kingston SSDNow mS200 ещё не тестировал только ленивый. Во‑вторых, потому что сделать это правильно — не так‑то просто, и результат всё равно получится неоднозначным. А то, что у нового «Эльбруса» нет каких‑то совсем уж фатальных проблем с дисковым контроллером, и так было ясно. Просто чтобы убедиться в этом, мы запустили утилиту fio 2.3 на чтение с большим размером блока (16 Мбайт оказалось достаточно для насыщения) и получили пик на уровне 185 Мбайт/с. Для теста записи хорошо сжимаемых данных воспользовались простым

dd if=/dev/zero of=myfile oflag=direct bs=16M count=64

и получили результат 63 Мбайт/с. Скорость записи несжимаемых данных (видео) по такой же методике составила 34 Мбайт/с. Да, это много меньше, чем упоминается в сторонних исследованиях данной модели накопителя, но для повседневных задач, выполняемых на данном компьютере, наверняка будет достаточно. Каковы причины подобного поведения — другой вопрос, так как объяснить всё одними лишь ограничениями интерфейса SATA‑2 не получается, и загрузка процессора при этом не поднимается выше 10–15 %.

iPerf


Однозначно оценить производительность сетевой подсистемы тоже вряд ли возможно, и мы снова довольствовались простым измерением максимальной пропускной способности — с помощью iPerf 3.1.1. Партнёром в этом деле для «Эльбрус 401‑PC» стал вышеописанный компьютер на базе Core i7 со встроенным сетевым контроллером Intel 82579LM, работающий под управлением openSUSE 13.2; компьютеры были соединены кабелем напрямую. Настройки iPerf для TCP оставались по умолчанию, а для UDP использовался буфер размером 60 Кбайт.

Направление TCP UDP
отправка, Мбит/с 725 820
получение, Мбит/с 665 н/д

Проверить UDP на вход не удалось, так как openSUSE, находившийся на противоположном конце кабеля, традиционно ограничивает выходную полосу UDP на уровне 10 Мбит/с независимо от скорости интерфейса; как видим, операционная система «Эльбрус» таких скрытых ограничений не имеет.

Выводы


Процессоры архитектуры «Эльбрус-2000» (E2K) имеют оригинальную организацию, позволяющую распараллеливать нагрузку между исполнительными устройствами каждого ядра ещё на этапе компиляции программ. Эта особенность является одновременно их сильной и слабой стороной, потому что многообещающий теоретический задел редко удаётся реализовать на практике, особенно когда речь идёт о программах общего назначения, не оптимизированных специально под «Эльбрус». Кроме того, статическая оптимизация оказывается бессильной при столкновении с динамическими языками программирования.

Другой отличительной особенностью E2K является комплексная технология защищённого исполнения программ, за счёт жёсткого аппаратного контроля обращения в память выявляющая типичные ошибки при использовании указателей и ручном управлении памятью. Если верить описанию, это прямо‑таки панацея, разом исцеляющая ваши программы практически ото всех болячек неосторожного обращения с памятью, — точнее, помогающая вам обнаружить все такие проблемные места ещё на этапе разработки, а не после запуска в промышленную эксплуатацию.

Также производитель заявляет о возможности исполнения программ, скомпилированных для архитектуры x86/x86‑64, прямо «на лету» — путём двоичной трансляции, что сулит широкие возможности использования популярных операционных систем (Windows, *nix) и всего многообразия прикладных программ с открытым и закрытым исходным кодом. Жаль, что нам не удалось опробовать эту функциональность; хотя, если вспомнить обо всех тех проблемах безопасности, которые несёт с собой x86, то скорее следует задаться вопросом, как заблокировать эту прозрачную совместимость раз и навсегда.

Суммарная производительность всех четырёх ядер процессора «Эльбрус‑4С», работающего на частоте 800 МГц, примерно соответствует таковой у двухъядерного Intel Atom D2500 на чуть более чем вдвое большей частоте (1866 МГц), — во всяком случае при том характере нагрузки, который создавали протестированные нами программы. Однако в повседневной жизни обычно преобладают однопоточные задачи, и потому много медленных ядер будут формировать у пользователя впечатление менее отзывчивой системы. Мечтать о динамичных видеоиграх на таком компьютере пока преждевременно, хотя эксперименты по запуску Doom 3 вроде прошли успешно. Воспроизведение фильмов Full HD тоже возможно, но в отсутствие аппаратного ускорения вся нагрузка ложится на центральный процессор. Для офисной работы, впрочем, имеющейся мощности хватит с избытком; тем более, как мы убедились, комфортность закладывается не процессором единым. И только допотопная версия веб‑браузера вызывает недоумение, потому что с этим реликтом сейчас совместим мало какой сайт в Интернете.

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

Короче говоря, новый «Эльбрус» автору очень понравился, особенно в сравнении с тем, что российская компьютерная промышленность могла предложить ранее. Да, пусть это ещё не Core i7 (или Xeon E7, если точнее), но догнать и перегнать Intel пока не удаётся даже огромной корпорации AMD с её миллиардными бюджетами на исследование и производство. Да, пусть цена пока «кусается», отпугивая рядовых потребителей и даже бизнес, — грезить об отвоёвывании гражданского рынка сейчас может только большой оптимист. Но уже виден прогресс, тем более что на горизонте отчётливо замаячил «Эльбрус‑8С», у которого больше ядер, больше мегагерцев и, хотелось бы верить, за меньше долларов. Надеемся, что однажды нам представится возможность написать статью и про него, — а ещё лучше, если своим опытом начнут делиться и другие владельцы отечественной техники. Платформа только тогда получит шанс стать массовой, когда научится быть открытой.

Post scriptum


Сегодня, 09.02.2016 нам позвонил представитель фирмы МЦСТ и предложил совместно поработать над устранением «тёмных пятен» — в частности, разобраться с технологией двоичной трансляции x86-кода, исследовать производительность новой версии Java-машины, подобрать дополнительные бенчмарки для демонстрации сильных сторон «Эльбруса», а также провести расширенное тестирование с участием и других образцов фирменной техники. Пока что это преварительная договорённость, поэтому делать прогнозы относительно того, во что может вылиться данная затея, ещё рано, но мы надееся не на отрывочные дополнения к нынешнему материалу, а на новую статью или даже серию статей — смотря сколько материала наберётся. Пожалуйста, наберитесь терпения, — всё это задумано именно ради публикации.

Дополнение от 03.03.2016. Первый результат совместной работы — «Дополнение к обзору: вопросы и ответы».
Теги:
Хабы:
+82
Комментарии 159
Комментарии Комментарии 159

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн