Вход на сайт

Просмотр новости

Найдите то, что Вас интересует

Как я учил планировщик класть широкие команды для Эльбруса, и почему LLM проиграла жадному алгоритму за 3 миллисекунды

Дата публикации: 14-09-2026 13:43:17

Проще говоря, NEX CLI x Elbrus берет граф и модель e2k‑v6 и показывает: сколько насчитал жадный, сколько мог бы идеальный, и на какой операции и каком канале разница. Читать далее

Основное содержимое страницы с новостью.

Уровень сложностиСредний

Время на прочтение7 мин

Охват и читатели10K

Обзор

Что это за проект84da27e33c68bfc34f876023106d4001.png

Прототип к исследовательскому проекту «Планировщик инструкций для VLIW‑архитектур». Главный тезис:

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

Проще говоря, NEX CLI x Elbrus берет граф и модель e2k‑v6 и показывает: сколько насчитал жадный, сколько мог бы идеальный, и на какой операции и каком канале разница.

Зачем вообще трогать планирование под Эльбрус95f27e22eafffb5a95726d0a40b73b27.png

Эльбрус это VLIW. Нет развитого OoO, который на x86 прячет кривое расписание.

VLIW значит, что несколько операций склеиваются в одну широкую команду заранее, на этапе компиляции. Процессор их не переставляет сам.

  • MUL: каналы 0, 1, 3, 4. Готов через 4 такта.

  • DIV: только ,5. Готов через 11, следующее не раньше чем через 2 такта.

  • LOAD: 0, 2, 3, 5. Готов через 5.

  • STORE: только 2 и 5.

Ошибся тактом на делителе — встал пакет. Положил STORE не туда — заклинил ,5, который нужен и DIV, и части LOAD. Это должно быть видно статически.

python3 -m vliw run slotclash
# жадный: 23 такта, оптимум: 22. -1 такт = -4%.
# где жадный зевнул монопольный ,5?

memstream та же логика с другой стороны: 8 троек LOAD‑ADD‑STORE, каналов под запись два.

Цифры не из воздуха. Но я им сам не до конца верю

Числа в e2k-v6-measured сняты с настоящего lcc-1.29.16 кросс‑сборкой под e2k-v6 тремя независимыми приемами. Это написано в шапке репа vliw/core/model.py:

1. Матрица портов — спрошена у ассемблера, а не угадана по листингу.
Для каждой пары (операция, канал) собирается крошечный .s. Если так нельзя аппаратно — ассемблер отвечает прямым отказом: 'muls' cannot be encoded in ALC2. Это ответ про кодировку широкой команды, про само железо, а не про то, что решил планировщик lcc. Автомат этого — tools/probe_matrix.py.

2. Латентность — цепочкой зависимых. x = x * b пять раз подряд. Следующая обязана ждать предыдущую, компилятор вынужден развести их ровно на latency. Разница номеров bundle читается напрямую. Так намеряны MUL 4, DIV 11, LOAD 5.

3. Занятие порта — потоком независимых. 8–16 штук с готовыми операндами. Шаг между выдачами = темп устройства. Так намеряны DIV раз в 2 такта, MUL раз в такт.

А теперь детектив. (можете пропустить, это исследовательская глава)

Обожаю несмешно шутить

Обожаю несмешно шутить

Первая версия модели была неверна. Был probe.c — 4 деления + 4 умножения. Все muls легли в ,0 подряд. Я прочитал это как «умножитель один, держит порт 8 тактов». А потом проверка ассемблером показала: умножение исполнимо на четырех каналах, а поток из 16 независимых умножений идет по одному в такт. Четырех операций просто не хватило, чтобы у жадного планировщика lcc появился повод их раскидать.

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

Все это прогонялось потом десятками ИИ‑агентов для перепроверки пар, каналов, сочетаний. Нашли ровно два запрета сочетаний в одной широкой команде: STORE,2 + LOAD,3 и STORE,5 + LOAD,0 — швы между кластерами ,0,1,2 и ,3,4,5. Сверялись с официальным «Руководством по эффективному программированию на платформе Эльбрус» 1.2 — но числа оттуда в модель НЕ подставляли: там Е4С/Е8С, а тулчейн целится в v6. Это сверка, а не источник.

