Size: a a a

Конференция C++ Russia

2021 July 16

MK

Max Khizhinsky in Конференция C++ Russia
GCC это attribute((target)) для функции. Обычно используется для реализаций SSE.
И, конечно, это должна быть отдельная функция, ни о каким инлайнинге здесь речи нет. А значит, разрабатывая всякие template class (куда очень хорошо ложатся всякие структуры данных) в .h, такие специфические вещи придется выносить в отдельные функции в .cpp, и часто даже не понятно, как их назвать...
источник

AB

Anton Bikineev in Конференция C++ Russia
> а ld при загрузке выберет именно ту, на чем сейчас запускается процесс.

Думал об этой идее, чтобы стартап (либо дин. линкер) подбирал лучший вариант в зависимости от текущей архитектуры. Это, кстати, то, где jitы сияют.

В Хроме мы вручную запрашиваем cpuid, а затем в завимости от поддерживаемого расширения вызываем соответствуюшую функцию аннотированную с помощью __attribute__((target(…))): https://source.chromium.org/chromium/chromium/src/+/main:base/allocator/partition_allocator/starscan/scan_loop.h;l=78?q=scan_loop.h&ss=chromium%2Fchromium%2Fsrc
источник

AB

Anton Bikineev in Конференция C++ Russia
Можно попробовать сделать такую прикольную штуку, как inline __attribute__((noinline)):
- inline даст возможность обойти ODR и иметь функцию в хэдере (через COMDAT-секцию либо weak символы);
- __attribute__((noinline)) даст некоторую гарантию что функция материализуется в бинаре.

(для шаблонных функций inline даже не нужен)
источник
2021 July 17

MK

Max Khizhinsky in Конференция C++ Russia
хм... а зачем делать в runtime то, что можно сделать на этапе загрузки (что делает ldd при стартепроцесса )?.. В Линуксе (винду отставляем в сторону) ldd должен сам выбрать правильную функцию по target, без всяких if'ов в рантайме... По крайней мере несколько лет назад это работало...

inline attribute((noinline)) - век учись и дураком помрешь 😊 Сам бы такое не выдумал...
источник

DK

Dmitry Kazakov in Конференция C++ Russia
Проблема этого атрибута в том, что гранулярность слишком высокая. Придется весь алгоритм целиком дублировать во всех методах. Иначе будет лишний function call в самом горячем месте.

Ну то есть глобально проблема этого атрибута, что его нельзя к шаблонам применять.

Кстати, хороший вопрос: а что будет, если из методов с разными атрибутами вызывать один и тот же шаблон? Как там кодгенерация сработает? Перенесется ли этот атрибут на сгенерированный код?
источник

DK

Dmitry Kazakov in Конференция C++ Russia
Ну и больше всего интересно, как он отработает вот такие #if defined __AVX2__: https://invent.kde.org/graphics/krita/-/blob/master/libs/pigment/KoOptimizedRgbPixelDataScalerU8ToU16.h#L29
источник

DK

Dmitry Kazakov in Конференция C++ Russia
А длина буфера в этом ScanLoop у вас большая? Просто если этому алгоритму скармливать буферы по 3 элемента он тупить начнет (у нас такой эффект есть, но у нас элементов в одном ymm больше помещяется).
источник
2021 July 18

AB

Anton Bikineev in Конференция C++ Russia
да, большие - это линейные куски хипа.
источник

AB

Anton Bikineev in Конференция C++ Russia
> ldd должен сам выбрать правильную функцию по target, без всяких if'ов в рантайме..

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

Хром собирается с минимальным -msse3, т.к. все еще много старых машин на земле :). Поэтому, чтобы заставить sse4/avx2 интринсики работать, мы используем таргет-аттрибут.
источник

o

ololoshwin in Конференция C++ Russia
насколько мне известно PLT загрузчик функции в linux/glibc выбирает реализацию соответствующую процессору во время выполнения.
источник

AB

Anton Bikineev in Конференция C++ Russia
Хорошее замечание. Почитал - действительно glibcшный линкер патчит .got.plt только для glibcшных функций, вроде memset и т.д. Это, в целом, разумно, т.к. сам линкер - часть glibc. Для юзерового кода это, очевидно, не работает.

Для юзерового кода нашел только фичу работающую на уровне DSOs в glibc (называется dt_hwcap). Если правильно понял, работает так, что дин. линкер приоретизирует загрузку DSOs из определенных директорий, соответствующих именам поддерживаемых проц. расширений (например, /usr/lib/sse2). Кажется, появилось только в glibc-2.26 и работает пока только для x86 (не для x86_64).

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

АР

Андрей Руссков... in Конференция C++ Russia
если вы про attribute((target("avx"))) то эта штука в x64 тоже есть
источник

FS

Flower Surgeon in Конференция C++ Russia
Линкер не часть glibc, а часть тулчейна.
источник

FS

Flower Surgeon in Конференция C++ Russia
(понимаю, что все и так поняли, но всё же)
источник

AB

Anton Bikineev in Конференция C++ Russia
Нет, про то, как дин. линкер glibc ищет пути в зависимости от текущих поддерживаемых расширений
источник

AB

Anton Bikineev in Конференция C++ Russia
Наверно, confusion вокруг статического линкера (ld) и динамического линкера (ld.so, ld-linux.so). Я говорю про динамический, что поставляется с glibc, вы говорите про статический, что поставляется с binutils (bfd/gold) либо llvm (lld)
источник

АР

Андрей Руссков... in Конференция C++ Russia
ну он этот аттрибут не учитывает?
источник

АР

Андрей Руссков... in Конференция C++ Russia
методы им помеченные манглятся по-разному, так что мог бы
источник

FS

Flower Surgeon in Конференция C++ Russia
Или мы не тот линкер обсуждаем. Забьём для ясности.
источник

o

ololoshwin in Конференция C++ Russia
Тот который в glibc понятнее называть загрузчиком
источник