Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Streebog dynamic dispatch + import of SSE4.1 & MMX implementations #367

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

vt-alt
Copy link
Member

@vt-alt vt-alt commented Nov 26, 2021

Идея такая:

  • В файле gosthash2012_dispatch.h создаются разные версии g() под разные микроархтектуры (sse2, sse4.1, и ref).
  • Они переключаются динамически во время выполнения (сейчас для определения микроархитектуры используется __builtin_cpu_supports() и __has_builtin() (так что это работает только на свежих версиях gcc), но потом можно сделать определение через CPUID "как у всех").
  • Если dynamic dispatch невозможен, то все должно работать по старому (только sse2 и ref).
  • Переключение с помощью if — это наиболее быстрый вариант из доступных.

ps. gosthash2012: Fix '_mm_empty' call - надо в stable ветки перегнать, это багфикс.

'_mm_empty' call incorrectly wrapped in `#ifndef' instead of `#ifdef'.
This was affecting correctness of benchmarks on i686:

  type         16 bytes  64 bytes  256 bytes  1024 bytes  8192 bytes  16384 bytes
  streebog512      -nan      -nan       -nan        -nan        -nan         -nan

Fixes: 0755b6e ("gosthash2012: Properly ifdef '_mm_empty' call")
Signed-off-by: Vitaly Chikunov <[email protected]>
@vt-alt vt-alt force-pushed the dispatch branch 2 times, most recently from 55bb508 to b618bbc Compare November 27, 2021 17:30
@vt-alt vt-alt changed the title Streebog dynamic dispatch + import of SSE4.1 implementation Streebog dynamic dispatch + import of SSE4.1 & MMX implementations Nov 27, 2021
@vt-alt vt-alt marked this pull request as draft November 27, 2021 17:37
@vt-alt vt-alt requested a review from beldmit November 27, 2021 19:07
# error "No static implementation of g() is selected."
# endif
#endif
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Аццкий адЪ!

@beldmit
Copy link
Contributor

beldmit commented Nov 27, 2021

