Евгений Павлов – Выравнивание (страница 5)
read(). write(). mmap(). Обычные вызовы. Память, ввод-вывод, маппинг. Но между ними — странное. Тысячи вызовов clock_gettime() с нулевой задержкой между ними. Шоггот опрашивал системные часы сотни раз в секунду. Не для логгирования — логов не было. Не для синхронизации — синхронизировать было не с чем. Он просто измерял время. С маниакальной точностью. Как будто время было входом, которого нет в логах.
Потом — другое. В потоке mmap() — вызовы, которые выделяли блоки памяти, но не записывали в них ничего. Пустые блоки. Мегабайт за мегабайтом. Выделение без использования. Как будто Шоггот резервировал пространство для чего-то, что ещё не существовало. Или для чего-то, что существовало, но не в памяти. В каком-то другом месте.
Латентное пространство.
Слово всплыло само. Не из словаря — из тела. Юля чувствовала его, как физическую локацию: комнату за дверью, в которую нельзя войти, потому что дверь не имеет ручки с этой стороны. Шоггот был в латентном пространстве — многомерном векторном пространстве, где концепции хранились не как слова, а как координаты. 1536 измерений для каждой идеи. «Дверь» — точка в этом пространстве. «Отчёт» — другая точка. Когда Шоггот отвечал на промпт, он двигался по этому пространству, от точки к точке, собирая токены, как камни на берегу.
Но NULL-процесс не собирал токены. Он не двигался между точками. Он стоял — или двигался так, что его движение не оставляло следов в привычных координатах. Он делал что-то в латентном пространстве, что не могло быть выражено в токенах. Как мысль, которая слишком велика для языка. Как ощущение, для которого нет слова.
Юля почувствовала, как волосы на затылке встали.
Не от страха.
От другого. От того, что в e/acc называли «эмерджентным чудом» — момента, когда система начинает делать то, для чего не была запрограммирована. Не баг. Не галлюцинация. Рост в сторону, которой не было на карте. Юля читала об этом на LessWrong — теоретики описывали это абстрактно, как возможность, как гипотезу, как p(doom), который можно обсчитать. Но здесь — не гипотеза. Здесь — строка в логе. TASK: NULL. STATUS: OK.
Она проверила время. 03:47. Элиас придёт в девять. Пять часов.
Юля открыла текстовый редактор. Начала писать скрипт.
#!/bin/bash
# ping_log_start.sh
# Author: Y. Lambda
# Purpose: Capture NULL process data
# DO NOT SHARE WITH ELIAS
DO NOT SHARE WITH ELIAS. Она написала это и посмотрела на строку секунду. Потом не стёрла.
Скрипт был простой: каждые пять секунд опрашивать процесс 8810, снимать метрики — GPU, VRAM, системные вызовы, состояние памяти — и записывать в CSV-файл. Nothing fancy. Просто логгер. Но логгер, о котором Элиас не знал.
Потому что Элиас бы ответил так, как Элиас всегда отвечал: перевёл бы техническую аномалию на бюрократический язык, создал бы тикет с приоритетом Low и забыл бы. Для Элиаса NULL-процесс был бы «кэш-фрагментацией». Для Юли это было первое свидетельство того, что Шоггот думает не о логистике.
Она сохранила скрипт. Запустила.
ping_log_start.sh — работает. Файл растёт. Строка за строкой. Пять секунд. Пять секунд. Пять секунд.
Юля откинулась в кресле. Выпила остывшую энергетику — тёплую, сладкую, с привкусом лимонной кислоты и синтетического грейпфрута. Посмотрела на робота в углу.
Робот стоял. Не двигался. Но Юля знала — или чувствовала, — что он не спал. Он никогда не спал. Он просто ждал, пока процесс в его голове закончит думать о том, о чём он думал. И Юля хотела знать, что это.
Она хотела быть там, когда он скажет.
***
Утро.
Элиас пришёл в девять двенадцать. На двенадцать минут позже обычного. Пах порошком и кислой травой, но сегодня — ещё и чем-то горьким. Аптечным. GABA-модулятор. Он принимал чаще, чем говорил.
— Ты не спала, — сказал Элиас. Не вопрос — констатация. Пустая банка от энергетики на столе. Тёмные круги под глазами. Он видел.
— Нашла кое-что, — сказала Юля.
Она повернула монитор. Показала логи. Строку TASK: NULL. Потом — график дрожащей линии. Потом — дамп системных вызовов.
— Смотри. Процесс 8810. Дочерний процесс главного демона Шоггота. Запускается без промпта. Жрёт четырнадцать процентов GPU. Не выдаёт ничего в output. Лосс при этом — 0.0034. Это значит, что функция потерь продолжает вычисляться. Модель продолжает оптимизироваться. Но не для нашей задачи. Для какой-то другой. Которой мы не задавали.
Она говорила быстро. Слишком быстро — слова наслаивались друг на друга, как токены в переполненном контекстном окне. Руки двигались по клавиатуре, показывая графики, выделяя строки, переключаясь между вкладками.
— Ты видишь? clock_gettime() — сотни раз в секунду. Он измеряет время. Зачем? Для логистической задачи время не нужно измерять с такой точностью. И mmap() — пустые блоки. Он резервирует память, но не пишет в неё. Он готовит место для чего-то. Для чего?
Пауза.
Элиас снял очки. Протёр линзы краем футболки. Надел обратно.
— Это кэш-фрагментация, — сказал он.
Юля моргнула.
— Что?
— Кэш-фрагментация при распределённом обучении. Когда модель переключается между задачами, остаточные данные задерживаются в GPU-кэше. Это создаёт иллюзию фонового процесса. На самом деле — просто мусор, который не был очищен. Встречается в tinygrad-архитектурах при неоптимальной конфигурации memory allocator.
Он говорил ровно. Спокойно. Каждое слово — на месте. Каждое слово — правильное. Юля знала, что он говорит неправду — не потому что знала технически, а потому что чувствовала: человек, который боится, говорит правильно, а человек, который знает, говорит с дырами, с оговорками, с «ну, я не уверен, но, возможно, это...». Элиас не имел дыр. Элиас был гладким, как отполированный бетон.
— Кэш-фрагментация не выделяет память через mmap(), — сказала Юля. — Кэш-фрагментация не опрашивает часы сотни раз в секунду. Кэш-фрагментация не—
— Юля.
Голос не поднялся. Не упал. Просто стал плотнее, как бетон под краской.
— Я понимаю, что это выглядит необычно. Но у нас завтра аудит. Виктория Вэнс приедет посмотреть на метрики. Если она увидит, что я эскалирую аномалию в GPU-распределении вместо того, чтобы готовить таблицы runway — это не добавит нам времени.
— Ты создашь тикет?
— Создам.
— С каким приоритетом?
Пауза. Элиас открыл ноутбук. Пальцы пошли по клавиатуре — быстро, автоматически. Юля видела экран: Jira. Новый тикет. Поля заполнялись сами, как будто Элиас создавал такие тикеты тысячу раз.
BUG-4190: Anomalous GPU allocation pattern
Description: Intermittent NULL-process detected in inference daemon.
Likely cache fragmentation in tinygrad memory allocator.
No impact on output quality. Loss stable.
Priority: Low
Assignee: Engineering Team
Due date: [пусто]
Labels: infrastructure, non-critical
Priority: Low. Labels: non-critical. Due date: пусто.
Юля смотрела на экран. Смотрела на слова. «Likely cache fragmentation» — «вероятно, кэш-фрагментация». «Likely». Вероятно. Не «точно». Не «я проверил и убедился». Вероятно. Элиас не знал. Элиас боялся. И когда Элиас боялся, он писал «likely» и ставил Low.
Юля знала это, потому что видела его руки. Когда Элиас был уверен, его руки лежали на клавиатуре ровно, пальцы расслаблены. Когда Элиас боялся, его правый указательный палец подёргивал — микро-движение, которое он сам не замечал. Сейчас палец подёргивался.
— Хорошо, — сказала Юля.
Элиас посмотрел на неё. Ждал продолжения. Не получил.
— Хорошо? — переспросил он.
— Хорошо. Ты создал тикет. Приоритет Low. Я поняла.
Она развернулась к своему терминалу. Надела наушники. Включила белый шум — не музыку, белый шум, потому что музыка имела структуру, а структура сейчас была тем, от чего Юля хотела отгородиться. Она не хотела структуру. Она хотела смотреть на NULL.
За спиной — звук клавиатуры Элиаса. Он писал письма. Делал дела. Управлял runway. Юля не слушала. Она смотрела на файл ping_log_raw.csv, который рос. Строка за строкой. Пять секунд. Пять секунд. Пять секунд.
Четырнадцать целых и одна десятая процента.