Системное программирование – одна из тех областей, где нейросеть либо становится незаменимым помощником, либо выдает такую чушь, что хочется закрыть ноутбук и уйти в огород. Разница почти всегда в одном: в том, как сформулирован запрос. Промпты для системного программиста – это не просто "напиши мне код", это точная инструкция с контекстом, ограничениями и форматом результата.
В этой статье собраны 27 готовых примеров запросов для работы с нейросетью. Они охватывают реальные задачи: от отладки ядра и работы с памятью до написания драйверов и анализа производительности.
Что найдете внутри:
- Промпты для работы с низкоуровневым кодом на C и ассемблере
- Запросы для анализа утечек памяти и состояний гонки
- Шаблоны для написания и отладки драйверов устройств
- Примеры для работы с межпроцессным взаимодействием и синхронизацией
- Запросы для профилирования и оптимизации системного кода
- Шаблоны для документирования архитектурных решений
Каждый промпт – готовый к использованию шаблон. Скопировали, подставили свои данные, получили результат. Никакой теории ради теории.
27 промптов для системного программиста: готовые шаблоны для нейросети
1. Анализ утечки памяти в C-программе
Проблема:
Утечки памяти в системном коде обнаруживаются поздно – когда процесс уже съел всю доступную оперативную память и упал в самый неподходящий момент.
Решение:
Промпт заставляет нейросеть пройтись по коду как опытный аудитор: найти незакрытые выделения, указать строки и объяснить причину каждой утечки.
Текст промпта:
*****
Ты – [укажите роль, например, “опытный системный программист со специализацией в отладке памяти на C и C++”].
Проанализируй следующий фрагмент кода на предмет утечек памяти:
[вставьте код, например, “функция инициализации буфера с выделением через malloc и несколькими путями возврата”]Контекст: [опишите контекст выполнения, например, “код работает в многопоточной среде, вызывается из обработчика прерываний”]
Твоя задача:
- Найди все места, где выделенная память не освобождается при всех путях выполнения функции.
- Для каждой найденной утечки укажи номер строки (или описание места), причину возникновения и последствия при длительной работе программы.
- Предложи исправленный вариант кода с комментариями на русском языке.
Формат ответа: сначала список найденных проблем с объяснением, затем исправленный код.
Ограничения: не меняй логику программы, только исправь управление памятью. Не используй умные указатели C++ – только ручное управление памятью в стиле C.
Тон: строго технический, без лирических отступлений.
*****
Почему это работает:
Явное требование рассматривать все пути выполнения (включая пути ошибок) заставляет нейросеть не ограничиваться "счастливым путем", где все освобождается корректно. Ограничение "только C, без C++" исключает нерелевантные советы.
2. Написание драйвера символьного устройства для Linux
Проблема:
Написание драйвера с нуля требует знания десятков специфических структур ядра, и даже опытный разработчик тратит часы на поиск правильного шаблона.
Решение:
Промпт генерирует рабочий каркас драйвера с правильной регистрацией, операциями файла и корректной очисткой ресурсов при выгрузке модуля.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик драйверов для ядра Linux с опытом работы с подсистемой символьных устройств”].
Напиши каркас модуля ядра Linux для символьного устройства со следующими характеристиками:
Устройство: [опишите устройство, например, “виртуальное устройство для передачи данных между пространством пользователя и ядром через буфер фиксированного размера”] Версия ядра: [укажите версию, например, “Linux 5.15 LTS”] Операции: [перечислите операции, например, “open, release, read, write, ioctl для управления размером буфера”]
Контекст: [опишите контекст, например, “драйвер будет использоваться во встроенной системе, ресурсы ограничены, приоритет – минимальный размер кода”]
Структура ответа:
- Заголовочные файлы с объяснением назначения каждого.
- Объявление структур и глобальных переменных с комментариями.
- Реализация каждой операции с подробными комментариями на русском языке.
- Функции инициализации (init) и выгрузки (exit) модуля.
- Макросы MODULE_LICENSE, MODULE_AUTHOR, MODULE_DESCRIPTION.
Ограничения: использовать только стабильный API ядра, не использовать устаревшие функции (register_chrdev вместо cdev_init – не нужен), обеспечить корректное освобождение всех ресурсов в функции exit даже при частичной инициализации.
Тон: технический, комментарии объясняют "почему", а не "что".
*****
Почему это работает:
Требование "корректное освобождение даже при частичной инициализации" – это именно то, что начинающие авторы драйверов упускают и что приводит к панике ядра. Явное указание версии ядра исключает советы с устаревшим API.
3. Поиск состояния гонки в многопоточном коде
Проблема:
Состояния гонки воспроизводятся нестабильно, а их последствия – от тихого повреждения данных до полного зависания системы – обнаруживаются через недели после появления.
Решение:
Промпт проводит систематический анализ общих ресурсов и точек синхронизации, выдавая конкретные места с объяснением механизма возникновения гонки.
Текст промпта:
*****
Ты – [укажите роль, например, “специалист по многопоточному программированию и анализу параллельного выполнения кода на C/C++”].
Проанализируй следующий многопоточный код на наличие состояний гонки и проблем синхронизации:
[вставьте код, например, “реализация пула потоков с общей очередью задач и несколькими рабочими потоками”]Контекст выполнения: [опишите контекст, например, “код выполняется на многоядерном процессоре x86-64, компилятор GCC 12 с оптимизацией O2”]
Выполни анализ в следующем порядке:
- Определи все общие ресурсы (переменные, структуры данных, файловые дескрипторы).
- Для каждого общего ресурса проверь: есть ли защита мьютексом/семафором, правильно ли расставлены захват и освобождение блокировки, нет ли возможности взаимной блокировки.
- Проверь атомарность операций: какие операции выглядят атомарными, но таковыми не являются на уровне процессора.
- Укажи конкретные сценарии, при которых гонка проявится, с описанием последовательности событий.
Формат: таблица найденных проблем (ресурс – тип проблемы – сценарий – последствие), затем исправленный код.
Ограничения: не предлагай переписать все с нуля, работай с существующей структурой кода.
*****
Почему это работает:
Требование описать конкретный сценарий проявления гонки (последовательность событий) переводит анализ из абстрактного в воспроизводимый – именно это нужно для написания теста, который поймает проблему.
4. Оптимизация горячего пути в критической функции
Проблема:
Профилировщик показывает, что функция занимает 40% времени выполнения, но непонятно, что именно тормозит – алгоритм, промахи кэша или ветвления.
Решение:
Промпт проводит многоуровневый анализ производительности: от алгоритмической сложности до предсказания ветвлений и локальности данных.
Текст промпта:
*****
Ты – [укажите роль, например, “эксперт по низкоуровневой оптимизации кода для архитектуры x86-64”].
Оптимизируй следующую функцию, которая является узким местом по результатам профилирования:
[вставьте код функции, например, “функция обработки пакетов, вызываемая 10 миллионов раз в секунду”]Данные профилирования: [опишите данные, например, “40% времени в этой функции, высокий процент промахов кэша L1, частые неверные предсказания ветвлений”] Целевая архитектура: [укажите архитектуру, например, “Intel Core i7 12-го поколения, кэш L1 32 КБ, L2 256 КБ”]
Проведи анализ по уровням:
- Алгоритмический уровень: можно ли снизить сложность или количество итераций.
- Уровень структур данных: оптимальна ли компоновка данных для кэша (выравнивание, структура vs массив структур).
- Уровень ветвлений: какие условия предсказуемы, какие нет, как их реструктурировать.
- Уровень инструкций: где применить векторизацию, встроенные функции процессора или подсказки компилятору.
Для каждой оптимизации укажи ожидаемый эффект и потенциальные компромиссы (читаемость, переносимость).
Ограничения: сохранить корректность результата, не использовать ассемблерные вставки без крайней необходимости.
*****
Почему это работает:
Многоуровневый подход к анализу позволяет не упустить причину на каждом из уровней абстракции – часто разработчики ищут проблему на уровне инструкций, когда она находится на алгоритмическом уровне и наоборот.
5. Разработка протокола межпроцессного взаимодействия
Проблема:
Выбор механизма межпроцессного взаимодействия без четкого понимания компромиссов приводит к архитектурным решениям, которые потом переписываются целиком.
Решение:
Промпт помогает выбрать и спроектировать механизм взаимодействия с учетом конкретных требований к задержке, пропускной способности и надежности.
Текст промпта:
*****
Ты – [укажите роль, например, “архитектор системного программного обеспечения с опытом проектирования высоконагруженных систем на Linux”].
Помоги спроектировать механизм межпроцессного взаимодействия для следующей задачи:
Описание системы: [опишите систему, например, “сервис мониторинга собирает метрики от 50 агентов каждые 100 миллисекунд и передает в центральный агрегатор”] Требования к производительности: [укажите требования, например, “задержка не более 1 миллисекунды, пропускная способность 100 МБ/с, данные не критичны к потере отдельных пакетов”] Ограничения среды: [укажите ограничения, например, “все процессы на одном хосте, Linux 5.15, нельзя использовать внешние библиотеки”]
Структура ответа:
- Сравнение подходящих механизмов (разделяемая память, очередь сообщений POSIX, доменные сокеты Unix, именованные каналы) по критериям: задержка, пропускная способность, сложность реализации, надежность.
- Обоснованная рекомендация с учетом указанных требований.
- Схема протокола: формат сообщений, синхронизация, обработка ошибок.
- Минимальный рабочий пример реализации на C.
Ограничения: объяснять компромиссы, а не просто называть "лучший вариант".
*****
Почему это работает:
Требование объяснять компромиссы, а не просто рекомендовать "лучший вариант", дает понимание, а не слепое следование совету – это критично при смене требований проекта.
6. Написание и отладка кода на ассемблере x86-64
Проблема:
Ассемблерный код сложно читать, еще сложнее отлаживать, а нейросеть без четкого контекста генерирует синтаксически правильный, но семантически сломанный код.
Решение:
Промпт с явным указанием синтаксиса, соглашения о вызовах и целевой задачи дает корректный ассемблерный код с подробными пояснениями каждой инструкции.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик низкоуровневого кода с глубоким знанием архитектуры x86-64 и соглашений вызовов System V AMD64 ABI”].
Напиши функцию на ассемблере x86-64 для следующей задачи:
Задача: [опишите задачу, например, “поиск первого нулевого байта в буфере памяти с использованием векторных инструкций SSE2 для ускорения”] Синтаксис: [укажите синтаксис, например, “AT&T синтаксис для GCC inline assembler” или “Intel синтаксис для NASM”] Соглашение о вызовах: [укажите соглашение, например, “System V AMD64: первый аргумент в rdi, второй в rsi, результат в rax”]
Требования:
- Каждая инструкция должна иметь комментарий на русском языке, объясняющий что и почему делается.
- Явно обозначь сохранение и восстановление регистров согласно соглашению о вызовах.
- Обработай граничные случаи: пустой буфер, буфер без нулевого байта.
- Приведи эквивалентный код на C для понимания логики.
Ограничения: не использовать инструкции новее SSE2 без явного указания, обеспечить корректное выравнивание стека.
*****
Почему это работает:
Явное требование приводить эквивалент на C позволяет немедленно проверить логику и убедиться, что ассемблерный код делает именно то, что задумано.
7. Анализ дампа памяти после аварийного завершения
Проблема:
Дамп памяти без правильного плана анализа превращается в часы бесплодного копания в шестнадцатеричных значениях вместо быстрого нахождения причины сбоя.
Решение:
Промпт создает структурированный план анализа с конкретными командами отладчика и объяснением того, что искать на каждом шаге.
Текст промпта:
*****
Ты – [укажите роль, например, “специалист по постмортем-анализу системных сбоев с опытом работы с GDB и анализа дампов ядра Linux”].
Помоги проанализировать аварийное завершение программы. Имеющиеся данные:
Сигнал завершения: [укажите сигнал, например, “SIGSEGV – обращение по недопустимому адресу”] Трассировка стека: [вставьте трассировку, например, “вывод bt в GDB с несколькими кадрами”] Контекст программы: [опишите контекст, например, “многопоточный сервер обработки запросов, сбой происходит под нагрузкой примерно через 2 часа работы”] Последние изменения в коде: [опишите изменения, например, “добавлен новый обработчик запросов три дня назад”]
Выполни анализ по плану:
- Интерпретируй трассировку стека: что делала программа в момент сбоя, какой поток, какая функция.
- Предложи гипотезы о причине с ранжированием по вероятности.
- Для каждой гипотезы дай конкретные команды GDB для проверки с объяснением что ищем.
- Укажи, какую дополнительную информацию нужно собрать при следующем воспроизведении.
Формат: структурированный план действий, команды в блоках кода, пояснения на русском.
*****
Почему это работает:
Ранжирование гипотез по вероятности направляет анализ от наиболее вероятных причин к редким, что экономит время при ограниченном количестве воспроизведений сбоя.
8. Проектирование системы управления памятью (аллокатор)
Проблема:
Стандартный аллокатор не всегда подходит для специфических паттернов выделения памяти в системном коде – это приводит к фрагментации и неприемлемым задержкам.
Решение:
Промпт помогает спроектировать специализированный аллокатор с учетом конкретных паттернов использования и требований к производительности.
Текст промпта:
*****
Ты – [укажите роль, например, “системный программист с опытом реализации специализированных аллокаторов памяти для встроенных систем и систем реального времени”].
Спроектируй специализированный аллокатор памяти для следующих условий:
Паттерн использования: [опишите паттерн, например, “выделение объектов одного размера (512 байт) в большом количестве с коротким временем жизни, частые выделение и освобождение”] Требования: [укажите требования, например, “детерминированное время выделения O(1), минимальная фрагментация, работа без системных вызовов после инициализации”] Среда: [опишите среду, например, “встроенная система, 4 МБ доступной памяти, однопоточная среда”]
Структура ответа:
- Выбор подходящего типа аллокатора (пул, стек, кольцевой буфер, битовая карта) с обоснованием.
- Схема организации памяти с объяснением каждого поля заголовка блока.
- Реализация основных функций: инициализация, выделение, освобождение.
- Анализ фрагментации и стратегия ее минимизации.
- Тест корректности и измерение производительности.
Ограничения: реализация на C, без использования стандартного malloc/free внутри аллокатора.
*****
Почему это работает:
Явное требование детерминированного времени выполнения O(1) сразу отсекает неподходящие алгоритмы и фокусирует нейросеть на правильном классе решений.
9. Настройка и анализ производительности с помощью системных счетчиков
Проблема:
Счетчики производительности процессора – мощный инструмент, но без понимания, что именно измерять и как интерпретировать результаты, они остаются набором непонятных цифр.
Решение:
Промпт создает конкретный план измерений с командами, объяснением метрик и интерпретацией типичных результатов для заданной задачи.
Текст промпта:
*****
Ты – [укажите роль, например, “специалист по анализу производительности системного программного обеспечения с опытом работы с perf и аппаратными счетчиками производительности”].
Помоги настроить и интерпретировать измерения производительности для следующей задачи:
Программа: [опишите программу, например, “обработчик сетевых пакетов на C, работающий в режиме ядра”] Наблюдаемая проблема: [опишите проблему, например, “пропускная способность на 30% ниже теоретической, загрузка CPU высокая, но пакеты обрабатываются медленно”] Оборудование: [укажите оборудование, например, “Intel Xeon E5-2680 v4, Linux 5.15”]
Создай план измерений:
- Какие счетчики производительности измерять (промахи кэша, неверные предсказания ветвлений, остановки конвейера) и почему именно эти.
- Конкретные команды perf для каждого измерения.
- Пороговые значения: что считать нормой, что – проблемой для данного типа нагрузки.
- Интерпретация возможных результатов: если высокий показатель X, то проблема в Y, решение Z.
- Последовательность действий по результатам измерений.
Формат: пошаговый план с командами и таблицей интерпретации метрик.
Ограничения: только инструменты, входящие в стандартный Linux (perf, ftrace, /proc), без внешних зависимостей.
*****
Почему это работает:
Требование указать пороговые значения и интерпретацию "если X, то Y" превращает набор цифр в actionable-план – это именно то, чего не хватает большинству руководств по профилированию.
10. Реализация механизма синхронизации без блокировок
Проблема:
Структуры данных без блокировок кажутся элегантным решением, но неправильная реализация создает тонкие ошибки, которые проявляются только на определенных процессорах или при определенной нагрузке.
Решение:
Промпт создает корректную реализацию с явным анализом модели памяти и обоснованием каждого барьера памяти.
Текст промпта:
*****
Ты – [укажите роль, например, “специалист по параллельному программированию с глубоким знанием моделей памяти процессоров и алгоритмов без блокировок”].
Реализуй следующую структуру данных без использования мьютексов:
Структура: [опишите структуру, например, “очередь MPSC (несколько производителей, один потребитель) для передачи указателей между потоками”] Требования: [укажите требования, например, “операции push и pop должны быть без блокировок, порядок FIFO, максимальный размер 1024 элемента”] Целевая платформа: [укажите платформу, например, “x86-64, компилятор GCC, стандарт C11 с поддержкой атомарных операций”]
Структура ответа:
- Анализ требований к порядку памяти: какие операции требуют барьеров памяти и почему.
- Реализация с явными атомарными операциями (_Atomic в C11 или _atomic* в GCC).
- Для каждого барьера памяти (memory_order_*) объясни: почему именно этот порядок, что произойдет при более слабом порядке.
- Тест корректности: как проверить правильность реализации под нагрузкой.
- Производительность: сравнение с эквивалентной реализацией на мьютексах.
Ограничения: не использовать внешние библиотеки, только стандартный C11 или GCC-специфичные расширения.
*****
Почему это работает:
Требование объяснить, что произойдет при более слабом порядке памяти, заставляет нейросеть обосновать каждое решение, а не просто написать код с произвольными барьерами памяти.
11. Разработка системного вызова для ядра Linux
Проблема:
Добавление системного вызова в ядро требует понимания множества деталей: от объявления до обработки аргументов из пространства пользователя – и одна ошибка открывает уязвимость.
Решение:
Промпт создает полный шаблон системного вызова с безопасной обработкой пользовательских данных и корректной интеграцией в таблицу системных вызовов.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик ядра Linux с опытом добавления системных вызовов и обеспечения их безопасности”].
Помоги реализовать новый системный вызов для ядра Linux:
Назначение системного вызова: [опишите назначение, например, “получение статистики использования памяти конкретным процессом с расширенными метриками, недоступными через /proc”] Аргументы: [опишите аргументы, например, “PID процесса, указатель на структуру для результата, флаги выбора метрик”] Версия ядра: [укажите версию, например, “Linux 6.1”]
Реализация должна включать:
- Объявление системного вызова через макрос SYSCALL_DEFINE с правильным количеством аргументов.
- Безопасное копирование данных из пространства пользователя (copy_from_user) и в него (copy_to_user) с проверкой всех возможных ошибок.
- Проверки привилегий и валидация входных данных.
- Регистрацию в таблице системных вызовов (с пояснением для архитектуры x86-64).
- Пример вызова из пространства пользователя через syscall().
- Список типичных уязвимостей при реализации системных вызовов и как их избежать.
Ограничения: все взаимодействия с пользовательским пространством только через безопасные функции ядра, никакого прямого разыменования пользовательских указателей.
*****
Почему это работает:
Явный запрос на список уязвимостей при реализации системных вызовов – это то, что отличает промпт для системного программиста от запроса новичка: безопасность закладывается с самого начала, а не добавляется потом.
12. Анализ и оптимизация работы с кэшем процессора
Проблема:
Промахи кэша могут замедлить программу в 10–100 раз по сравнению с теоретическим максимумом, но причина часто неочевидна без понимания того, как именно данные располагаются в памяти.
Решение:
Промпт анализирует структуру данных и паттерны доступа, предлагая конкретные преобразования для улучшения локальности данных.
Текст промпта:
*****
Ты – [укажите роль, например, “специалист по оптимизации производительности с глубоким пониманием иерархии памяти и принципов работы кэша процессора”].
Проанализируй следующий код на предмет проблем с эффективностью работы с кэшем:
[вставьте код, например, “цикл обработки массива структур с несколькими полями разного размера”]Характеристики кэша целевого процессора: [укажите характеристики, например, “кэш-линия 64 байта, L1 32 КБ 8-канальный, L2 256 КБ, L3 8 МБ”] Паттерн доступа: [опишите паттерн, например, “последовательный проход по массиву из 10 миллионов элементов, обращение только к двум полям структуры из восьми”]
Анализ должен включать:
- Вычисление текущей эффективности использования кэш-линий: сколько полезных байт из каждой загруженной кэш-линии.
- Диаграмму размещения структуры в памяти и кэш-линиях.
- Конкретные преобразования: разделение структуры (AoS → SoA), выравнивание, предвыборку данных.
- Оценку ожидаемого прироста производительности для каждого преобразования.
- Компромиссы: что ухудшится при каждом преобразовании.
Формат: текстовый анализ с ASCII-диаграммами размещения данных в памяти.
*****
Почему это работает:
Вычисление эффективности использования кэш-линий в числах ("полезных байт из 64 загруженных") делает абстрактную проблему конкретной и измеримой, что сразу показывает масштаб потенциального улучшения.
13. Написание юнит-тестов для системного кода
Проблема:
Тестирование системного кода сложнее прикладного: нужно изолировать зависимости от оборудования, эмулировать условия ошибок и тестировать граничные состояния, которые в реальности воспроизвести трудно.
Решение:
Промпт создает набор тестов с подстановкой зависимостей, покрывающий нормальные случаи, граничные условия и сценарии ошибок.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик с опытом тестирования системного кода на C с использованием фреймворков проверки и техник подстановки зависимостей”].
Напиши набор тестов для следующего системного кода:
Код для тестирования: [вставьте код или опишите функцию, например, “функция чтения из символьного устройства с обработкой ошибок ввода-вывода и таймаутов”] Зависимости: [перечислите зависимости, например, “системные вызовы read(), select(), открытый файловый дескриптор устройства”] Фреймворк: [укажите фреймворк, например, “CMocka” или “Unity для встроенных систем”]
Тесты должны покрывать:
- Нормальный случай: успешное чтение данных.
- Граничные условия: пустой буфер, буфер ровно нужного размера, переполнение.
- Сценарии ошибок: устройство недоступно, прерывание сигналом (EINTR), таймаут.
- Состояния гонки: параллельные вызовы при наличии общего состояния.
Для каждого теста:
– Объясни что именно проверяется и почему это важно.
– Покажи как эмулировать поведение зависимостей (системных вызовов) без реального оборудования.
– Укажи что считается успехом теста.
Ограничения: тесты должны выполняться без привилегий суперпользователя и без реального оборудования.
*****
Почему это работает:
Требование тестировать прерывание сигналом EINTR – это именно тот граничный случай, который обычно пропускается и потом вызывает трудновоспроизводимые сбои в production-системах.
14. Проектирование встроенной файловой системы
Проблема:
Выбор и проектирование файловой системы для встроенного устройства без четкого анализа требований приводит к решениям, которые либо избыточны, либо не выдерживают реальных условий эксплуатации.
Решение:
Промпт создает структурированный анализ требований и проектное решение с обоснованием каждого архитектурного выбора.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик встроенных систем с опытом проектирования и адаптации файловых систем для устройств с ограниченными ресурсами”].
Помоги спроектировать файловую систему для встроенного устройства:
Хранилище: [опишите хранилище, например, “NAND Flash 512 МБ, размер страницы 4 КБ, размер блока стирания 256 КБ, ресурс 100 000 циклов перезаписи блока”] Паттерн использования: [опишите паттерн, например, “частая запись небольших конфигурационных файлов до 4 КБ, редкое чтение, критична целостность данных при внезапном отключении питания”] Ограничения ресурсов: [укажите ограничения, например, “доступно 64 КБ ОЗУ для файловой системы, процессор ARM Cortex-M4”]
Анализ должен включать:
- Сравнение подходящих файловых систем (JFFS2, YAFFS2, LittleFS, SPIFFS) по критериям: расход ОЗУ, стойкость к отключению питания, выравнивание износа, сложность интеграции.
- Рекомендацию с обоснованием.
- Ключевые параметры конфигурации выбранной файловой системы с объяснением их влияния.
- Стратегию тестирования: как проверить стойкость к внезапному отключению питания.
Ограничения: не рекомендовать файловые системы, требующие аппаратного MMU, если он не указан в требованиях.
*****
Почему это работает:
Явное требование учитывать стойкость к внезапному отключению питания как критерий сравнения – это то, что отличает реальный выбор от теоретического: именно этот критерий часто определяет финальное решение во встроенных системах.
15. Реализация планировщика задач для операционной системы реального времени
Проблема:
Планировщик реального времени – это не просто "кто следующий выполняется", а сложная система с гарантиями по времени отклика, которые нарушить очень легко, а восстановить – крайне сложно.
Решение:
Промпт создает реализацию планировщика с явным анализом наихудшего времени выполнения и проверкой выполнимости расписания.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик систем реального времени с опытом реализации планировщиков задач для операционных систем реального времени”].
Реализуй планировщик задач для следующих условий:
Тип планирования: [укажите тип, например, “вытесняющий планировщик с фиксированными приоритетами, алгоритм Rate-Monotonic”] Задачи: [опишите задачи, например, “5 периодических задач с периодами от 1 до 100 миллисекунд и временем выполнения от 0.1 до 10 миллисекунд”] Платформа: [укажите платформу, например, “микроконтроллер ARM Cortex-M3, системный таймер SysTick, без аппаратной поддержки виртуальной памяти”]
Реализация должна включать:
- Проверку выполнимости расписания (тест загрузки процессора для Rate-Monotonic).
- Структуры данных для очереди задач и блоков управления задачами.
- Реализацию переключения контекста: сохранение и восстановление регистров.
- Обработчик таймера для вытеснения задач.
- Анализ наихудшего времени отклика для каждой задачи.
Ограничения: реализация на C, переключение контекста через обработчик прерывания PendSV, без использования динамического выделения памяти в планировщике.
*****
Почему это работает:
Требование провести проверку выполнимости расписания до реализации – это именно тот шаг, который пропускают при разработке и потом обнаруживают, что система не может выполнить все задачи в срок уже после написания тысяч строк кода.
16. Написание обработчика прерываний
Проблема:
Обработчик прерываний с ошибками – это не просто баг, это потенциальное зависание всей системы, и отлаживать его в условиях запрета на большинство стандартных операций крайне сложно.
Решение:
Промпт создает корректный обработчик прерываний с явным соблюдением всех ограничений контекста прерывания и правильным разделением работы между обработчиком и основным потоком.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик встроенных систем с опытом написания обработчиков прерываний для микроконтроллеров и ядра Linux”].
Напиши обработчик прерывания для следующей задачи:
Источник прерывания: [опишите источник, например, “прерывание от UART при получении байта данных, частота до 115200 бод”] Платформа: [укажите платформу, например, “микроконтроллер STM32F4, Cortex-M4, FreeRTOS”] Требования: [укажите требования, например, “минимальное время в обработчике, передача данных в основной поток через кольцевой буфер без блокировок”]
Реализация должна включать:
- Сам обработчик прерывания с атрибутами компилятора для правильного размещения в векторной таблице.
- Объяснение: что разрешено и запрещено делать в контексте прерывания (какие функции ОС можно вызывать).
- Механизм передачи данных в основной поток (кольцевой буфер с атомарными операциями).
- Обработку ошибок: переполнение буфера, ошибки UART.
- Измерение времени выполнения обработчика и обеспечение его соответствия требованиям.
Ограничения: в самом обработчике прерывания не использовать функции с блокировками, динамическое выделение памяти или длительные вычисления.
*****
Почему это работает:
Явное требование объяснить, что разрешено и запрещено в контексте прерывания, формирует правильное понимание ограничений, а не просто выдает шаблон кода без понимания почему он именно такой.
17. Реализация виртуальной памяти и управления страницами
Проблема:
Работа с таблицами страниц и механизмами виртуальной памяти требует точного понимания аппаратных структур, и одна ошибка в управлении страницами может привести к трудно воспроизводимым повреждениям памяти.
Решение:
Промпт создает реализацию с явным объяснением каждого уровня таблицы страниц и корректной обработкой исключений страничного нарушения.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик операционных систем с опытом реализации подсистем управления виртуальной памятью”].
Реализуй базовую подсистему управления страницами памяти:
Архитектура: [укажите архитектуру, например, “x86-64, четырехуровневые таблицы страниц (PML4, PDPT, PD, PT), размер страницы 4 КБ”] Задача: [опишите задачу, например, “реализация для учебной операционной системы: отображение физической памяти на виртуальную, обработка страничных нарушений”] Объем физической памяти: [укажите объем, например, “64 МБ, карта памяти получена от загрузчика”]
Реализация должна включать:
- Структуры данных для каждого уровня таблицы страниц с описанием каждого бита флагов.
- Функции создания отображения (map_page) и его удаления (unmap_page).
- Обход таблицы страниц для трансляции виртуального адреса в физический.
- Обработчик исключения страничного нарушения (#PF) с разбором кода ошибки.
- Простой физический аллокатор страниц (битовая карта свободных страниц).
Для каждой функции объясни: почему именно такой порядок операций, какие флаги TLB нужно сбрасывать и когда.
Ограничения: реализация на C с минимальными ассемблерными вставками только там, где без них невозможно.
*****
Почему это работает:
Требование объяснять порядок операций и необходимость сброса буфера трансляции адресов – это именно те детали, которые отсутствуют в большинстве учебных примеров и которые являются источником трудноуловимых ошибок.
18. Создание инструмента трассировки системных вызовов
Проблема:
Понять, что именно делает процесс в системе, без инструмента трассировки – это как чинить машину с завязанными глазами: теоретически возможно, но крайне неэффективно.
Решение:
Промпт создает инструмент мониторинга системных вызовов с фильтрацией, форматированием вывода и минимальным влиянием на производительность наблюдаемого процесса.
Текст промпта:
*****
Ты – [укажите роль, например, “системный программист с опытом разработки инструментов трассировки и мониторинга на базе механизмов ядра Linux”].
Создай инструмент трассировки системных вызовов:
Механизм: [укажите механизм, например, “ptrace для трассировки пользовательского процесса” или “eBPF для мониторинга с минимальными накладными расходами”] Требования: [укажите требования, например, “перехват и вывод системных вызовов с аргументами и возвращаемыми значениями, фильтрация по имени системного вызова”] Целевая среда: [укажите среду, например, “Linux 5.15, трассировка произвольного процесса по его PID”]
Реализация должна включать:
- Присоединение к процессу и перехват системных вызовов.
- Декодирование аргументов: числовые значения, строки из пространства пользователя, флаги (с расшифровкой битовых масок).
- Форматированный вывод: имя вызова, аргументы, возвращаемое значение, время выполнения.
- Фильтрацию по имени системного вызова или возвращаемому значению (только ошибки).
- Корректное отсоединение от процесса при завершении трассировщика.
Объясни: как работает выбранный механизм трассировки, каковы его ограничения и накладные расходы по сравнению с альтернативами.
Ограничения: реализация на C, без использования внешних библиотек трассировки.
*****
Почему это работает:
Требование декодировать битовые маски флагов в человекочитаемый вид – это то, что делает разницу между "видеть числа" и "понимать что происходит" при анализе поведения системы.
19. Оптимизация сетевого стека для высоконагруженной системы
Проблема:
Стандартные настройки сетевого стека Linux ориентированы на универсальность, а не на максимальную производительность, и без целенаправленной настройки система не использует и половины возможностей оборудования.
Решение:
Промпт создает конкретный план настройки с параметрами, объяснением их влияния и измеримыми результатами для заданного типа нагрузки.
Текст промпта:
*****
Ты – [укажите роль, например, “специалист по высоконагруженным сетевым системам с опытом оптимизации сетевого стека Linux для обработки миллионов пакетов в секунду”].
Разработай план оптимизации сетевого стека для следующей задачи:
Тип нагрузки: [опишите нагрузку, например, “обработка UDP-пакетов малого размера (64–256 байт) с интенсивностью 5 миллионов пакетов в секунду”] Оборудование: [опишите оборудование, например, “сетевая карта Intel X710 10 Гбит/с, сервер с 32 ядрами NUMA, Linux 5.15”] Текущая проблема: [опишите проблему, например, “потери пакетов при пиковой нагрузке, высокая задержка обработки”]
План оптимизации должен охватывать:
- Настройки ядра (параметры sysctl): размеры буферов сокетов, параметры очередей, настройки прерываний – с объяснением каждого параметра.
- Привязку прерываний сетевой карты к ядрам процессора с учетом топологии NUMA.
- Настройку многоочередного режима сетевой карты (RSS/RPS/RFS).
- Оценку применимости технологии обхода ядра (DPDK) для данной задачи.
- Методологию измерения результатов: какие метрики снимать до и после каждого изменения.
Формат: пошаговый план с конкретными командами и ожидаемым эффектом каждого изменения.
Ограничения: начинать с изменений, не требующих перекомпиляции ядра.
*****
Почему это работает:
Требование начинать с изменений без перекомпиляции ядра задает правильный порядок оптимизации: сначала "бесплатные" улучшения, потом более сложные – это экономит время и позволяет измерить вклад каждого изменения отдельно.
20. Реализация безопасного парсера бинарного протокола
Проблема:
Парсеры бинарных протоколов – традиционный источник уязвимостей: переполнение буфера, выход за границы массива, целочисленное переполнение при вычислении размеров – все это легко пропустить при написании.
Решение:
Промпт создает парсер с систематической проверкой всех входных данных и явным анализом потенциальных уязвимостей.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик безопасного системного кода с опытом написания парсеров бинарных протоколов и анализа уязвимостей”].
Реализуй безопасный парсер для следующего бинарного протокола:
Описание протокола: [опишите протокол, например, “протокол с заголовком фиксированного размера (тип сообщения 2 байта, длина данных 4 байта) и полезной нагрузкой переменного размера до 64 КБ”] Источник данных: [опишите источник, например, “сетевой сокет, данные приходят от внешних клиентов, считаются потенциально враждебными”] Платформа: [укажите платформу, например, “Linux, 64-битная, компилятор GCC с включенными санитайзерами”]
Реализация должна включать:
- Проверку каждого поля: диапазон значений, корректность размеров, соответствие типу сообщения.
- Защиту от целочисленного переполнения при вычислении размеров буферов.
- Защиту от чтения за пределами буфера при разборе переменных полей.
- Явное указание и обработку всех состояний ошибок с информативными кодами ошибок.
- Анализ: перечисли все места, где мог бы быть баг безопасности, и объясни как они закрыты.
Ограничения: не использовать небезопасные функции (strcpy, sprintf без ограничения длины), все индексы и размеры проверять перед использованием.
*****
Почему это работает:
Требование перечислить все потенциально уязвимые места и объяснить как они закрыты – это метод "доказательства безопасности", который переводит написание кода из интуитивного в систематическое.
21. Разработка системы логирования для ядра или встроенной системы
Проблема:
Логирование в контексте ядра или встроенной системы – это не просто fprintf, а сложная задача с ограничениями на выделение памяти, доступные функции и объем хранилища.
Решение:
Промпт создает систему логирования с кольцевым буфером, уровнями детализации и механизмом вывода без блокирующих операций.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик встроенных систем с опытом реализации систем диагностики и логирования для ресурсоограниченных платформ”].
Реализуй систему логирования для следующих условий:
Среда: [опишите среду, например, “модуль ядра Linux” или “встроенная система на ARM Cortex-M без операционной системы”] Ограничения: [укажите ограничения, например, “нельзя использовать динамическое выделение памяти, нельзя блокировать выполнение, объем буфера логов не более 16 КБ”] Требования: [укажите требования, например, “уровни детализации (ошибка, предупреждение, информация, отладка), временные метки с точностью до миллисекунды, атомарность записи”]
Реализация должна включать:
- Кольцевой буфер фиксированного размера с атомарными операциями записи.
- Форматирование сообщений без использования malloc (статические буферы или форматирование на месте).
- Механизм вывода: как читать буфер из пространства пользователя или через последовательный порт.
- Защиту от переполнения: стратегия при заполненном буфере (перезапись старых или отбрасывание новых).
- Макросы для удобного использования с автоматической подстановкой имени файла и номера строки.
Ограничения: реализация должна быть безопасна для вызова из контекста прерывания.
*****
Почему это работает:
Требование безопасности для вызова из контекста прерывания – это ключевое ограничение, которое определяет всю архитектуру системы логирования и которое легко упустить при проектировании.
22. Анализ и устранение взаимной блокировки
Проблема:
Взаимная блокировка в системном коде может заморозить не только отдельный поток, но и всю систему – а воспроизвести ее в отладчике часто невозможно из-за нестабильности временных условий.
Решение:
Промпт систематически анализирует граф зависимостей блокировок, находит циклы и предлагает реструктуризацию с сохранением корректности.
Текст промпта:
*****
Ты – [укажите роль, например, “специалист по отладке многопоточных систем с опытом анализа взаимных блокировок и реструктуризации кода синхронизации”].
Проанализируй следующий код на наличие потенциальных взаимных блокировок:
[вставьте код, например, “два потока, каждый из которых захватывает два мьютекса в разном порядке”]Контекст: [опишите контекст, например, “серверное приложение, взаимная блокировка проявляется под нагрузкой примерно раз в несколько часов”]
Выполни анализ:
- Построй граф зависимостей блокировок: какой поток владеет каким мьютексом и ожидает какого.
- Найди все циклы в графе зависимостей (потенциальные взаимные блокировки).
- Для каждого найденного цикла опиши точную последовательность событий, приводящую к блокировке.
- Предложи варианты устранения с анализом компромиссов:
– Упорядочивание захвата мьютексов
– Использование trylock с повторной попыткой
– Реструктуризация кода для устранения необходимости в нескольких блокировках - Покажи исправленный код для рекомендованного варианта.
Ограничения: не предлагать глобальный мьютекс как решение – это устраняет симптом, но убивает параллелизм.
*****
Почему это работает:
Явный запрет предлагать глобальный мьютекс как решение отсекает самый распространенный "легкий" выход, который действительно решает проблему взаимной блокировки, но создает новую – последовательное выполнение там, где должен быть параллелизм.
23. Написание скрипта автоматической сборки и тестирования системного кода
Проблема:
Ручная сборка системного кода с разными конфигурациями компилятора, флагами санитайзеров и запуском тестов – это монотонная работа, которая пропускается при спешке именно тогда, когда нужна больше всего.
Решение:
Промпт создает автоматизированный сценарий сборки с несколькими конфигурациями, запуском тестов и понятным отчетом о результатах.
Текст промпта:
*****
Ты – [укажите роль, например, “инженер по автоматизации сборки системного программного обеспечения с опытом настройки конвейеров сборки для C/C++ проектов”].
Создай скрипт автоматической сборки и тестирования для следующего проекта:
Проект: [опишите проект, например, “модуль ядра Linux и пользовательская библиотека для работы с ним, исходный код в нескольких директориях”] Конфигурации сборки: [перечислите конфигурации, например, “отладочная (без оптимизации, с санитайзерами адресов и неопределенного поведения), релизная (O2, LTO), для встроенной платформы (кросс-компиляция arm-linux-gnueabihf)”] Тесты: [опишите тесты, например, “юнит-тесты через CMocka, статический анализ через cppcheck и clang-tidy, проверка утечек через Valgrind”]
Скрипт должен:
- Выполнять сборку для каждой конфигурации независимо.
- Запускать соответствующий набор тестов для каждой конфигурации.
- Собирать результаты и формировать итоговый отчет: что прошло, что упало, с указанием файла и строки.
- Возвращать ненулевой код завершения при любом сбое (для интеграции в автоматизированные системы).
- Поддерживать параметр для сборки только конкретной конфигурации.
Язык скрипта: [укажите язык, например, “Bash” или “GNU Make с дополнительными сценариями Bash”] Ограничения: скрипт должен работать без дополнительных инструментов кроме указанных, подробные комментарии на русском языке.
*****
Почему это работает:
Требование возвращать ненулевой код завершения при любом сбое – это маленькая деталь, которая определяет, можно ли интегрировать скрипт в автоматизированную систему сборки или он будет всегда "успешно завершаться" даже при ошибках.
24. Проектирование API системной библиотеки
Проблема:
Плохо спроектированный API системной библиотеки – это долгосрочная проблема: его используют другие разработчики, изменить обратно несовместимым образом сложно, а последствия ошибок проектирования ощущаются годами.
Решение:
Промпт создает продуманный API с явным анализом удобства использования, обработки ошибок и обратной совместимости.
Текст промпта:
*****
Ты – [укажите роль, например, “архитектор системных библиотек с опытом проектирования публичных API для системного программного обеспечения на C”].
Спроектируй API для следующей системной библиотеки:
Назначение библиотеки: [опишите назначение, например, “библиотека для работы с разделяемой памятью: создание, отображение, синхронизация доступа”] Целевые пользователи: [опишите пользователей, например, “разработчики системного ПО на C, опыт работы с POSIX API”] Требования к API: [укажите требования, например, “простота использования для типичных случаев, гибкость для сложных, четкая семантика ошибок”]
Проектирование должно включать:
- Заголовочный файл с полными объявлениями функций, типов и констант с документирующими комментариями.
- Для каждой функции: назначение, предусловия, постусловия, возможные ошибки.
- Стратегию обработки ошибок: через errno, коды возврата или структуру ошибки – с обоснованием выбора.
- Примеры типичного использования: минимальный пример и расширенный.
- Анализ потенциальных ловушек для пользователей API и как их предотвратить через дизайн.
- Стратегию версионирования для будущих изменений без нарушения обратной совместимости.
Ограничения: API должен следовать принципу наименьшего удивления, ошибки должны быть обнаружимы на этапе компиляции где это возможно.
*****
Почему это работает:
Требование анализировать "ловушки для пользователей API" и предотвращать их через дизайн – это переход от "что делает функция" к "как ее сложно использовать неправильно", что является ключевым критерием качества API.
25. Реализация механизма сторожевого таймера
Проблема:
Системы без механизма восстановления после зависания могут застревать в некорректном состоянии на неопределенное время – особенно критично для встроенных устройств без возможности ручного перезапуска.
Решение:
Промпт создает надежный механизм сторожевого таймера с корректной интеграцией в систему и обработкой различных сценариев сбоя.
Текст промпта:
*****
Ты – [укажите роль, например, “разработчик надежных встроенных систем с опытом реализации механизмов самовосстановления и сторожевых таймеров”].
Реализуй механизм сторожевого таймера для следующей системы:
Платформа: [укажите платформу, например, “микроконтроллер STM32 с аппаратным независимым сторожевым таймером (IWDG)” или “Linux-система с программным сторожевым таймером через /dev/watchdog”] Архитектура системы: [опишите архитектуру, например, “несколько независимых задач FreeRTOS, каждая должна сообщать о своей работоспособности”] Требования: [укажите требования, например, “сброс системы при зависании любой критической задачи, журналирование причины сброса в энергонезависимой памяти”]
Реализация должна включать:
- Инициализацию и настройку сторожевого таймера с выбором таймаута.
- Механизм "кормления" таймера: как каждая задача сообщает о работоспособности.
- Определение критических задач и стратегию: что считается зависанием.
- Сохранение диагностической информации перед сбросом: какая задача не ответила, состояние системы.
- Чтение и анализ причины предыдущего сброса при старте системы.
Объясни: почему выбранный таймаут является компромиссом между чувствительностью к зависаниям и ложными срабатываниями при высокой нагрузке.
Ограничения: механизм кормления таймера должен быть устойчив к ошибкам в логике самого механизма (не должен кормить таймер при зависшей задаче мониторинга).
*****
Почему это работает:
Требование обеспечить устойчивость самого механизма кормления таймера к зависанию – это нетривиальное требование, которое обычно упускается и которое превращает "красивую" реализацию в реально работающую защиту.
26. Написание документации к системному коду
Проблема:
Документация системного кода часто либо описывает очевидное ("функция возвращает значение"), либо упускает критически важные детали о предусловиях, владении памятью и потокобезопасности.
Решение:
Промпт создает содержательную документацию, которая отвечает на вопросы следующего разработчика до того, как он их задаст.
Текст промпта:
*****
Ты – [укажите роль, например, “технический писатель со специализацией в документировании системного программного обеспечения на C”].
Напиши документацию для следующего системного кода:
[вставьте код или описание модуля, например, “модуль управления пулом соединений: создание, получение, возврат, уничтожение”] Аудитория: [укажите аудиторию, например, “разработчики, которые будут использовать API, но не читали исходный код”] Формат: [укажите формат, например, “Doxygen-совместимые комментарии к функциям + README для модуля”]Документация должна содержать для каждой функции:
- Краткое описание (одна строка) и подробное описание с примером использования.
- Предусловия: что должно быть выполнено до вызова.
- Постусловия: что гарантируется после успешного вызова.
- Параметры: тип, назначение, допустимые значения, владение памятью (кто освобождает).
- Возвращаемое значение и все возможные коды ошибок с объяснением причин.
- Потокобезопасность: можно ли вызывать из нескольких потоков одновременно.
- Ограничения: что нельзя делать (вызывать из контекста прерывания, держать блокировку при вызове и т.д.).
Ограничения: не документировать очевидное, фокусироваться на неочевидных деталях и потенциальных ловушках.
*****
Почему это работает:
Явное требование документировать владение памятью и потокобезопасность – это именно те аспекты, которые следующий разработчик не сможет вывести из кода без глубокого изучения всей реализации, и именно они чаще всего становятся источником ошибок.
27. Рефакторинг устаревшего системного кода
Проблема:
Рефакторинг системного кода без четкого плана и понимания рисков часто превращается в "починили одно – сломали другое", особенно когда код содержит неочевидные зависимости и побочные эффекты.
Решение:
Промпт создает структурированный план рефакторинга с явным анализом рисков и стратегией проверки корректности на каждом шаге.
Текст промпта:
*****
Ты – [укажите роль, например, “опытный разработчик системного программного обеспечения с опытом безопасного рефакторинга критически важного кода”].
Разработай план рефакторинга следующего устаревшего системного кода:
[вставьте код или описание модуля, например, “монолитный модуль обработки данных на 3000 строк, написанный 10 лет назад, без тестов, с глобальными переменными и смешанной ответственностью функций”] Цели рефакторинга: [укажите цели, например, “разделить на независимые модули, устранить глобальное состояние, добавить покрытие тестами”] Ограничения: [укажите ограничения, например, “нельзя менять публичный API, система работает в production, нельзя допустить регрессию поведения”]План должен включать:
- Анализ текущего состояния: что именно делает код, какие есть скрытые зависимости и побочные эффекты.
- Стратегию рефакторинга: последовательность изменений от наименее рискованных к наиболее рискованным.
- Для каждого шага: что меняется, какой риск, как проверить что ничего не сломалось.
- Стратегию добавления тестов: как тестировать код без изменения его поведения (характеризующие тесты).
- Метрики успеха: как измерить что рефакторинг достиг целей.
Ограничения: каждый шаг должен оставлять систему в рабочем состоянии, никаких "больших взрывов" – только инкрементальные изменения.
*****
Почему это работает:
Требование инкрементальных изменений с проверкой работоспособности после каждого шага – это принципиальное отличие от "переписать с нуля", которое кажется привлекательным, но чаще всего заканчивается месяцами работы и новыми ошибками в старых местах.
Типичные ошибки при использовании нейросети в работе системного программиста
- Отправлять код без указания целевой платформы и версии ядра. Нейросеть может использовать API, устаревший три версии назад, и код будет выглядеть правильно, но не скомпилируется или сломается во время выполнения.
- Просить написать "безопасный код" без указания модели угроз. Безопасность от случайных ошибок и безопасность от намеренных атак – это разные задачи с разными решениями, и без уточнения нейросеть выберет произвольно.
- Принимать сгенерированный ассемблерный код без проверки соглашений о вызовах. Нейросеть может перепутать соглашения или пропустить сохранение регистров, что проявится как случайное повреждение данных в вызывающем коде.
- Не указывать ограничения контекста выполнения при запросе кода для ядра. Код, корректный в пользовательском пространстве, в контексте ядра может привести к панике из-за вызова функций, недопустимых в данном контексте.
- Запрашивать оптимизацию без данных профилировщика. Без реальных данных о том, где тратится время, нейросеть будет оптимизировать то, что выглядит медленным, а не то, что реально является узким местом – классическое преждевременное улучшение.
- Не проверять сгенерированный код на граничных условиях и путях ошибок. Нейросеть хорошо пишет "счастливый путь", но часто пропускает корректную обработку ошибок при выделении памяти, системных вызовах и граничных значениях входных данных.
- Запрашивать реализацию алгоритмов без блокировок без указания модели памяти. Алгоритм без блокировок, правильный на x86, может быть некорректен на ARM из-за более слабой модели памяти – это не теоретическая проблема, а реальный источник труднообнаруживаемых ошибок.
- Использовать сгенерированный код драйвера без проверки управления ресурсами в пути ошибки. Нейросеть часто корректно освобождает ресурсы при успешной инициализации, но пропускает правильную очистку при частичной инициализации – это приводит к утечкам в ядре.
- Не указывать требования к детерминированности при запросе кода для систем реального времени. Функция с недетерминированным временем выполнения (например, использующая динамическое выделение памяти) в системе реального времени нарушает временные гарантии, даже если в среднем работает достаточно быстро.
Сравнение слабых и сильных запросов к нейросети для задач системного программирования
| Задача | Слабый запрос | Сильный запрос | Почему важна разница |
| Анализ утечек памяти | Найди утечки памяти в этом коде | Проанализируй все пути выполнения функции, включая пути ошибок, найди места где выделенная через malloc память не освобождается, укажи номер строки и сценарий | Без указания "все пути" нейросеть анализирует только основной путь и пропускает утечки при ошибках |
| Написание драйвера | Напиши драйвер для Linux | Напиши драйвер символьного устройства для Linux 5.15, используй cdev API, обеспечь корректное освобождение ресурсов в exit даже при частичной инициализации | Без версии ядра используется устаревший API, без указания частичной инициализации пропускается критическая часть логики очистки |
| Оптимизация кода | Оптимизируй эту функцию | Оптимизируй функцию, вызываемую 10 млн раз/сек на Intel Core i7, данные профилировщика: 40% промахи кэша L1, анализируй по уровням от алгоритмического до инструкций | Без данных профилировщика оптимизируется не то место, без уровней анализа упускается системный подход |
| Синхронизация потоков | Исправь состояние гонки | Найди все общие ресурсы, для каждого опиши конкретный сценарий гонки с последовательностью событий, предложи исправление сохраняющее параллелизм | Без требования описать сценарий нейросеть дает теоретический анализ без проверяемого воспроизведения |
| Код для ядра | Напиши обработчик прерывания | Напиши обработчик прерывания UART для STM32F4 с FreeRTOS, передача данных через кольцевой буфер без блокировок, объясни что запрещено в контексте прерывания | Без указания ОС и ограничений контекста нейросеть может использовать блокирующие функции, недопустимые в обработчике прерывания |
| Безопасность кода | Сделай парсер безопасным | Данные от внешних клиентов считать враждебными, защити от целочисленного переполнения при вычислении размеров, выхода за границы буфера, перечисли все потенциально уязвимые места | Без явного указания "враждебные данные" нейросеть закрывает только случайные ошибки, игнорируя намеренные атаки |
| Документирование | Задокументируй этот код | Документируй для разработчиков-пользователей API: предусловия, постусловия, владение памятью, потокобезопасность, что нельзя делать – фокус на неочевидных деталях | Без конкретных требований документация описывает очевидное и упускает критические детали о владении ресурсами и ограничениях использования |
Советы по работе с нейросетью для системного программиста
- Всегда указывайте версию ядра или компилятора в запросах о системном коде. API ядра Linux меняется между версиями, и нейросеть без этой информации может сгенерировать синтаксически корректный код, который не скомпилируется на вашей версии из-за изменений в интерфейсах.
- Просите нейросеть перечислить все допущения, которые она сделала при генерации кода. Системный код критически зависит от предположений о среде выполнения, и скрытые допущения – это источник ошибок, которые проявляются только при изменении условий.
- Разделяйте запрос на "спроектируй" и "реализуй" как два отдельных обращения. Нейросеть, получившая сразу задачу на реализацию, пропускает этап проектирования и выдает первое пришедшее в голову решение – часто не оптимальное для системных задач.
- При запросе кода для работы с памятью отдельно просите перечислить все пути, где выделенная память освобождается. Это заставляет нейросеть явно проследить каждый путь выполнения вместо того, чтобы убедиться только в наличии вызовов освобождения памяти.
- Используйте итеративный подход: сначала получите скелет, затем уточняйте каждый компонент отдельно. Запрос "напиши полный драйвер" дает поверхностный результат, а "напиши только обработчик ioctl для драйвера с такими характеристиками" – детальный и проработанный.
- После получения кода отдельным запросом просите нейросеть сыграть роль злоумышленника и найти способы сломать написанный код. Смена роли с "автора" на "атакующего" активирует другой режим анализа и выявляет уязвимости, которые автор кода неосознанно игнорирует.
- Сохраняйте успешные промпты для системных задач в отдельный файл с пометкой о версии ядра и платформе. Запросы для системного программирования содержат много специфического контекста, и воссоздать точную формулировку, дающую нужный результат, значительно сложнее, чем в прикладных задачах – а удачные шаблоны для работы с нейросетью в области системного программирования экономят часы при следующей похожей задаче.