И все равно — я не считаю цифры паспортом:

  • живого железа у меня не было, SSH Эльбруса — мне лень с ним возится.

  • из 19 классов latency измерена у 9. Остальное — ASSUMED=1, список открыт в ISA.md;

  • LOAD 5 против 3 (L1 hit, L2 11, L3 40, память ~100) из доки МЦСТ — расхождение поколений(Я перепроверял, и цифры сходились с документацией 24 года);

  • occupancy склеивает занятость устройства и слота. div8.c меряет устройство (раз в 2 такта), а в fma_kernel.s fdivd,5@t19 + aaurwd,5@t20 — слот свободен раньше. Модель пессимистична сознательно.

Поэтому давайте честно: это лучшая доступная аппроксимация, а не даташит.

И здесь — оффер, ради которого статья и пишется. Это не вам нужен мой проект. Это мне нужны вы.

Если у вас есть живой e2k-v6 — прогоните цепочки из examples/probes/ (mul_latency.c, div_latency.c, load_latency.c, store_burst.c...). Пришлите листинги lcc -O3 -fverbose-asm. Закроем 13 допущений, сверим LOAD 5 vs 3, померяем межкластер. Без вас эта таблица так и останется «замерами по поведению компилятора».

ИИ‑арка: как Qwen на 2 ГБ пытался стать оптимизатором (Можете пропустить это исследовательская глава) f2dc86b6dd8900ef4afdac119b70467f.png

Сначала модель должна была писать расписание целиком: граф на вход, строки id: такт=.. канал=.. на выход. Qwen2.5–3B‑Instruct, QLoRA, GGUF 2.1 ГБ, ноутбук без GPU. Промпт один и тот же на обучение и запуск. Без маркера конца она не останавливалась и лила лишние id.

Датасет: пары граф → оптимум, только доказанные оракулом, размеры 6–14. Училась на коротких. Реальные куски 112–386 узлов.

Что вышло:

  • жадный на лёгких уже 298/300 и 300/300 в оптимуме. Выигрывать нечего. Модель на тот же ответ тратит десятки секунд;

  • с EOS на узком 97.7% валидных, на широком 32.7%. Почти все провалы — STORE на чужом канале. В датасете STORE не было;

  • на реале словарь на треть UNKNOWN, 0 из 13 лучше случайного перебора за то же время.

Как бухгалтер она медленная и хрупкая: 30 секунд за то, что эвристика делает за 3 мс, и 17% законных на трудных графах. Поэтому каналы у неё забрал алгоритм. Это CAB.

CAB: забираем у модели бухгалтерию, оставляем чутьеЛадно, это очень смешно

Ладно, это очень смешно

CAB — “портфель законных расписаний из одного ответа модели”. Второй этап SEED стоит на нем, но суть — в первом.

Идея из docs/DIAG3.md: модель отлично чувствует порядок, но тонет в бухгалтерии — 315 незаконных каналов, 208 конфликтов, 26 неготовых операндов. При этом из 98 законных ответов 97 были точным оптимумом. Значит — забираем бухгалтерию целиком.

Что берем у модели:

берем

как

что выбрасываем

порядок

сортировка по ее (такт,канал)priority

такты

как defer_until «не раньше»

каналы

не берем вообще

самая частая ошибка

Бухгалтерию ведет list_schedule из core/baseline.py — он по построению не выдаст раньше предков и не посадит двоих на канал. Расписание законно механизмом, а не удачей.

Дорогая здесь только генерация. Поэтому из одного ответа строим 5 кандидатов без лишних генераций: модель, модель+каналы (починка Куном), порядок, порядок+такты, жадный. Плюс те же 5 со второй генерации по грамматике GBNF. Побеждает min (makespan), при равенстве — ответ самой модели, чтобы не приписывать алгоритму чужое. Подпись в UI честная: CAB: <кандидат>.

Предсказание, записанное ДО замера, на slotclash с убитыми в ,0 каналами:

  • сырой — 22, но незаконно

  • жадный — 23

  • порядок — 23

  • порядок+такты — 22 = оптимум

Порядка мало, нужно еще «придержать» операцию у монопольного ,5. defer_until это возвращает.

