Матричное расширение ISA CPU… Что это и что оно делает? Уже из названия понятно, что это расширение позволяет ускорять операции над матрицами на CPU. Но задумывались ли вы когда-нибудь, какие они бывают, когда появились, кто и как их создает?

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

Матричные расширения появились не так давно — чуть более трех лет назад. Несмотря на это, они есть у каждой уважающей себя процессорной архитектуры, в том числе у относительно молодой открытой RISC-V. Причем, как это ни парадоксально, по числу матричных расширений RISC-V уже обогнала все остальные архитектуры: на данный момент разработаны два кастомных расширения и прямо сейчас разрабатываются два стандартных. 

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

Эту статью можно поделить на две части:

  1. Попытаемся понять, зачем вообще нужны матричные расширения и в чем тут соль.

  2. Соберем воедино все, что можно найти в открытых источниках о ныне существующих матричных расширениях — от Intel AMX до SpacemiT IME. 

А через неделю выйдет продолжение. Попробуем разобраться, как идет разработка стандартных матричных расширений RISC-V и что в связи с этим ждать. Подписывайтесь, чтобы не пропустить.

Часть первая: 5 вопросов для «первого свидания»

В каких приложениях нужно ускорять матричные операции?

Матричные операции — это основные хот-споты для приложений из таких областей, как:

  • искусственный интеллект и машинное обучение (AI/ML), 

  • компьютерное зрение (CV), 

  • дополненная и виртуальная реальность (AR/VR), 

  • математическое моделирование сложных физико-технических систем (CAE, HPC),

  • усовершенствованные системы помощи водителю (ADAS) и др.

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

Зачем ускорять матричные операции на CPU в эпоху ускорителей?

Очень частое заблуждение, что все математически сложные алгоритмы уже давно выполняются только на специализированных ускорителях: графических (GPU), тензорных (TPU), нейронных (NPU) и так далее. 

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

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

Интересный факт: даже в сегменте суперкомпьютеров есть полностью гомогенные машины, то есть суперкомпьютеры, состоящие только из CPU. Яркий пример — японский гомогенный суперкомпьютер Fujitsu Fugaku на базе архитектуры Arm A64FX. В июне 2020 года он стал самым быстрым суперкомпьютером в мире в рейтинге Top500 и первым суперкомпьютером в истории, занявшим первое место сразу во всех основных суперкомпьютерных рейтингах — Top500, LINPACK, HPCG, HPL-AI и Graph500. До Fujitsu Fugaku ни один суперкомпьютер на базе архитектуры Arm не показывал столь высокой производительности.

Как ускоряли матричные операции на CPU до появления расширений?

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

?_{? \times ?}  = ?_{? \times ?} \times ?_{? \times ?}

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

\begin{bmatrix}C_0^0&\cdots&C_0^{N-1}\\\vdots&\ddots&\vdots\\C_{M-1}^0&\cdots&C_{M-1}^{N-1}\end{bmatrix}=\begin{bmatrix}\sum\limits_{k=0}^{K-1}A_0^kB_k^0&\cdots&\sum\limits_{k=0}^{K-1}A_0^kB_k^{N-1}\\\vdots&\ddots&\vdots\\\sum\limits_{k=0}^{K-1}A_{M-1}^kB_k^0&\cdots&\sum\limits_{k=0}^{K-1}A_{M-1}^kB_k^{N-1}\end{bmatrix}.

То есть, чтобы вычислить матрицу-произведение, вам нужно выполнитьM \cdot N скалярных произведений строк на столбцы. В виде алгоритма это можно записать так:

\begin{split}C_{M \times N} = [0]_{M \times N}, \quad \mbox{for }i=&[0,M) \\ \mbox{for }&j=[0,N)\\ &\mbox{for }k=[0,K) \ \ C_i^j+=A_i^kB_k^j.\end{split}

Кажется, что алгоритм предельно прост: мы обнуляем элементы матрицы-аккумулятора и затем в трех вложенных циклах выполняем M \cdot N \cdot K умножений-сложений. Число операций не сократить — значит, алгоритм уже не ускорить?

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

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

Что же делать? 

Решает проблему достаточно простая идея, которая лежит в основе абсолютно всех высокопроизводительных библиотек линейной алгебры. Описана она в знаменитой статье «Анатомия высокопроизводительного матричного умножения» (Anatomy of High-Performance Matrix Multiplication), которую написали Kazushige Goto и Rovert A. Van De Geijn из Техасского университета в Остине. 

Идея в том, что вы «нарезаете» матрицу B на горизонтальные полосы, которые по размеру могут уместиться в L3-кэш, матрицу A — на блоки, «влезающие» в L2-кэш, затем полосы матрицы B из L3-кэша разбиваете на столбцы, помещаемые в L1-кэш, как показано на схеме ниже. Аккумулируется произведение уже в регистрах, то есть в самой быстрой памяти.

Источник

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

В плане дальнейшей оптимизации есть некоторый простор для творчества: так, например, в библиотеке OpenBLAS оптимизация начинается с Loop 2 (macro-kernel), а в библиотеке BLIS низкоуровневые оптимизации возникают только в последнем цикле, Loop 0 (micro-kernel).

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