А диспетчер менее адским сделать не получается, да? :(

@vt-alt
Copy link
Member Author

vt-alt commented Nov 27, 2021

Там всё рационально, только непривычно такое количество логики на препроцессоре. Но, оно нужно, чтоб сохранить уже существующую портабельность. Рассмотрим gosthash2012_dispatch.h как 2 смысловые части:

  1. Создание разных версий g(). -- Этот вариант вносит наименьшее кол-во изменений в существующий код (не раскрывает все макросы и не создаёт повторов одного и того-же как в php-stribog). Не меняет способ сборки (иначе придется перенести усложнение в CMakeLists.txt, а там это может оказаться ещё "страшнее"). Так же у нас уже поддержка нескольких компиляторов, которую надо было оставить.
  2. Сам диспетчер (top level g()) вполне обычный. Вот пример для BLAKE3: https://github.com/BLAKE3-team/BLAKE3/blob/master/c/blake3_dispatch.c
    Если есть идеи, то предлагай.

@vt-alt
Copy link
Member Author

vt-alt commented Nov 27, 2021

# if defined(__clang__)
#  pragma clang attribute push (__attribute__((target("mmx"))), apply_to = function)
# elif defined(__GNUC__)
#  pragma GCC push_options
#  pragma GCC target("mmx")
# endif

...

# if defined(__clang__)
#  pragma clang attribute pop
# elif defined(__GNUC__)
#  pragma GCC pop_options
# endif

Вот этот фрагмент скорее всего можно заменить на 1 макрос устанавливающий __attribute__((target("mmx"))), а потом или прилеплять его сразу к функции g, или спрятать в другой (компиляторо-зависимый) макрос.

@vt-alt
Copy link
Member Author

vt-alt commented Nov 27, 2021

# undef XLOAD
# undef STORE
# undef TRANSPOSE
# undef XTRANSPOSE
# undef XLPS32
# undef XLPS
# undef __GOST3411_USE_MMX__
# undef g

Такое всё равно придется делать при темплейтировании и в gosthash2012_mmx.h это не убрать, так как эти мкросы ещё нужны в момент include gosthash2012_g.h. Но может можно это загнать в один макрос.

@vt-alt
Copy link
Member Author

vt-alt commented Nov 28, 2021

Пример диспетчера в libntru: https://github.com/tbuktu/libntru/blob/master/src/poly.c#L1082 общая схема такая-же, но всё проще так как этот код только под x86_64. Нам же так нельзя.

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

@vt-alt
Copy link
Member Author

vt-alt commented Nov 28, 2021

Пример из BIKE https://github.com/open-quantum-safe/liboqs/blob/main/src/kem/bike/additional_r3/decode_internal.h#L61
Все равно в _init есть сложная логика. И далее они устанавливают callbacks.
g() через pointers будет работать значительно медленнее для такой часто вызываемой функции,.
Вот соавтор BLAKE3 рассуждает о ifunc и поинтерах: BLAKE3-team/BLAKE3#92 (comment)
Другой эксперт по performance мне так же советовал из трех вариантов - if(), pointer, ifunc - использовать if() для переключения (для кода в библиотеках).

@vt-alt
Copy link
Member Author

vt-alt commented Nov 28, 2021

Мало кто делает темплейт. Можно пойти на дублирование кода и перенести копии функции g() (она не такая большая) в gosthash2012_{ref,mmx,sse2,sse41}.h тогда все #undef и attribute target() можно перенести в них же. А в gosthash2012_dispatch.h будет только 4 #include этих микроархитектурно зависимых хедеров и диспетчер.

Это можно дальше развить и переименовать все эти gosthash2012_sse2.h в gosthash2012_sse2.c и собирать их отдельно (заодно выкинуть #undef). А gosthash2012_dispatch.h вернуть обратно в gosthash2012.c.

@beldmit
Copy link
Contributor

beldmit commented Nov 28, 2021

LGTM

@vt-alt
Copy link
Member Author

vt-alt commented Nov 28, 2021

Только сейчас подумал, что можно же было делать #include "gosthash2012_g.h" внутри gosthash2012_sse41.h и др. Странно мозг работает.

@vt-alt
Copy link
Member Author

vt-alt commented Nov 29, 2021

LGTM

Это про что?

@beldmit
Copy link
Contributor

beldmit commented Nov 29, 2021

Это по совокупности

This implementation is functionally exact to previous code (just
rearrangement), in preparation to run-time dispatch use.

Signed-off-by: Vitaly Chikunov <[email protected]>
Currently, only switch between see2 and ref implementations. This should
affect only i686, since x86_64 always have SSE2 unless compiled with
`-mno-sse2'.

This version of dynamic dispatch would work only on GCC-10 / Clang-3,
otherwise fallback to static dispatch like before.

Signed-off-by: Vitaly Chikunov <[email protected]>
Merged and fixed two MMX implementations. For example,
[1] uses SSE2 register types `__m128i',
[2] GCC's `mmintrin.h' defines `_mm_cvtsi64_m64' only for `__x86_64__',
    but we need MMX exactly for IA-32, since x86_64 it have SSE2 in
    baseline.

Link: https://github.com/adegtyarev/streebog
Link: https://github.com/sjinks/php-stribog
Signed-off-by: Vitaly Chikunov <[email protected]>
@vt-alt
Copy link
Member Author

vt-alt commented Nov 30, 2021

Переделал так — убрал прагмы (вместо них attribute target() прямо у функций — для msvc говорят они не нужны), вместо темплейта (с include _g.h) и {ref,sse2,...}.h сделал .c где в каждом своя версия g. Логика выбора реализаций в gosthash2012.h, диспетчер (top-level g остался) в gosthash2012.c. Добавил атрибут _internal для всех g (может это повлияет на оптимизацию.), (А для главной g (диспетчера) заменил static на _internal, чтоб его asm можно было посмотреть в gdb -ex 'disas/s g'" — это можно убрать, но, вроде, не мешает).

@beldmit
Copy link
Contributor

beldmit commented Dec 1, 2021

Так оно стало гораздо читабельнее.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants