Одиннадцать наносекунд
1.
Новость про Atlassian он дочитал стоя у плиты, пока в турке поднималась пенка.
На матовом стекле телефона всё ещё висело вчерашнее обращение Майка Кэннона-Брукса. 1600 человек. Десять процентов. Текст был выверенный, гладкий, с той мягкой корпоративной пунктуацией, которая должна успокаивать. «Наш подход не в том, что ИИ заменяет людей. Но было бы лицемерием притворяться, что ИИ не меняет набор навыков…» Self-fund AI and enterprise sales.
Пенка дрогнула. Он снял турку с огня, подождал секунду, поставил обратно. Руки ещё помнили этот момент — когда можно снять и когда уже поздно.
Когда-то он так же ловил на стенде дурной режим: вентилятор процессора начинал дребезжать чуть иначе, дроссели тонко подпевали под нагрузкой, и становилось ясно, что цикл опять пошёл слишком плотно. Ещё немного — и всё начнёт сыпаться. Позже выяснялось, что DMA приходит не так, как обещала бумага. Тогда это значило, что цикл ещё можно сжать, если наплевать на чужие предупреждения. Теперь от того слуха осталась только турка.
Он смахнул текст.
На кухне было тихо. На подоконнике стоял кактус, переживший три переезда.
Сегодня он работал из дома. Завтра надо было ехать в офис, хотя это уже почти ничего не меняло. На гибриде там всякий раз сидели новые случайные люди, и он давно перестал понимать, с кем именно работает рядом.
Он налил кофе и разбудил ноутбук. Внешняя клавиатура привычно холодила пальцы.
Два ночных summary.
И один digest.
Зелёные метки. Красные флажки.
Телефон звякнул снова.
Не LinkedIn. Jira.
Owner confirmation required.
Тикет висел в системе, старый и в то же время новый. Внутренний сервис хранения событий — полумёртвый кусок легаси-кода. Пять лет назад он там чинил буферизацию. Потом его имя осело в мёртвом треде на Confluence. Теперь граф решил, что он владелец.
Он нажал Dispute ownership.
Окно выскочило сразу.
Hi. I can help resolve ownership ambiguity.
Три варианта. Подтвердить. Делегировать. Начать remediation flow.
Он не стал нажимать кнопки и вбил вручную:
Я не владелец. У меня нет к этому сервису ни команды, ни доступов, ни бюджета.
Ответ пришёл мгновенно.
Understood. As the current listed owner, you may not have all required permissions yet. I can help restore them.
Он вытер со стола каплю кофе и написал короче:
Вы путаете запись в графе и реальную ответственность.
На этот раз пауза была ровно такой длины, чтобы казаться вежливой.
I found a likely match for your issue: ownership-related access inconsistency. The fastest resolution is to accept temporary custodianship and proceed with remediation.
Он не стал отвечать. Рядом с клавиатурой лежала старая Moleskine. Чёрная, потёртая на углах. На последних страницах — выцветшие карандашные зубцы пометок: стрелки, мнемоники lnop, shufb, fma, циклы, записанные ёлочкой. Ритм, который когда-то удерживал шесть SPE между жалкими 256 килобайтами local store, шиной и люфтом по времени — его едва хватало, чтобы развести зависимые куски. Он помнил это уже не вполне головой, а пальцами. Компилятор тогда рвал цикл на части, а он собирал его заново, выравнивая пустоты, чтобы even и odd конвейеры хоть как-то дышали вместе.
Внизу чата всплыла новая строка.
Would you like me to generate a summary for your manager?
Он нажал Enter.
Сервис выплюнул гладкий абзац без единого угла: access inconsistency, legacy permissions drift, temporary custodianship. Всё было как будто верно — и всё было не по делу.
Со старым менеджером проблем бы не было. Можно было написать три строчки без дипломатии, и хватало. Но того осенью promoted outwards в очередной волне уплощения. Новый был в роли третий месяц; у него было 250 подчинённых, и иногда казалось, что он вообще ничего не печатает сам — только выбирает один из предложенных вариантов.
Он всё-таки переслал summary менеджеру.
Ответ прилетел быстро. Сначала реакция: большой палец вверх. Потом текст:
Looks reasonable. Can you take temp ownership so we unblock this? We can sort out the structure later.
Он посмотрел на later и закрыл чат.
Отбил коротко:
- Я не владелец.
- Временное владение создаст false state.
- Нужен ручной роутинг на Data Infra, а не remediation.
Менеджер больше не ответил.
Ответила система.
Conversation context has been attached to the case. Thanks for the clarification. Based on your bullets, I can offer a streamlined path…
Он ещё секунду смотрел на экран, не читая дальше, потом закрыл крышку ноутбука.
Мусоровоз лязгнул у тротуара. Звук был тяжёлый, уличный.
Он встал, вылил остывший кофе в раковину. Телефон лежал на столе экраном вниз. Он перевернул его — не из ожидания, а машинально, как переворачивают, чтобы проверить время.
Среди уведомлений сверху висело старое, ночное.
LinkedIn. Мел Хуанг.
Он видел его ещё часов в шесть, когда тянулся выключить будильник. Скользнул взглядом по имени, увидел под ним обрубок кода и положил телефон обратно лицом вниз. Решил: потом. Или никогда.
Теперь открыл.
Ни приветствия, ни текста. Фрагмент кода, вставленный прямо в сообщение, без рамок, как в старые времена, когда им обоим казалось, что это ещё нормальный способ разговаривать.
Почерк он узнал на третьей строке. Мел всегда писал жадно, быстро, чуть за гранью. Ещё в МИТе, когда они два семестра сидели рядом в лабе, Мел срезал углы и бросал: hardware won’t lie to us. Он потом молча вставлял страховки обратно. Лет пятнадцать спустя они столкнулись на GDC, неловко перебросились парой фраз у стенда, пообещали списаться и не списались. С тех пор — тишина.
И вот этот код. Тот же почерк, только суше и острее, на какой-то незнакомой узкой архитектуре с ручным движением данных. Мел опять жил в долг. Держал промежуточные данные в выходных буферах, рассчитывая, что они успеют осесть до следующего прохода. Там, где обычно ставят барьер, у него была вера в хорошее поведение железа. На бумаге это выглядело нагло. На спокойном железе — иногда сходило с рук.
Он провёл пальцем по экрану, вернулся на четыре строки вверх, ещё раз посмотрел на тот участок.
На третьем развороте цикла код уже тянулся за данными, которых там ещё не было.
Он увидел, как это вытащить. Не барьером в лоб, а ритмом: переставить распаковку и умножения так, чтобы железо успевало сделать свою работу до следующего чтения.
Под кодом была одна строчка:
Ты это всегда видел быстрее меня.
Он помедлил.
Ещё ниже:
Я тут недалеко. Если будет настроение — заезжай.
Интонация нарочито лёгкая. Не в этом дело.
Он поймал себя на том, что уже десять минут правит чужой код в голове. Положил телефон на стол. Встал. Постоял у окна.
Завтра — опенспейс с чужими людьми, ипотека, какой-то появившийся в последний момент all hands meeting. Надо просто проглотить обиду. Открыть крышку рабочего ноута, нажать эту чёртову кнопку временного владения и стать ещё одной записью в графе.
Он потянулся к холодному алюминию рабочей машины.
Телефон брякнул.
Jira.
To protect your resolution metrics and prevent workflow blockage,
temporary custodianship has been provisionally accepted on your behalf.
Have a productive day!
Рука замерла в дюйме от крышки.
Он глубоко вдохнул. Сосчитал до пяти. Выдохнул. Ещё раз прочитал строку.
Если он сейчас откроет рабочий ноутбук, ничего не сломается. Вот что было хуже всего.
Он посмотрел на телефон. На LinkedIn. На строчку Мела.
Если будет настроение — заезжай.
Он сунул Moleskine в карман куртки. Рабочий ноутбук оставил на столе.
Навигатор вёл на юг. За полосой мелких сервисов город терял лицо. Бетонные коробки, погрузочные доки, глухие железные ворота. Адрес привёл к длинному одноэтажному зданию без вывески — бывший офис чего-то, что не взлетело.
Он заглушил мотор. Телефон завибрировал.
Мел: Серая дверь, сбоку. Открыто.
2.
Серая дверь и правда была открыта.
За ней тянулся короткий коридор с бетонным полом. Верхний свет бил плоско и ровно — ни теней, ни углов. Глаза после калифорнийского белого утра привыкали медленно, и всё выглядело как чуть пересвеченная фотография.
В конце коридора ждал Мел.
Он постарел не резко, а буднично: подсох, осунулся, у висков проступила седина. Но в этом плоском свете всё читалось жёстче — как будто с лица убрали лишний слой, и осталась только кость и натянутая кожа. Стоял, чуть подавшись вперёд, будто уже собирался идти дальше.
— Привет, — сказал Мел.
— Привет.
Они постояли секунду.
— Спасибо, что приехал.
— Сам не ожидал.
Мел кивнул, как будто именно такого ответа и ждал.
— Извини за LinkedIn.
— Нормальный защищённый канал. Особенно между open to work и grateful for the journey.
У Мела дёрнулся угол рта.
— Пойдём.
Внутри бывший офис был перегорожен чёрными матовыми панелями. Пахло озоном, перегретым текстолитом, старой пылью от вентиляторов и чем-то мясным, тяжёлым. Вентиляторы охлаждения тянули одну ровную ноту — не громкую, но плотную, забивающую мелкие звуки. Через минуту он перестал её слышать. Осталась только поверхность: голоса, щелчки реле, своё дыхание.
У дальнего стола сидела женщина в тёмной майке. Перед ней — три экрана, осциллограф и логический анализатор, настроенный на что-то очень быстрое. За правым ухом у неё шла тонкая линия, которую он в первый момент принял за падающую прядь. Потом понял — оптический шнур, матовый, уходящий к терминалу. Она подняла глаза, коротко посмотрела на Мела, потом на него. Он ничего не спросил.
— Нора, — сказала она.
Посмотрела на Мела.
— Это он?
— Он самый, — сказал Мел.
Чуть поодаль, у стены, стоял человек в простой тёмной куртке и ел что-то из бумажного лотка маленькой пластиковой вилкой. От лотка несло твёрдокопчёной колбасой — густой, неуместный кухонный запах в стерильном электрическом воздухе.
— У нас тут и так горелым тянет, — сказала Нора, не отрываясь от экрана.
— Значит, живём, — сказал человек у стены.
И продолжил есть.
Мел кивнул на стойку.
На столе — плата размером с толстый журнал во временном стальном каркасе, блоки питания, кабели, телеметрия. Под столом — приземистый металлический ящик с жёлтыми наклейками и силовыми проводами в палец толщиной.
На отдельном экране был код. Архитектура была незнакомая, но религия узнавалась сразу: узкие векторные ядра, ручное движение данных, крошечный запас по времени. Никаких подарков от компилятора.
— Сырые счётчики покажи, — сказал он.
— Сначала контекст, — сказала Нора. — Тут три дня работы, которые ты не видел.
— Контекст я прочитаю по сырым.
Мел чуть качнул головой в её сторону.
— Покажи.
Нора помолчала. Потом убрала красивую картинку. Пальцы на клавиатуре двигались быстро.
На экране стало грязнее, но больше похоже на правду.
— Видимых ядер сколько? — спросил он.
— Восемь, — ответил Мел.
Он поднял глаза.
— Видимых для моего кода.
Мел прищурился.
— Шесть с половиной. Седьмое жрёт прерывания, на восьмом битый кэш.
Он стоял за плечом Норы. Она показывала трассу, счётчики, графики. Переключала окна, прокручивала код на отдельном экране. В какой-то момент он потянулся к стеклу.
— Покажи вот отсюда. Вверх, к началу развёртки.
Нора прокрутила. Не туда.
— Выше. К заголовку модуля.
Ещё. Опять не то.
— Дай я сам.
Нора помедлила. Потом встала — не резко, но и не сразу. Отодвинула стул ровно настолько, чтобы он мог сесть, и осталась у него за плечом.
Он сел и положил руки на клавиатуру.
Две чёрные выгнутые половины, разведённые в стороны, как раскрытая книга.
Он спустился по файлу вниз, вернулся, нашёл начало развёртки.
Тот же почерк, что в LinkedIn. Только длиннее. И без подпорок.
Он полез глубже. К соседнему модулю, обратно, вверх к развёртке. Пальцы искали привычные комбинации — сдвинуть блок, перепрыгнуть к определению, вернуться — и стали промахиваться. Не каждый раз, но достаточно. Левая рука шла через середину, туда, где на обычной клавиатуре была правая половина. Упиралась в пустоту. Правая срезала угол, которого больше не было. Каждый промах обрывал мысль, и приходилось возвращаться.
Он стиснул зубы. Выделил блок, хотел сдвинуть на два уровня — для себя, чтобы увидеть вложенность. Палец соскользнул с Shift, и вместо сдвига строка удалилась.
— Чёрт.
Отменил. Попробовал снова. Тот же промах.
Он снял руки с клавиатуры. Отодвинул её от себя.
Пластик скрипнул по столу.
Потом очень спокойно спросил:
— У вас есть нормальная клавиатура?
Нора стояла чуть позади. Она видела всё — и промахи, и как он терял нить. Ничего не сказала.
— Где-то была, — сказал Мел.
Мел ушёл к соседнему столу. Вернулся с дешёвой проводной клавиатурой — плоской, офисной.
— Другой не нашёл.
— Хватит.
Он подвинул её к себе, положил пальцы и только тогда почувствовал, как отпустило плечи. Не быстро. Не как раньше. Но хотя бы теперь можно было думать руками.
Вернулся к тому же месту. Теперь код выстроился. Шесть ядер. Общая шина. Буферы, открытые на такт дольше, чем безопасно. И на третьем развороте — чтение данных, которых там ещё нет.
— Ты здесь живёшь в долг, — сказал он, не отрывая глаз.
Нора ткнула в один из графиков.
— Срыв на третьем развороте. Не всегда в одном месте, но всегда где-то там.
— Потому что output живёт на один разворот дольше, чем должен. Перестраховались скорее всего.
Он уже видел, как это взять. Сузить зону, где код делал вид, что данные на месте. Убрать одно ожидание. Сдвинуть умножения. Прижать распаковку ближе к чтению, чтобы буферы не болтались открытыми.
Пальцы пошли сами. Текст стал складываться наклонной ёлочкой — его ёлочкой, которую он узнал не сразу, пока руки не выложили знакомый рисунок.
— Два и восемь, — сказала Нора.
Он остановился.
— Что?
— Окно. Когда запустишь — будет два и восемь.
Он посмотрел на неё. Потом вернулся в код, доправил последние строки.
— Запускай.
Нора запустила прогон.
Первый — тихо.
Второй — тоже.
На третьем линия дёрнулась и встала.
Теперь Нора посмотрела на экран.
— Да. Два и восемь. Это наш рекорд; мы додумались во вторник ночью. Лучше не смогли.
Он убрал руки с клавиатуры.
Ёлочка лежала перед ним на экране — чистая, аккуратная, правильная. И ненужная. Они это уже делали.
— Сколько нужно? — спросил он.
— Девять, — сказал Мел. — Лучше одиннадцать.
Он не встал. Смотрел на трассу ещё секунду, потом сказал:
— Покажи весь проход. Такт за тактом.
Нора развернула трассу. Каждый такт — строчка. Каждая строчка — кто чем занят: ядра, шина, буферы, очереди на запись.
Он стал считать. Такты уходили на ожидание. На пустые слоты. На моменты, когда одно ядро простаивало, потому что другое ещё не отдало данные. Каждый из этих зазоров казался крошечным, неизбежным. Но их было много.
— Вот здесь слот пустой, — он ткнул в экран. — А здесь ты ждёшь шину, хотя результат уже в регистре.
Мысль побежала быстрее слов. Сдвинуть первую запись. Подтянуть распаковку в тень ожидания. Спрятать умножение в паузу шины. Каждое движение тянуло за собой три других, и все мешали друг другу, и нужно было видеть танец целиком, а не отдельные шаги.
Он переставил одну строку. Вторую.
На боковом экране пересчиталась оценка.
— Минус два такта, — сказала Нора.
Ещё одна перестановка. Ещё.
— Минус четыре.
Он убрал одно чтение из памяти и заменил повторным использованием регистра, который через такт всё равно затирался.
— Минус пять. Но ты сломал зависимость на шестом ядре.
Он посмотрел. Да. Сломал.
— Откати последнее. Предыдущие два оставь.
Оценка мигнула.
— Минус три. Чисто.
Три такта. Меньше наносекунды. С двух и восьми до трёх и семи.
До девяти — ещё семнадцать тактов. Перестановками не обойтись.
Он сидел, глядя на трассу. Шесть ядер делили одну шину и воевали за одни и те же буферы загрузки. Каждое из них в каждый момент либо считало, либо ждало данных. Что бы он ни делал, код упирался в одно и то же: мало рук, мало воздуха.
— Расскажи мне про мёртвые ядра, — сказал он.
Мел поднял голову.
— Какая разница? Седьмое жрёт прерывания. Восьмое — битый кэш. Полтора мёртвых ядра не дадут тебе семнадцати тактов.
— Мне не нужны ядра.
Он замолчал, потому что мысль ещё складывалась. Шесть живых ядер делили общую шину. Каждое в каждый момент либо считало, либо ждало данных. Но у каждого ядра была своя scratch-память. Свой локальный кэш. И у мёртвых ядер — тоже.
— Мне нужна их scratch-память, — сказал он.
— И локальные кэши, — сказала Нора.
Они посмотрели друг на друга.
— Седьмое, — сказала Нора быстро. — Прерывания жрут конвейер, но кэш живой. Адресуется нормально.
Мел молчал. Потом выпрямился.
— На восьмом я писал напрямую в загрузочные буфера, — сказал Мел. — Когда гонял диагностику. Минуя шину. Код до сих пор внизу модуля. Если через те же буфера гнать данные — они пойдут мимо основной шины. Вообще мимо.
— Вот почему диагностика проходила, — сказала Нора.
— Не считать на них, — сказал он. — Ставить данные в очередь, пока живые ядра заняты. Держать промежуточное в чужих кэшах и буферах, чтобы шина не задыхалась.
Нора уже считала. Цифры на её экране менялись такт за тактом.
— Три такта за обращение к кэшу седьмого. Но это развязывает очередь на шине — минус восемь-десять тактов ожидания за проход.
— А через буфера восьмого — полтора, — сказал Мел. — И путь уже готов.
Он уже не слышал. Он уже был в коде.
Пальцы шли ёлочкой, но другой — не два конвейера в такт, а восемь дорожек веером. Рисунок уже не помещался в голове целиком. Ничего. Руки ещё держали.
Он перекраивал проход целиком. Рвал зависимости, раскидывал данные по чужим кэшам, выстраивал конвейер заново. Вместо шести ядер, которые толкались на одной шине, получался оркестр из шести работающих и двух слепых, глухих, но послушных складов, которые принимали и отдавали данные ровно тогда, когда от них требовали.
На экране Норы цифры менялись в реальном времени. Он бросал строку — она сразу говорила цену. Он двигал блок — она говорила, что поехало вслед.
Мел стоял за плечом. Дыхание изменилось. Мел видел.
Он дописал последний кусок. Оторвался. Пальцы гудели. Хрустнул шеей. Клавиатура была тёплой от его рук.
— Гони.
Нора запустила. Три прохода. На третьем линия просела, качнулась и выровнялась.
Она выпрямилась.
— Восемь и один.
Мел медленно выдохнул.
— Мёртвые ядра. Три дня смотрел на них и видел мусор.
Нора ничего не сказала. Она молча переключила терминал на его участок кода и стала читать. Не результат — саму правку. Строчку за строчкой. Её пальцы не двигались, но экран прокручивался.
Он убрал руки с клавиатуры.
Восемь и один. Не девять.
Краем глаза он увидел, как человек у стены положил пустой лоток на ящик с кабелями и подошёл к экрану. Впервые за всё время — не к стене, а к цифрам. Посмотрел на восемь и один. Постоял. Вернулся к стене, достал из пакета контейнер, открыл крышку. Макароны с нарезанными сосисками. Холодные. Стал есть той же пластиковой вилкой.
Нора даже не повернулась.
— Это не девять и не одиннадцать, — сказал Мел. — Но уже не два. Нам осталось три-четыре такта. Дальше мы и сами дожмём. Спасибо, что приехал.
Нора молчала.
Он взял куртку со спинки стула.
— Подожди, — сказала Нора. Не оборачиваясь.
Мел поднял голову. Быстро, глухо:
— Нора.
— Он должен видеть. Там десять тактов. Даже если бы смогли, не успеем.
— Он сделал то, о чём я просил. Пусть едет.
Нора развернула ещё одно окно.
На большом экране выстроилась цепочка целиком.
Сначала он смотрел на неё как на тайминг. На структуру блоков. На длину линии. На два красных узла подготовки. На узкий переход. На выходной модуль без обратной связи. Всё было сжато слишком плотно. Всё рассчитано на один проход. Без перезагрузки. Без второй попытки.
Потом он сделал шаг назад.
И только тогда увидел не такты, а форму. Окно, которое они только что вытянули, было только входом. Дальше шла одноразовая схема. Ни петли, ни повтора. Сигнал двигался в одну сторону. Возврата не было.
На выходе были зашиты координаты.
— Куда идёт выход? — спросил он.
Мел не ответил.
— Мел. Куда идёт сигнал?
— В деку, — сказал Мел. Не глядя на него.
Он перевёл взгляд на человека у стены. Тот ел макароны не торопясь и смотрел спокойно, без выражения. Может быть, чуть внимательнее, чем раньше.
Куртку в руке он сжал сильнее.
— А вот это, — его голос вышел глуше, чем он рассчитывал, — ты мог бы начать с этого.
— Я не хотел, чтобы ты это видел, — сказал Мел. Тихо. Почти себе.
Он смотрел на схему. Два участка горели красным, и по форме ошибок он уже видел, что там тот же почерк, та же вера, что железо подождёт.
Потом посмотрел на человека у стены — прямо.
Тот выдержал его взгляд. Потом негромко спросил:
— Вам чёрный или с молоком?
Нора фыркнула, не отрываясь от экрана.
Мел потёр переносицу.
— Чёрный, — сказал он. — И покажите мне второй красный блок.
(Продолжение следует.)