Как расширения помогают ускорять вычисления?

Лимит ускорения не исчерпан, если мы сможем распараллелить операции. Так, например, если у нас есть векторное расширение, то мы можем операции векторизовать: загрузить в векторные регистры K элементов из строки матрицы A, K элементов из столбца матрицы B и умножить элементы векторных регистров. Здесь мы предполагаем, что число K после всех описанных выше разбиений матрицы на блоки выбрано с учетом длины векторного регистра.  

Таких операций требуется сделать M \times N, то есть в K раз меньше, чем в реализации алгоритма матричного умножения без использования расширений. Но, конечно, эти  операции более «дорогостоящие»: умножение совершается не над скалярами, а над векторами, плюс неизбежны накладные расходы на загрузку данных в векторные регистры и выгрузку. Поэтому, конечно же, ускорения вычислений в те же самые K раз ожидать не стоит. Однако ускорение умножений матриц даже в 2 раза просто за счет использования векторного расширения — это уже очень неплохо, если такие умножения занимают большую часть времени работы приложения. 

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

Конечно, такие матричные операции еще более «дорогостоящие» по тактам, чем векторные, но и требуется их меньше. Ведь плиток (блоков) в исходных матрицах явно меньше, чем строк и столбцов. 

Но позволит ли матричное расширение получить ускорение по сравнению с векторным? Здесь мы можем вспомнить о такой метрике, как вычислительная интенсивность:

\eta=\frac{\mbox{число операций}}{\mbox{число элементов}}

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

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

Анализ данных из открытых источников показал, что «в среднем по больнице» матричные расширения позволяют получить ускорение от 2 до 12 раз по сравнению с векторными.

Для Arm SME сравнивалось число тактов (на симуляторе). Во всех остальных случаях — время счета.
Для Arm SME сравнивалось число тактов (на симуляторе). Во всех остальных случаях — время счета.

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

Источники данных для табицы

Какие бывают матричные расширения?

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

В случае интегрированных матричных расширений в уже существующую архитектуру не добавляются никакие дополнительные регистры: для хранения как матриц-сомножителей, так и матриц-аккумуляторов используются векторные регистры. Примерами матричных расширений такого класса являются оба кастомных расширения RISC-V: SiFive Intelligence Extension и SpacemiT IME (Integrated Matrix Extension).

Если в архитектуру добавляется независимый блок регистров для матриц-аккумуляторов, то это уже гибридное матричное расширение. Именно к этой группе относятся Power MMA (Matrix Multiply Assist) и Arm SME (Scalable Matrix Extension).

И наконец, если в архитектурное пространство добавлены полноценные двумерные матричные регистры, в которых хранятся как плитки матриц-сомножителей, так и плитки матрицы-аккумулятора, и матричное расширение взаимодействует только с этими регистрами, то перед нами независимое матричное расширение. В этом случае матричное и векторное расширения абсолютно не зависимы друг от друга, и вполне возможна ситуация, когда на CPU есть матричное расширение, но нет векторного. Примеры независимых матричных расширений — Intel AMX (Advanced Matrix Extension) и Apple AMX (Attached Matrix Extension).

Часть вторая: расширения в деталях

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

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

Самое большое расхождение между анонсом и появлением реализации в железе у Intel AMX: в 2020 году оно было анонсировано, но мир увидел его только в 2023 году — на год позже, чем замеры производительности кастомного матричного расширения RISC-V от компании SiFive. То есть в плане матричных расширений RISC-V, несмотря на свою молодость, движется наравне с такой зрелой архитектурой, как х86, в чем-то даже опережая ее. Интересное наблюдение, но давайте посмотрим детальнее, что известно о существующих матричных расширениях. 

Intel AMX 

Первое расширение, которое мы рассмотрим, это Intel Advanced Matrix Extension (AMX). Его анонс вышел еще в 2020 году, но в железе оно появилось только в 2023 году, в четвертом поколении серверных процессоров Intel Xeon — Sapphire Rapids. Это независимое от векторного матричное расширение, включающее 12 новых инструкций, которые можно разделить на три группы: 

  1. Конфигурирование матричных регистров («тайлов» или плиток). 

  2. Управление матричными регистрами (load/store, clear, set и другие). 

  3. Операции над плитками матриц в матричных регистрах.

Что же из себя представляют независимые матричные регистры в Intel AMX? Это новый расширяемый двумерный (2D) регистровый файл. Сейчас он состоит из восьми регистров Т0-Т7 по 1 Кб каждый. Из матричных операций пока реализована только одна — TMUL, инструкция матричного умножения (как уже отмечалось выше, это основной хот-спот во многих приложениях). TMUL использует три регистра: T2 += T1 * T0.

Расширение поддерживает типы данных пониженной и половинной точности: INT8, UINT8, BF16, FP16, Complex FP16. Можно сделать вывод, что его разработчики были сфокусированы на ускорении инференса нейронных сетей. При этом аккумуляторы всегда 32-битные: INT32, UINT32 или FP32.

Что мы знаем про производительность этого расширения из открытых источников? Например, есть исследование, в котором рассматривается сверточная нейронная сеть ResNet50 (FP32, batch size = 16). Векторизация на основе Intel VNNI (AVX-512 Vector Neural Network Instructions) позволяет ускорить вычисления в четыре раза по сравнению со скалярной версией, а матричное расширение — почти в 9 раз. Получается, на этом кейсе матричное расширение быстрее векторного более чем в два раза.

Ускорение по сравнению со скалярным кодом, раз 
Ускорение по сравнению со скалярным кодом, раз 

Apple AMX

Следующее расширение – Apple Attached Matrix Extension (AMX). Это, опять же, независимое матричное расширение. Официальной документации у него нет. А само расширение обнаружили в 2020 году при реверс-инжиниринге процессора Apple M1. 

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

Что мы знаем об этом расширении? Его инструкции были обнаружены при мониторировании вызовов математических библиотек vImage, vDSP, BNNS, BLAS/LAPACK. А значит, оно используется для ускорения обработки изображений и сигналов, операций линейной алгебры и работы с нейронными сетями в приложениях AR/VR, CV и ML. По сравнению с Arm Neon ускорение получается в среднем в два раза.

Архитектурное пространство, выделенное для регистров данного расширения, составляет 5 Кб. Для сомножителей отводится по восемь регистров (64-байтовых векторов) на каждый из двух операндов (x0..7 и y0..7), элементы которых могут иметь следующие типы данных: INT8, UINT8, INT16, UINT16, FP16..64. В Apple M2 также добавлена поддержка BF16. Все остальное пространство расширения (z на схеме ниже) отводится под аккумуляторы и может быть сконфигурировано следующими способами:

  • 1 регистр размером 64 \times 64 (32 \times 32) элемента по 8 (32) бита. 

  • 2 регистра размером 32 \times 32 по 16 бит.

  • 4 регистра размером 16 \times 16 по 32 бита.

  • 8 регистров размером 8 \times 8 по 64 бита.

  • 64 регистра, каждый из которых – 64-байтовый вектор-строка.

Arm SME

Расширение Arm Scalable Matrix Extension (SME) анонсировали в 2022 году для Armv9-A. Профиль «A» (application) соответствует высокопроизводительным ядрам, которые используются в смартфонах, планшетах и других устройствах, вплоть до оборудования центров обработки данных. 

Cудя по всему, первым процессором с реализацией Arm SME стал Apple M4, представленный 7 мая 2024 года. Пока еще нет детального сравнения производительности с Arm Neon — в открытом доступе можно найти только первые замеры, поэтому далее мы рассмотрим только результаты сравнения на симуляторе. 

Это гибридное расширение, то есть для сомножителей используются векторные регистры — SVE или SVE2, а для матрицы-аккумулятора вводится один дополнительный 2D матричный регистр (по последним данным это дополнительное пространство может конфигурироваться в несколько регистров, как z в описанном выше Apple AMX). Элементы аккумуляторов могут быть 32- или 64-битными, в то время как элементы сомножителей могут иметь ширину от 8 до 64 бит. Известно, что первая версия SME содержит инструкцию умножения матриц, а во второй добавились инструкции для матрично-векторного умножения (GEMV) и нелинейных решателей, а также поддержка разреженных матриц (но процессоров с SME2 пока нет). 

