Я собрал сервер на нескольких CMP 90HX (если интересно - статья об этом тоже есть на аккаунте) и сначала ожидал от него простой логики: видеокарт много, суммарной видеопамяти много, потребление серьёзное, чип семейства Ampere - значит, большие языковые модели должны работать быстро. На практике dense-модели, где при каждом шаге работает вся сеть целиком, оказались заметно медленнее, чем ожидалось. Более-менее нормально выглядели в основном MoE-модели, где при каждом токене активируется не вся модель, а только выбранные экспертные блоки.

На первом этапе это легко списать на обычные проблемы локального запуска LLM: не тот квант, маленький батч, плохой сплит по видеокартам, слабая производительность центрального процессора на одно ядро, узкое место PCI Express, неудачный вычислительный бэкенд или кривая сборка llama.cpp. Всё это действительно влияет. Но в случае CMP90HX была причина глубже: карта избирательно ограничена по типам вычислений.

CMP 90HX - это не обычная RTX без видеовыхода. Это майнинговая карта линейки NVIDIA Crypto Mining Processor. NVIDIA указывала для 90HX 86 MH/s на Ethereum-классе нагрузки, 320 Вт потребления и 10 ГБ памяти; то есть сама линейка была рассчитана на майнинг, а не на универсальные вычисления, LLM или научные расчёты.

Исходную методику снятия ограничения я оставляю за китайским автором pearlfortune. Именно он придумал способ модификации драйвера для увеличения производительности этих карт. Моя задача - не приписывать себе сам принцип, а понять механику, разложить её понятным (насколько это возможно) языком, воспроизвести на своём сервере и проверить результат. Сразу скажу статья не является руководством - здесь только теория как я сам ее понимаю, и результаты моих исследований по применению метода.

И при чём же тут 67?

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

Сначала про модели: почему MoE ещё терпимо, а dense сразу показывает правду

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

Упрощённо:

токен 1 → слой 1 → слой 2 → слой 3 → ... → слой N

токен 2 → слой 1 → слой 2 → слой 3 → ... → слой N

токен 3 → слой 1 → слой 2 → слой 3 → ... → слой N

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

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

токен 1 → общие слои → эксперт 2 + эксперт 7

токен 2 → общие слои → эксперт 1 + эксперт 5

токен 3 → общие слои → эксперт 3 + эксперт 8

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

Два разных этапа работы LLM

У LLM есть две разные скорости.

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

Пример: я вставил в запрос большой технический документ. Модель ещё ничего не написала, но уже должна обработать весь вход. Если prefill медленный, я долго жду первое слово.

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

Пример:

5 токенов/с  - медленно;

15 токенов/с - терпимо;

30 токенов/с - уже похоже на нормальную интерактивную работу.

Эти этапы нагружают карту по-разному.

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

Decode - это повторяющийся цикл: прочитать веса, посчитать следующий токен, обновить внутреннее состояние, повторить. Здесь сильнее проявляются скорость чтения из видеопамяти, эффективность квантованных вычислительных ядер и распределение модели по нескольким картам.

Поэтому в тестах важно их разделять.

Что физически считает LLM

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

Главная операция - скалярное произведение:

результат = a1×b1 + a2×b2 + a3×b3 + ... + an×bn

В реальной модели таких операций не три, а миллиарды. Они выполняются в слоях внимания, в проекциях, в нормализациях и при каждом новом токене.

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

Теперь надо последовательно разобрать, какие блоки есть внутри видеокарты.

Как устроена видеокарта как вычислительное устройство

Упрощённо видеокарта с точки зрения LLM состоит из нескольких уровней.

Первый уровень - видеопамять. Там лежат веса модели, кэш внимания и промежуточные данные.

Второй уровень - контроллеры памяти. Они читают и пишут данные из видеопамяти.

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

Четвёртый уровень - вычислительные кластеры. У NVIDIA крупный вычислительный блок называется SM, потоковый мультипроцессор. Именно в SM исполняются потоки вычислительных программ.

Пятый уровень - внутренности SM. Внутри одного SM есть:

  • планировщики инструкций;

  • регистровый файл;

  • блоки вещественной арифметики;

  • блоки целочисленной арифметики;

  • матричные ускорители;

  • блоки загрузки и сохранения данных;

  • локальная разделяемая память;

  • локальные кэши.

Если представить GPU как завод, то видеопамять - это склад, контроллеры памяти - транспорт со склада, L2-кэш – стеллажи в цехах, SM - отдельные цеха, а исполнительные блоки внутри SM - конкретные станки.

Модель работает так:

  • видеопамять хранит веса;

  • контроллеры памяти доставляют веса ближе к вычислителям;

  • кэши пытаются удержать часто используемые данные;

  • SM выполняют инструкции;

  • регистры держат текущие промежуточные числа;

  • планировщики отправляют инструкции на нужные блоки.

 

Что такое поток, варп и планировщик

Один поток - это маленький исполнительный контекст: он знает, какие данные ему взять, какую инструкцию выполнить и куда положить результат.

Потоки группируются в варпы. У NVIDIA варп обычно состоит из 32 потоков. Планировщик внутри SM выдаёт инструкцию сразу группе потоков. Это не совсем как центральный процессор, где одно ядро исполняет одну последовательную инструкцию за другой. GPU рассчитан на массовый параллелизм.

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

Но всё упирается в планировщик инструкций. Планировщик решает, какую инструкцию сейчас отправить на исполнение.

Нормальный режим:

такт 1: выдать FFMA;

такт 2: выдать FFMA;

такт 3: выдать FFMA;

такт 4: выдать FFMA.

Ограниченный режим:

такт 1: выдать FFMA;

такт 2: пауза;

такт 3: пауза;

такт 4: пауза;

такт 5: выдать FFMA.

Физический блок есть, но работу ему дают редко. Это как станок, который умеет делать 100 деталей в минуту, но мастер выдаёт ему задание только раз в несколько секунд.

Именно так выглядит смысл ограничения CMP 90HX: часть вычислительных путей физически существует, но штатно работает не на полной скорости.

Почему майнинговая карта ограничена именно так

Для майнинга Ethereum-класса главную роль играла видеопамять: объём, пропускная способность и работа с большим набором данных. Полная FP32-производительность, быстрые INT8-скалярные произведения и матричные ускорители для ИИ майнингу не нужны.

Смысл ограничения CMP 90HX, скорее всего, был в сегментации продукта. NVIDIA выпускала эти карты как специализированные устройства для майнинга: им нужна была высокая пропускная способность памяти и достаточная эффективность на майнинговых алгоритмах, но не полноценная производительность в играх, рендере, научных расчётах и нейросетях. Если бы CMP 90HX работала как обычная RTX-карта на том же кристалле, после падения интереса к майнингу она стала бы дешёвой заменой игровым и профессиональным ускорителям. Поэтому карту оставили пригодной для целевой задачи, но ограничили те вычислительные пути, которые важны для универсальных нагрузок: FP32, INT-скалярные произведения, матричные операции и связанные с ними режимы выдачи инструкций.Поэтому карта может быть хорошей для майнинга и плохой для LLM.

Как команда от LLM доходит до железа

Когда я запускаю LLM, путь команды примерно такой:

сервер модели или llama.cpp

  ↓

вычислительный бэкенд

  ↓

пользовательская часть драйвера

  ↓

модуль ядра nvidia.ko

  ↓

очереди команд GPU

  ↓

планировщики внутри GPU

  ↓

SM

  ↓

исполнительные блоки

llama.cpp или другой сервер модели не говорит видеокарте: «посчитай нейросеть». Он запускает вычислительные ядра. Ядро делает конкретную работу: например, умножает матрицы, де-квантизует веса, считает внимание или нормализацию.

Эти ядра превращаются в низкоуровневые инструкции GPU. Например:

  • вещественное умножение с накоплением → FFMA;

  • целочисленное скалярное произведение → DP4A;

  • целочисленное умножение с прибавлением → IMAD;

  • операции над двумя FP16 сразу → HFMA2;

  • матричные операции → HMMA/IMMA-подобные пути.

Если обычная RTX-карта видит такие инструкции, она исполняет их с нормальной скоростью. Если CMP 90HX запущена в ограниченном режиме, часть этих инструкций поддерживается, но выдаётся на исполнение реже. Далее разберем типы данных и вычислений.

FP32 и FFMA

FP32 - это 32-битное вещественное число. Оно используется для обычной численной математики.

Ключевая инструкция - FFMA, вещественное умножение с накоплением:

d = a × b + c

В нейросетях такая операция встречается постоянно. Матричное умножение - это огромное количество операций «умножить и прибавить».

Даже если модель квантована, FP32 всё равно может появляться в промежуточной арифметике. Например, вес хранится в сжатом виде, а перед использованием масштабируется.

Потом этот вес участвует в накоплении:

сумма = сумма + активация × реальный_вес

Если FP32-путь ограничен, всё, что использует такие операции, начинает тормозить.

INT8, DP4A и квантованные модели

Квантованные модели хранят веса компактно. Например, Q4 использует 4 бита на вес вместо 32 бит, получается экономия примерно в 8 раз.

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

Для этого полезна инструкция DP4A. Она берёт четыре пары 8-битных целых чисел, перемножает их и прибавляет сумму к накопителю:

acc = acc

    + a0×b0

    + a1×b1

    + a2×b2

    + a3×b3

На обычной Ampere-карте это хороший путь для квантованных вычислений. На CMP 90HX этот путь проблемный: инструкция есть, но её скорость ограничена. Поэтому обычная оптимизация становится ловушкой. Библиотека выбирает DP4A, потому что для нормальной карты это правильно, а CMP 90HX исполняет этот путь медленно.

IMAD как программный объезд

IMAD - это целочисленное умножение с прибавлением:

d = a × b + c

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

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

FP16, half2 и HFMA2

FP16 - это 16-битное вещественное число. Оно менее точное, чем FP32, зато занимает меньше места и может считаться быстрее.

FP32: 1.2345678

FP16: примерно 1.234

half2 - это упаковка двух FP16-чисел в один 32-битный регистр.

Инструкция HFMA2 делает две операции умножения с накоплением сразу:

d0 = a0×b0 + c0

d1 = a1×b1 + c1

Если FP32 FFMA ограничена, часть вычислений можно перенести на HFMA2. Это может ускорить конкретное вычислительное ядро, но снова остаётся обходом. Причина ограничения не убрана.

Матричные ускорители и почему prefill особенно страдает

У современных NVIDIA-карт есть матричные ускорители. Их задача - быстро выполнять маленькие матричные умножения.

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

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

Еще раз - почему программных обходов недостаточно

Можно переписать вычислительные ядра:

  • DP4A заменить на IMAD;

  • FFMA заменить на HFMA2;

  • подобрать другой путь для квантов;

  • избегать отдельных матричных маршрутов.

Это может дать прирост. Но проблема остаётся ниже:

  • карта всё ещё ограничена;

  • другая программа снова выберет медленный путь;

  • стандартные библиотеки автоматически быстрыми не станут;

  • prefill может остаться слабым;

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

Что такое внутренний служебный процессор видеокарты

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

У NVIDIA один из таких служебных процессоров называется Graphics System Processor. Это внутренний процессор графической карты, который участвует в управлении GPU и работает вместе с драйвером.

Рядом с этим встречается слово Falcon - это семейство внутренних микроконтроллеров NVIDIA. Их можно воспринимать как маленькие GSP внутри GPU, которые исполняют внутренний код: загрузчики, проверки, подготовку защищённых областей и другие низкоуровневые задачи.

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

Как драйвер общается с внутренним процессором

Драйвер общается с внутренним процессором не текстовыми командами. Всё делается через память и регистры.

Типовая схема такая:

1. Драйвер выделяет область памяти.

2. Драйвер кладёт туда служебные данные.

3. Драйвер передаёт карте адрес этой области.

4. Драйвер записывает аргументы в специальные регистры обмена.

5. Драйвер запускает внутренний процессор.

6. Внутренний процессор читает данные.

7. Внутренний процессор выполняет служебный код.

8. Драйвер читает результат из регистров состояния.

Регистры обмена часто называют mailbox-регистрами. Это буквально «почтовые ящики» между драйвером и внутренним процессором.

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

Что такое PLM

В этой истории ключевой «замок» называется FEAT_OVR_PLM.

PLM можно понимать как маску уровней привилегий. Она определяет, доступна ли запись в определённую группу защищённых регистров.

Адрес нужной маски:

FEAT_OVR_PLM = 0x00823804

Закрытое состояние:

0xFFFFFF8F

Открытое состояние:

0xFFFFFFFF

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

PLM - замок;

SS0 и SS1 - переключатели внутри шкафа.

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

В проверочных данных проекта видно именно это: PLM переходит из закрытого состояния 0xffffff8f в открытое 0xffffffff.

Что такое SS0 и SS1

Финальная цель - два селектора вычислительного режима:

SS0 = 0x0082381C

SS1 = 0x00823820

Значения полного режима:

SS0 = 0x88888888

SS1 = 0x00000008

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

Что такое внутренний загрузчик

Когда GSP запускается, ему нужен служебный код, который подготавливает дальнейшую загрузку. Такой внутренний загрузчик называют Booter. Он участвует в подготовке GSP/RM, где RM - это ресурсный менеджер, то есть внутренняя логика управления ресурсами карты.