Замер на трудном эвале, где у жадного наконец есть зазор (0/300 в оптимуме, разрыв 1.03):

  • жадный — 1.03, 0/300

  • модель + CAB — 0.82, 59/300 точно в оптимуме (62/300 после замера STORE=2)

  • вклад: порядок 25, модель 16, порядок+такты 13, модель+каналы 7. Итого 61/300 строго лучше жадного — 20% трудных графов.

Без CAB на тех же данных — 17% законных. С CAB — 100% по построению. Рост законных ничего не доказывает, доказывают 5 тактов на 30 и 60+ графов, отыгранные у доказанного оптимума.

SEED-1 (подсказка верхней границей в оракул) при этом мертв замером, а не мнением: даже идеальный оптимум экономит 5% узлов, потому что поиск идет снизу вверх и тратит все на провальные пробы. Платить 30с генерации за 5% от 30мс — бессмысленно. Оставили в коде, пригодится если поиск пойдет сверху вниз.

6. Где ИИ сейчас: не бухгалтер, а мини‑агент

И тут важный дисклеймер.

ИИ неэффективен только в моем сетапе. У меня нет мощностей гонять модели на сотни гигабайт — тысячегиговые монстры явно умнее моего Qwen на 2.5 ГБ. Суть не в том, что «ИИ бесполезен», а в том, что я откинул его на задний план.

Он в проекте есть. Он просто занимается фоновым:

  • поставляет порядок/такты для CAB,

  • помогает алгоритму как эвристика,

  • пересказывает код и панели человеческим языком поверх уже посчитанных ядром чисел,

  • перебирает детали в /doctor, /explain, /agent.

По сути я собрал агентного мини‑ИИ для Эльбруса на той же Qwen: один llama-server на unix‑socket, база — для чата, LoRA — для плана, офлайн‑фолбэк с детерминированным ответом, если весов нет. Ядро считает, модель формулирует… Живая заливка решетки токенами, trace для разбора, --raw/--pure для аудита.

Все

Исходный код прототипа
Веса LoRA

P. S. Это появилось после текста выше. Постановка сырая, в статью как готовый результат не входит.LLM расписание текстом больше не пишет. Вместо неё маленький MLP: десятки тысяч параметров, на выходе только скоры порядка для обычного list_schedule. Законность по построению, галлюцинировать нечему. Несколько кандидатов, ничья уходит жадному, хуже baseline портфель не отдаёт.На синтетике eval_hard (300 графов) пока так: средний разрыв до оптимума 0.27 такта против 0.97 у жадного, 219/300 в оптимуме, 203/300 строго лучше baseline, незаконных ноль, порядка 60 мс на граф. Это не живой код после lcc. На настоящих графах 112–386 узлов и большая модель, и крошка пока упираются в форму графа, не в порядок выдачи.Обкатал несколько сеток вчера, дальше застопорило. Сеть даже до 100k параметров не довели. Имеет смысл как смена вопроса: не «пусть LLM кладёт каналы», а «выучить эвристику порядка, не ломая правила машины». Доказательства, что так можно оптимизировать настоящий lcc, ещё нет.

Схожие новости

#Наименование новостиТональностьИнформативностьДата публикации
1Алгоритм был правильным. Ошибка была в контракте графа-17.5713-08-2026
2Как желание быстрее читать чужой код превратилось в войну с недетерминизмом LLM0528-06-2026
3habrGPT. Обучим LLM 0.5B с нуля на статьях Хабра с помощью nanochat от Карпатого. Обучение fp8 дома и сравнение с bf160508-07-2026
4А нам точно нужны code agents?0517-07-2026
5Будет ли self-hosted LLM производительнее, чем модель во внешнем контуре: сравниваем GLM, Claude и GPT010.6110-08-2026
6Когда контекстное окно кончается, а проект — нет5723-06-2026
7Книга: «LLM на практике. Большие языковые модели от идеи до внедрения»08.0118-08-2026
8Как оптимизировать инференс LLM: кеширование, время ответа и GPU-ресурсы011.508-07-2026
9Пишу алгоритм FFT на Си для процессора Эльбрус: прямая векторизация012.711-09-2026
10Промпты, RAG, LLM-тюнинг, Harness… Идём дальше?011.8711-06-2026

Классификация: Мнения. Схожих патентов: 0. Схожих новостей: 10. Тональность: 0. Информативность: 9.08. Источник: habr.com.