На конференции The International Conference for High Performance Computing, Networking, Storage, and Analysis (SC'22), один из докладов был посвящен моделированию производительности Arm SME. Для симуляции авторы использовали модель ядра Fujitsu A64FX (именно оно используется в упомянутом ранее гомогенном суперкомпьютере Fujitsu Fugaku). Тестовая задача состояла из 200 матричных умножений (данные одинарной точности). Сравнивались векторная (на основе SVE) и матричная реализации. В зависимости от размера матриц SME позволило уменьшить число тактов от 2,2 до 6,4 раз по сравнению с SVE. Конечно, это оценка на симуляторе и на реальном железе цифры могут отличаться, однако результат интересный.

Power MMA

Гибридное матричное расширение Power Matrix Multiply Assist (MMA) появилось в 2021 году в Power10 — семействе суперскалярных симметричных мультипроцессоров на базе архитектуры POWER от IBM. Несмотря на то, что дополнительного пространства для аккумуляторных матричных регистров в архитектуре не появилось, расширение Power MMA позиционируется именно как гибридное, поскольку половину векторных регистров выделили под аккумуляторы насовсем. Эти 32 векторных регистра разбили на восемь групп по четыре регистра, и в итоге получили восемь 512-битных аккумуляторных регистров. Остальные 32 векторных регистра используются для операций векторного расширения VSX, а также для матриц-сомножителей в инструкциях матричного расширения. Поддерживаемые типы данных: BF16, FP16..64, INT4..16. 

Разработчики Power MMA задались очень правильным вопросом: как с минимальными затратами обеспечить ускорение для широкого спектра приложений? В итоге они добавили реализации матричного умножения с использованием Power MMA для различных типов данных в две библиотеки линейной алгебры: OpenBLAS и Eigen. Эти библиотеки используются во многих популярных фреймворках, таких как NumPy, PyTorch, TensorFlow, OpenCV и других, и влияют на производительность многих приложений.

Рассмотрим результаты, представленные в исследовании производительности производительности Power MMA на нескольких тестовых кейсах. Так, в случае умножения плотных матриц с элементами двойной точности (DGEMM) векторное расширение VSX позволяет ускориться чуть больше чем в два раза по сравнению со скалярным кодом, а матричное — в 5,5 раз.

Ускорение по сравнению со скалярным кодом, раз
Ускорение по сравнению со скалярным кодом, раз

Также в исследовании рассматривалось влияние типа данных на ускорение инференса нейронной сети ResNet50 по сравнению со скалярной версией: если в случае данных одинарной точности Power MMA дает ускорение в 10 раз, то для 8-битных — уже в 21 раз.

Ускорение по сравнению со скалярным кодом, раз (в зависимости от типа данных)
Ускорение по сравнению со скалярным кодом, раз (в зависимости от типа данных)

Для LINPACK бенчмарка, представляющего собой решение последовательности плотных систем линейных алгебраических уравнений с матрицами разного размера, Power MMA показывает масштабируемость, превосходящую и скалярную (плато на графике для систем с размерностью, превышающей 1024) и векторную (выходит на плато начиная с 4096 неизвестных) реализации. 

Производительность, flops/cycle (в зависимости от размерности задачи)
Производительность, flops/cycle (в зависимости от размерности задачи)

Почему замеры производительности делают для разных размеров матриц? 

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

Идеальным случаем является линейное масштабирование: во сколько раз увеличивается размер задачи — во столько же растет производительность на графике выше. Но в реальной жизни такого, конечно, не бывает: всегда есть накладные расходы, размеры кэша и так далее. Поэтому в реальности график производительности всегда будет ниже линейного, а с какого-то размера задачи и вовсе выйдет на плато. Разработчики математических библиотек всегда бьются за то, чтобы масштабируемость была как можно ближе к линейной, а плато не наблюдалось как можно дольше. 

Интересующимся будет полезно изучить Best Practices Guide от разработчиков Power MMA. Интересно, что один из авторов этой книги, Хосе Морейра, также является председателем Vector Special Interest Group (SIG) консорциума RISC-V International. Именно он инициировал создание группы разработки интегрированного матричного расширения RISC-V IME TG и стал ее вице-председателем. И, насколько я могу судить по открытым источникам, многие идеи из Power MMA плавно перетекают в это расширение, о котором мы поговорим в следующем тексте.

SiFive Intelligence Extension

В 2022 году появилось первое матричное расширение для RISC-V. Это кастомное расширение, интегрированное в векторное, производства компании SiFive. Матричные инструкции оперируют данными, хранящимися в 512-битных векторных регистрах. Расширение позиционируется как подходящее для ускорения инференса, приложений AR/VR, приложений из систем IVI, цифровых и IP-камер, игровых устройств. У него уже есть поддержка в TensorFlow Lite, а на сайте SiFive доступны спецификации для типов данных INT8 и BFloat16

В исследовании Google представлены оценки производительности SiFive Intelligence Extension. Так, для умножения матриц с элементами типа INT8 говорится об ускорении в 12 раз по сравнению с векторным расширением RISC-V RVV, а для инференса сверточной нейронной сети MobileNet v1 (batch size = 1, VLEN = 512 бит) — в 6 раз: 

Ускорение по сравнению со скалярным кодом, раз
Ускорение по сравнению со скалярным кодом, раз

SpacemiT IME

Совсем недавно — в конце апреля 2024 года — стало известно о SpacemiT Integrated Matrix Extension (IME). Это еще одно кастомное матричное расширение RISC-V от компании SpacemiT и снова —  интегрированное в векторное. Из спецификации расширения следует, что поддерживается только одна матричная операция — умножение плотных матриц, но при помощи параметра Copу можно задавать число операций, выполняемых параллельно. Сомножители и аккумуляторы хранятся в 256-битных векторных регистрах. Поддерживаются следующие типы данных: BF16, FP4..16, INT4..16.

Уже доступна для заказа плата Banana Pi BPI-F3 с 8-ядерным процессором SpacemiT K1 RISC-V, все ядра которого включают векторное расширение RVV 1.0 и четыре из них — матричное расширение SpacemiT IME. Заявлено, что каждое ядро на 30% превосходит по производительности Arm Cortex A55, суммарная производительность 2.0 TOPs AI (подробнее здесь).

Заключение

Матричные расширения начали появляться относительно недавно — с 2020 года, и в этом направлении x86, Power, Arm и RISC-V движутся практически наравне. Такие расширения подходят для ускорения приложений AI/ML, AR/VR, CV, ADAS, HPC.

Очень удачным ходом со стороны разработчиков расширений является добавление оптимизаций в такие широко используемые библиотеки линейной алгебры, как OpenBLAS и Eigen (что было сделано в свое время компанией IBM для Power MMA).

Надеюсь, вы узнали что-то новое о матричных расширениях: почему они так востребованы и что сейчас есть на рынке. В следующем тексте, который выйдет через неделю, я расскажу больше о матричных расширениях RISC-V, которые находятся в стадии разработки.

А еще мы с коллегами готовим два текста «похардкорнее». Третья статья будет посвящена спецификации независимого матричного расширения T-Head RVM, а в четвертой мы подробно разберем, как с помощью этого расширения реализовать умножение матриц.

Комментарии (37)


  1. Imaginarium
    09.07.2024 16:45
    +4

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


    1. valeriaP Автор
      09.07.2024 16:45
      +6

      Спасибо, продолжение статьи уже в работе


  1. Barabashkad
    09.07.2024 16:45
    +1

    я так понимаю эти все расширения с родни нвидиовским tensor core ?
    есть ли информация сколько АМХ у интелов ? у каждого ядра или нет ?
    как они работают с hyperthreading ?
    что на счем AMD CPU ?


    1. valeriaP Автор
      09.07.2024 16:45
      +1

      идеологически похоже, хотя есть нюансы.

      Про такие детали Intel AMX внутри Sapphire Rapids мне информация не попадалась, но, возможно, кто-то из коллег в курсе.

      У AMD, насколько можно судить по спецификациям, AMX пока нет. В этом исследовании можно глянуть последние бенчмарки OpenVINO -- Sapphire Rapids с меньшим числом ядер за счет AMX показал результат выше EPYC 9684X с VNNI (AVX-512 Vector Neural Network Instructions).


  1. checkpoint
    09.07.2024 16:45
    +4

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


    1. valeriaP Автор
      09.07.2024 16:45
      +3

      Разработка таких расширений включает в себя не только аппаратную часть, но и большую работу со стеком ПО: помимо оптимизаций математических библиотек, это в том числе и организация поддержки расширения в ядре Linux (детекция наличия/отсутствия расширения, указание режима его работы, флаги используемых регистров для оптимизации переключения контекста и т.д.). Например, краткое описание в документации для Arm SME (понятно, что это не все "внутренности", а только минимальная видимая часть).

      Активная работа расширения происходит только во время решения вычислительных задач, для которых эти матричные операции -- серьезные хотспоты (до 90% времени работы приложений, о которых говорилось в тексте, может уходить на матричное умножение, например). Получаемое в итоге ускорение компенсирует возросшие накладные расходы -- на практике по сравнению с векторизацией минимум в 2 раза ускорение получается.

      Что оптимальнее -- расширение cpu или отдельный блок -- здесь нет однозначного ответа: есть примеры удачных решений как первой категории, так и второй. Тот же упомянутый в статье гомогенный Fujitsu Fugaku.


      1. checkpoint
        09.07.2024 16:45

        Что оптимальнее -- расширение cpu или отдельный блок -- здесь нет
        однозначного ответа: есть примеры удачных решений как первой категории,
        так и второй. Тот же упомянутый в статье гомогенный Fujitsu Fugaku.

        Валерия, мы говорим о процессоре общего назначения или о специализированном ?

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


        1. valeriaP Автор
          09.07.2024 16:45

          Если вы сможете провести такие замеры, будет очень интересно посмотреть. Например, Apple M4 c Arm SME или Apple M1--3 c Apple AMX.


          1. checkpoint
            09.07.2024 16:45

            К сожалению, моих ресурсов для такого исследования недостаточно. Я как раз надеялся на Вас и вашу компанию в этом вопросе. :-) Проблема еще в том, что яблочные M1-M4 полностью закрыты, документации нет. Но если вы взялись проектировать ускоритель для процессора общего назначения, то хотя бы какую-то прикидочную симуляцию/моделирование выполнить стоит.


            1. valeriaP Автор
              09.07.2024 16:45

              Возможно в тексте немного затерялось -- я инженер-математик по образованию, призванию и роду деятельности), т.е. применительно к этим расширениям я -- пользователь, а не разработчик. Ускорители я никогда не проектировала и не проектирую, но, как математика-прикладника, меня, конечно же, интересует, что есть в этой области, чего ждать.

              Думаю, разработчики железа проводили исследования, о которых вы упоминали, ведь те же Apple M1--4 не только для инференса и коррекции фото используются, но статьи о серьезных просадках производительности на других приложениях мне не попадались, пока я исследовала данную тему.


            1. beeruser
              09.07.2024 16:45

               Проблема еще в том, что яблочные M1-M4 полностью закрыты, документации нет.

              Вы о чём? Кем закрыты?

              Документация на сайте ARM.

              Если нужны детали реализации процессора, тут море информации:

              https://github.com/name99-org/AArch64-Explore


              1. checkpoint
                09.07.2024 16:45

                Видимо Вы потеряли нить повествования. Речь идет о матричном сопроцессоре и GPGPU. Эта тема для M1-M4 полностью закрыта, есть только пользовательские библиотеки с весьма ограниченным функционалом. Оценить производительность операционной системы по ним вряд ли выйдет.


                1. beeruser
                  09.07.2024 16:45

                  Видимо Вы потеряли нить повествования. Речь идет о матричном сопроцессоре

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

                  Потому что сказали вы другое:

                  яблочные M1-M4 полностью закрыты, документации нет. 

                  И это является ложью.

                  В M4 сопроцессор AMX выведен в виде SME.

                  Документация открыта на сайте ARM.

                  Вы ведь проигнорировали ссылку в статье?

                  https://github.com/tzakharko/m4-sme-exploration

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

                  Документация на AMX легко доступна в 1 клик.

                  https://github.com/corsix/amx

                  https://gist.github.com/dougallj/7cba721da1a94da725ee37c1e9cd1f21

                  Вот так вот информация "закрыта" чуть более чем полностью(с)

                  Пассаж про GPGPU тем более не ясен. Всё открыто в презентациях и документации Apple.


                  1. checkpoint
                    09.07.2024 16:45

                    Не буду с Вами спорить, а всего лишь попрошу продемонстрировать сниппет (кусочек) ассемблерного кода для AMX в составе процессора M4 для вычисления перемножения двух матриц 16x16 с элементами FP16. Это не должно быть для Вас большой проблемой - вся спецификация, с Ваших слов, есть в презентациях от Apple.


                    1. valeriaP Автор
                      09.07.2024 16:45

                      1. checkpoint
                        09.07.2024 16:45

                        Валерия, мне комментарием выше пишут, что

                        Документация на AMX легко доступна в 1 клик.

                        Откровенно говоря мне глубоко фиолетово на сорта говна в яблочной продукции.


                      1. valeriaP Автор
                        09.07.2024 16:45

                        а, Apple AMX из Apple M1--M3 -- возможно, имелось в виду исследование Дугалла Джонсона, который его как раз и обнаружил, https://gist.github.com/dougallj/7cba721da1a94da725ee37c1e9cd1f21


    1. Barabashkad
      09.07.2024 16:45

      смею предположить что матричные регистры вообще не сохраняються при переключении, а содаеться очередь команд от разных контекстов. и если существует несколько пытающихся использовать AMX они ждут друг друга, один поток выполнил часть , результат сохранился в L1/L2 и другой получит время , и все это на железном уровне. хм (мысли в слух) получаеться как с hyperthreading. вот только особого практического смыла в этом мне не видиться


      1. checkpoint
        09.07.2024 16:45

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

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

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

        В общем, я категорически против того, чтобы из RISC-V делали очередной CISC. Если требуется матричный вычислитель - ставьте отдельный IP блок GPGPU, посадите его на внутренний интерконнект, снабдите вагоном статической памяти не опираясь на размер регистрового файла. Но раздувать ядро и ISA это просто глупо!


        1. Barabashkad
          09.07.2024 16:45
          +1

          не совсем
          выполнение любой ассемблерной команды может зависить от предыдущих и pipeline может так сказать замереть.
          но в случае с Intel AMX судя по всему произходит как вы предположили : через syscal
          https://www.intel.com/content/www/us/en/developer/articles/code-sample/advanced-matrix-extensions-intrinsics-functions.html

          "2. The next section in the code is to to invoke a Linux system call to request access to Intel® AMX features. This is performed using the arch_prctl(2) based mechanism for applications to request usage of the Intel® AMX features. Specific information is described in the Linux kernel documentation. "

          добавление акселераторов делает ли из RISC CISC ? xм .... не уверен :-)
          MMX, SSE , NEON , SVE - все это акселераторы :-)
          да таже nvidia с тенсорами.
          а вот перегонка данных между процессорами очень затратное действие
          особенно в сегодняшней PC aрхитектуре.
          не зря Apple сделала свой чип


          1. checkpoint
            09.07.2024 16:45

            добавление акселераторов делает ли из RISC CISC ? xм .... не уверен :-)
            MMX, SSE , NEON , SVE - все это акселераторы :-)
            да таже nvidia с тенсорами. а вот перегонка данных между процессорами очень затратное действие особенно в сегодняшней PC aрхитектуре.

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

            Если я не ошибаюсь, у яблочного M1 ускорители вынесены и стоят рядом на отдельных кристаллах чиплета, только вместо PCIe - своя внутренняя высокоскоростная шина. Секретные инструкции недоступны пользовательким процессам, работа с ними только через систему. То есть это ничем не отличается от внешнего устройства типа GPGPU, но более эффективно за счет более тесной и более скоростной связи.

            Apple M1 chiplete


            1. Barabashkad
              09.07.2024 16:45
              +1

              есть разница между инструкцией с расширеным функционалом и акселератором расположеном на одной подложке.
              может быть разница не очень заметна но она есть.

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

              как реализовано у Apple я не знаю, они предоставляют высокоурвневые API из которых точно не возможно понять детали без дизассемблирования кода.
              так же Neural Engine наверное выполняет больше функций чем просто AMX
              я предпопагаю что там так же армовские ядра типа Cortex Mx с различными акселераторами
              и да именно тесная интеграция и использование одних кешей позволяет им добиться лучшей производительности
              но это точно также верно и для AMX.

              вот другой примет NEON у ARM
              только у RISC части есть instruction fetch и decode
              кооторый используеться для всех инструкций в том числе NEONoвских
              но разных частей процессора dаже разные длины конвееров
              у RISC - 13
              у NEON - 10
              и на самом деле NEON это DSP aксселератор тестно интегрированый в процессор
              https://en.wikipedia.org/wiki/ARM_Cortex-A8
              на 3тей странице картинка
              https://web.archive.org/web/20150101062932/http://www.arm.com/files/pdf/A8_Paper.pdf


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

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







              1. checkpoint
                09.07.2024 16:45

                есть разница между инструкцией с расширеным функционалом и акселератором расположеном на одной подложке.
                может быть разница не очень заметна но она есть.

                Разумеется. Об этом чуть ниже.

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

                Наличие отдельной инструкции в вычислительном ядре далеко не означает, что аппаратная часть её реализующая должа быть тесно интегрирована в это ядро. Вспомните математческий сопроцессор i387 - это отдельный рядом стоящий камень, тем не менее инструкции для работы с ним были внедрены в центральный процессор i386. Однако такое расположение дел создавало массу неприятностей для многозадачных операционных систем, так как приложение должно было вызывать инструкцию fwait для ожидания завершения работы мат сопроцессора, а это ставило на паузу весь праздник.

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

                Где баланс и как лучше - вопрос открытый. Собсно мой первый вопрос к автору статьи как бы намекал на это - рассказать нам про пропроблемы тех и других вариантов, что является наименьшим злом и в каких случаях. :-)

                ну и ... основная разница между RISC и CISC это размер машинной инструкции у риска она посноянная у сиска переменная все остальны различия и особенности вытикают только из этой особенности

                Боюсь Вас наглым образом обманули. :-) Размер машинного слова имеет третьестепенное значение для идеологии RISC процессора. Да, так оказалось, что при фиксированной ширине машинного слова декодер получается проще и быстрее. Основное же в RISC это обьем выполняемой работы за одну инструкцию - чем её меньше, тем более рисковый процессор. Отсюда вытекает второй идеологический постулат - система команд должна быть ортогональной, то есть не содержать команд выполняющих дублирующие функции, даже частично. Третий идеологический постулат RISC - ширина одной ступени конвейера должена быть как можно уже, то есть занимать минимально возможное время на свою работу (иными словами, критическая длина цепочки логических элементов в составе одной ступени долна быть минимальной). В теории это должно позволять поднимать тактовую частоту до немыслимых высот. Появление RISC процессоров в десятки раз подняло тактовую частоту к середине 90-х и то была настоящая революция! Однако, уже в конце 90-х в RISC процессоры начали наталкивать всякого рода SIMD и векторные инструкции (UltraSPARC, MIPS, позже ARM со своим Neon). Это существенно увеличило обьем выполняемой работы за такт, как следствие - ступени конвейера стали тяжелыми, их стало много, рост тактовой частоты затормозился несмотря на постоянный прогресс в литографии и увеличении плотности кристалла. Появления ускоряющих инструкций это полное отречение от идеологии RISC! Именно по этому ARM уже давно не является RISC процессором, не смотря на название. :)

                Меня давно мучает вопрос - какова могла бы быть максимальная тактовая частота ядра RV32IMFC выполненного по современным технологическим нормам (скажем, 3нм). Что-то мне подсказывает, что планка в 10ГГц была бы легко преодолена. И тут стоит вопрос - а может быть послать в гнездо все эти акселераторы ? Может процессор с очень простыми ядрами работающими на 10ГГц и со сверхмассовым их количеством это гораздо более интересное и производительно решение ? Помоему Nvidia двигается как раз этим путем и как мы видим - весьма преуспела.

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

                Полностью согласен, даже более того. У меня есть мнение, что у Интела нет шансов кроме одного - быстро пересесть в уходящий поезд RISC-V. То есть использовать свою высокопроизводительную супескалярную ОоО микроархитектуру, но заменить систему команд на RISC-V - тем самым послав подальше всё легаси и освободив место на кристалле под еще большее число ядер и кэша. Или для матричного вычислителя. :-)


                1. Barabashkad
                  09.07.2024 16:45
                  +1

                  на счет RISCa все вы правильно описали
                  но все это следствие фиксированой длины команды
                  которая ограничела набор команд
                  и заставила выбрать только простые и элементарные
                  которые в свою очередь требуют меньше транзисторов
                  фиксированый размер дал возможность уменьшитьшину адрессов для команд ... не намного, а 1,2 (сегодня на 3) разряда
                  но это относительно длиные пути в чипе
                  а максимальная частота чипа ограничиваеться самым длинным соеденением задействованым в процессе.
                  по той же причине
                  удлиняют конвеер, разбивают на простые этапы что бы уменьшить схему и сократить пути.
                  первые армы были с 3мя этапами, потом долгое время с 5ю
                  теперь 13 ...
                  кстти у этого подхода есть недостатки :-) вспомним чем 21 (кажеться)этапный обернулся для П4 ...
                  и более современные проблемы с предзагрузкой команд.

                  Интел давно уже внутри работает как RISC и запускает микрокод.
                  а его попытка с Itanium ... долго низенько летела , но взлетела ...

                  я так же имел дело с Xeon Phy , первой версии на отдельной карте
                  отличный был процессор
                  было много энтузиазма вокруг нео
                  с некоторыми упрощениями
                  можно сказать это был массив Atom ядер каждое из которых поддерживало Hyperthreading
                  если я не ошибаюсь у меня была версия с 64 или 128 ядрами
                  каждый был самостоятелным, на каждом бежал х86 код ...
                  но ... они не завезли туда (в целях экономии) ни ММХ ни SSE
                  и все , мир не принял :-)
                  (как и фирма где я работал)
                  недают Интелу слезть с их наборов инструкций
                  его берут только для совместимости
                  как с существуюшим софтом так и знаниями програмистов :-)
                  вот смениться поколениЯ :-) и все интелу крышка


    1. byman
      09.07.2024 16:45

      Во многих решениях векторный или матричный ускоритель работает сразу с L2, без нагрузки на L1. Это позволяет использовать широкую шину данных для загрузки-сохранения. В RISC-V расширения с собственным набором регистров имеют отдельный флаг использования. Якобы это может позволить сократить время переключения контекста. На мой взгляд, отдельный вычислитель нужен если реально нужна высокая скорость. А если просто побаловаться, то можно и в процессор расширение :)


      1. valeriaP Автор
        09.07.2024 16:45
        +1

        Даже для высокой скорости не всегда нужен отдельный вычислитель: в свежем июньском Top500 далеко не все машины гетерогенные, тот же Fujitsu Fugaku (ядра A64FX) до сих пор находится в топ-5. В инфографике можно посмотреть сравнение c ускорителями, правда 2021 г., но интересно.


        1. checkpoint
          09.07.2024 16:45

          Даже для высокой скорости не всегда нужен отдельный вычислитель

          Валерия, разверните пожалуйста мысль по подробнее. Что Вы имеете в виду ?


          1. valeriaP Автор
            09.07.2024 16:45

            просто цитата из комментария выше


      1. checkpoint
        09.07.2024 16:45

        А если просто побаловаться, то можно и в процессор расширение :)

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

        Как вариант, сделать так, чтобы инструкции матрично-векторных расширений не были доступны пользовательскому уровню (в терминах RISC-V - только для Supervisor mode), а взаимодействие происходило бы через ядро операционной системы, т.е. через отдельный syscall. В этом случае сохранять каждый раз состояние огромного векторно-матричного регистрового файла при переключении контекста не потребуется, его нужно будет сохранять и восстанавливать только при выполнении пользователем syscall-а (либо сделать доступ атомарным). Фактически, работа с векторно-матричным ускорителем превращается в работу с отдельным "виртуальным" устройством через стандартный API операционной системы. Если немного подумать, то становится понятно, что такое устройство надо вынести в отдельный кусок железа за переделы вычислительного ядра и таким образом мы получаем GPGPU.


    1. event1
      09.07.2024 16:45
      +1

      Thus, Linux implements on-demand expansion of per-task context switch buffers using an XSAVE feature: eXtended Feature Disabling (XFD). The kernel arms XFD to provide an #NM exception upon a tasks' first access to TILE state. The kernel exception handler allocates and installs the appropriate XSAVE context switch buffer. User space is unaware of the kernel's contexts switch buffer optimization.

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


      1. checkpoint
        09.07.2024 16:45

        Интересное решение, спасибо.

        И там делее по тексту:

        AMX is accessible only to applications that invoke a new system call to request access. When a user invokes this system call, they agree that if they use an alternate signal stack, that they are providing an alternative signal stack of sufficient size. The simplest way to do that is to use the updated ABI in glibc 2.34 or later [8][9], though they could Also use their own calculation or ask the kernel directly [3].

        То есть без отдельного syscall-а не обошлось, приложение обязано спрашивать систему разрешенея всякий раз когда оно хочет поработать с AMX. Система при этом резервирует от 8К до 64К на процесс для сохранения контекста AMX .


    1. ErmIg
      09.07.2024 16:45
      +1

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


  1. Limansky
    09.07.2024 16:45
    +3

    Где-то я это уже видел, я конечно далёк от всей этой красоты, но статья прекрасная. Большое спасибо за труды, за статью, продолжайте. И конечно же успешного развития этой тематики и физической реализации!


  1. event1
    09.07.2024 16:45
    +1

    Простите за возможно глупый вопрос, но если расширение умножает матрицы 16х16, а мне нужно перемножить 512х512, то как это сделать? Нужны же целые строки и столбцы.


    1. valeriaP Автор
      09.07.2024 16:45
      +4

      Отличный вопрос, если какие-то математические детали неясны -- не стесняйтесь спрашивать!

      В начале статьи кратко были описаны идеи многоуровневого блокирования из статьи Goto&Geijn: большие матрицы в несколько этапов разбиваются на маленькие блоки. И вы аккумулируете результаты умножения этих блоков. Ведь что такое элемент матрицы-произведения? Это сумма произведений элементов строки первого сомножителя на соответствующие элементы столбца второго сомножители. А раз это сумма, то вы можете просуммировать не все сразу, а частями -- идя по подстрокам и подстолбцам.

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


    1. ErmIg
      09.07.2024 16:45
      +1

      Если интересует практика использования AMX и как его применять для реального умножения матриц, то могу порекомендовать: https://habr.com/ru/articles/807033/