Обычный путь:

  • драйвер подготовил штатные данные;

  • драйвер запустил Booter;

  • Booter обработал штатные данные;

  • GSP продолжил загрузку;

  • карта стартовала обычным CMP-режимом.

Нужный путь:

  • драйвер временно подсовывает Booter специальный буфер;

  • Booter обрабатывает этот буфер;

  • открывается PLM;

  • штатный буфер возвращается;

  • карта перезапускается нормально.

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

Во время запуска Booter драйвер передаёт ему служебную область подписи. В коде она проходит как pSignatureMemdesc.

Сначала надо разобрать слово memdesc.

memdesc - это описание области памяти. Это не сами данные, а структура:

  • где лежит буфер;

  • какого он размера;

  • как получить его адрес;

  • как передать его устройству.

Аналогия: сам документ лежит в архиве, а карточка в каталоге говорит, в какой папке и на какой полке он находится. memdesc - это такая карточка для области памяти.

Как именно происходит инъекция

Последовательно:

1. Драйвер доходит до стадии запуска внутреннего служебного процессора.

2. Ранний запуск служебного процессора проходит успешно.

3. Драйвер сохраняет штатный pSignatureMemdesc.

4. Драйвер создаёт временную область памяти.

5. В эту область кладётся V67-цепочка.

6. Драйвер временно переключает pSignatureMemdesc на V67-область.

7. Booter стартует и читает уже V67-область.

8. В результате открывается FEAT_OVR_PLM.

9. Драйвер видит, что PLM стал 0xffffffff.

10. Драйвер возвращает штатный pSignatureMemdesc.

Почему момент после раннего запуска так важен

Нельзя подменить данные когда угодно.

Если сделать это в неудачное время, ранние проверки прошивки и защищённой памяти могут отвергнуть изменение.

Поэтому нужен промежуток:

  • ранний служебный процессор уже поднялся;

  • Booter ещё будет использовать область подписи;

  • PLM ещё можно открыть через привилегированный контекст.

Возврат штатной подписи

После открытия PLM V67-область больше не нужна. Более того, её нельзя оставлять. Карта должна продолжить нормальный запуск со штатными служебными структурами.

Поэтому драйвер делает обратную операцию:

  • берёт сохранённый штатный pSignatureMemdesc;

  • возвращает его на место;

  • обновляет служебные адреса и размеры;

  • освобождает временную V67-область;

  • очищает временное состояние.

Это важно: процедура не живёт постоянно на подменённой подписи. V67 используется как одноразовый служебный ключ.

Полная механика одной цепочкой

  • Карта определяется как CMP 90HX. У неё есть физически интересный вычислительный потенциал, но штатно она стартует с ограниченными вычислительными путями – искусственно задушенными некоторыми типами вычислений, полезных для LLM.

  • Полный режим задаётся селекторами SS0 и SS1.

  • Эти селекторы защищены маской FEAT_OVR_PLM.

  • Пока PLM закрыт, поздняя запись SS0/SS1 не работает.

  • Открыть PLM можно в раннем привилегированном этапе загрузки через внутренний Booter.

  • Для этого драйвер ждёт ранний успешный старт служебного процессора.

  • Затем драйвер сохраняет штатную область подписи.

  • После этого драйвер временно подменяет pSignatureMemdesc на V67-область.

  • Booter обрабатывает V67-область.

  • V67 приводит к открытию:

FEAT_OVR_PLM = 0xffffffff

  • Драйвер видит, что PLM открыт.

  • Драйвер возвращает штатную область подписи.

  • Драйвер записывает:

SS1 = 0x00000008

SS0 = 0x88888888

  • Драйвер читает значения назад и проверяет, что они применились.

  • Драйвер инициирует FLR.

  • Первый запуск завершается как служебный проход.

  • Драйвер повторяет nv_start_device.

  • Карта проходит штатный запуск уже с полными вычислительными селекторами.

  • Если карт несколько, процедура выполняется по одной карте за раз

Практический опыт применения

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

Этап 1 - исходные замеры до любых изменений

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

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

Для проверки использовались две модели разного типа.

До изменений скорость была примерно такой:

=== Summary ===

moe / fredrezones55/Qwen3.6-35B-A3B-Uncensored-HauhauCS-Aggressive:Q4

short: gen_avg=42.43 tok/s, prompt_avg=127.10 tok/s

medium: gen_avg=42.28 tok/s, prompt_avg=212.30 tok/s

code: gen_avg=42.26 tok/s, prompt_avg=236.52 tok/s

dense / gemma4:e4b

short: gen_avg=23.98 tok/s, prompt_avg=259.66 tok/s

medium: gen_avg=23.26 tok/s, prompt_avg=449.38 tok/s

code: gen_avg=23.34 tok/s, prompt_avg=479.15 tok/s

Эти цифры стали точкой отсчёта. Все дальнейшие результаты сравнивались именно с ними.

Этап 2 - установка нужной версии драйвера

Следующим этапом был драйвер NVIDIA. Для V67 важны конкретная версия драйвера и тип модуля ядра.

Был выбран NVIDIA 610.43.03 – именно его рекомендует китаец.

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

После переустановки драйвера был повторён тест скорости. Результаты почти не изменились: MoE-модель осталась около 42 токенов в секунду, плотная модель осталась около 23 токенов в секунду.

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

Этап 3 - первая попытка временной разблокировки V67 при помощи утилиты

После установки нужного драйвера была выполнена первая попытка временной разблокировки V67 (только до перезагрузки).

На этом этапе утилита отказалась продолжать работу. Причина была в версии ядра Linux.

Внутри утилиты уже был готовый модифицированный модуль для CMP 90HX, но он был рассчитан на другую систему: драйвер 610.43.03 и ядро 6.10.0-hiveos. У нас драйвер уже был правильный, но ядро было обычное Ubuntu - 5.15.0-187-generic.

Для обычной программы такая разница не всегда критична. Но для модуля ядра это принципиально. Модуль ядра собирается под конкретную версию ядра Linux. Если модуль собран под одно ядро, его нельзя просто взять и загрузить в другое ядро как обычный исполняемый файл.

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

В утилите такой файл называется candidate, но по смыслу это просто подготовленный вариант модуля nvidia.ko.

Этап 5 - сборка модуля под текущее ядро Ubuntu

Дальше был собран модифицированный модуль под конкретную связку:

драйвер NVIDIA - 610.43.03.

ядро Linux - 5.15.0-187-generic.

Для сборки использовались официальные исходники открытого модуля NVIDIA и набор файлов stockflow для CMP 90HX. Stockflow в данном случае - это механизм, который подготавливает изменённый вариант модуля NVIDIA для работы V67.

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

Этап 6 - временная разблокировка с собственным модулем

После сборки собственный модифицированный модуль был передан утилите V67 явно.

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

Результат оказался уже не похож на погрешность измерения.

MoE generation:

short: 42.37 → 71.98 tok/s +69.9%

medium: 42.16 → 71.60 tok/s +69.8%

code: 42.21 → 71.47 tok/s +69.3%

Dense generation:

short: 24.01 → 37.61 tok/s +56.6%

medium: 23.41 → 36.14 tok/s +54.4%

code: 23.35 → 36.01 tok/s +54.2%

MoE-модель выросла примерно с 42 до 72 токенов в секунду.

Dense модель выросла примерно с 23 до 36 токенов в секунду.

То есть прирост составил примерно 70 процентов для MoE-модели и примерно 55 процентов для плотной модели.

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

Итог

В итоге модификация V67 на CMP 90HX действительно сработала и дала заметный прирост в задачах запуска языковых моделей.

До применения V67 MoE-модель работала примерно на уровне 42 токенов в секунду, а плотная модель - примерно на уровне 23 токенов в секунду. После временной разблокировки скорость выросла примерно до 72 токенов в секунду для MoE и до 36 токенов в секунду для плотной модели. После установки постоянного варианта и перезагрузки результат сохранился: около 71 токена в секунду для MoE и около 36 токенов в секунду для плотной модели.

То есть прирост составил примерно 65-70 процентов для MoE-модели и примерно 50-55 процентов для плотной модели. Это слишком большая разница, чтобы списывать её на погрешность измерения или случайный разброс. Следующим шагом я хочу доработать распределение моделей по картам, и провести эксперимент с увеличением памяти одной карты.

Если нужен туториал - дайте знать, выложу отдельной статьей.

Ссылка на сам авторский репозиторий: github.com/pearlfortune/cmpunlocker

 

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


  1. UB3
    29.08.2026 21:39

    Очень интересное решение, с удовольствие прочту чего сможете выжать из этих карт, удачи вам!
    ps а как вообще, комфортно работать с нейронками, мне особенно интересно в плане работы с тем же Гермесом в частности.