Всем привет!

Пишу этот пост, чтобы поделиться своим опытом и получить критику или советы от людей с большим опытом.

Мне 22 года, я из Латвии. По образованию я судовой механик, но уже около 4 лет увлекаюсь программированием. Долгое время это оставалось хобби: пробовал сайты, простые игры — но они не приносили настоящего удовольствия. Я считал, что в программировании нужно было разбираться ещё со школы, и долго не верил, что могу найти себя в этой сфере.

Переломный момент наступил, когда я заинтересовался системным программированием. Каждый раз, когда узнаю, как работает низкоуровневая часть ОС, у меня будто открывается новый мир. Особенно зацепила тема процессорного планирования: все говорят «железо, CPU, видеокарта», но на практике даже реализация планировщика процессов может заметно влиять на производительность.

Учёба и идея проекта

Год назад я поступил в университет на программу Computer Systems, чтобы увеличить свои шансы на работу в ИТ. Но, к сожалению, программа оказалась сильно смещена в сторону веба и сетей. Поэтому я сделал ставку на самообучение и параллельно развивался в системном направлении, а университет оставил для диплома.

На одном из экзаменов по ООП нужно было реализовать программу с применением объектно-ориентированного подхода. Тогда я решил совместить приятное с полезным — сделать первый серьезный pet-проект который:

  • можно защитить на экзамене;

  • покажет, что я "умею" проектировать и писать код;

  • и будет реально интересен мне самому.

Так родилась идея synd3 — сообственного процесс-менеджера для Linux.

От идеи до реализации

Когда я впервые познакомился с Linux через WSL (Windows Subsystem for Linux), мне понадобилось отслеживать нагрузку на систему. Я запустил htop — и сразу заметил, что отображение загрузки CPU идет по ядрам, а не по суммарной мощности процессора.
Мне захотелось сделать инструмент, который, по моему мнению, будет отображать статистику более "человечно" и интуитивно.

Мы работали над проектом вдвоем и решили разделить обязанности:

  • Логика на С,

  • Интерфейс (TUI) на С++ с использованием ncurses и ООП.

Сборка проекта осуществляется через простой Makefile, который компилирует оба модуля и связывает их.

Как synd3 работает внутри

Подсчет загрузки CPU

Основные данные synd3 получает из файлов /proc/stat и proc/[PID]/stat.
Для каждого процесса мы вычисляем разницу между его пользовательским (utime) и системным (stime) временем между двумя циклами опроса.
Затем результат нормализируется относительно общего CPU времени, чтобы получить процент загрузки.
Если "упростить", то мы измеряем, сколько тиков CPU досталось процессу за последний интервал, и сравниваем это с общим временем работы всех ядер за тот же промежуток.

Пример логики в упрощенном виде:

unsigned long long prev_total = total_ticks();
unsigned long long prev_proc = process_ticks(pid);

sleep(1);

unsigned long long total = total_ticks();
unsigned long long proc = process_ticks(pid);

double usage = 100.0 * (proc - prev_proc) / (total - prev_total);

Подсчет использование памяти

В synd3 для вычисления использования памяти реализована функция get_process_mem_usage(pid_t pid, float *mem_usage).
Она не просто считывает VmRSS а учитывает весь контекст использования памяти — в том числе кэш, буферы, и reclaimable-области, чтобы получить более точное значение реальной нагрузки.

Алгоритм выглядит примерно так:

  1. Считываются метрики /proc/meminfo: MemTotal, MemFree, Buffers, Cached, SReclaimable.

  2. Подсчитывается используемая память:
    used_mem = MemTotal - MemFree - Buffers - Cached - SReclaimable;

  3. Для каждого процесса извлекается VmRSS из /proc/[PID]/statm.

  4. Расчитывается процент использования памяти:
    *mem_usage = (VmRSS / used_mem) * 100.0;

При этом в коде учитываются ситуации, когда /proc[PID]/statm может временно отсутствовать (например, при завершении процесса), а так же ошибки при чтении.

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

интерфейс synd3 на текущий момент
интерфейс synd3 на текущий момент

Проблемы и неожиданные открытия

Когда мы впервые тестировали synd3, первое, что нас удивило — разное поведение программы под WSL и полноценным Linux. Тестируя программу на полноценном Linux, мы столкнулись с тем, что в synd3, отображались процессы без имени. У них был PID, однако имя отсутствовало. Нас это насторожило, так как тестируя на WSL, мы такой проблемы не наблюдали.
Оказалось, что в WSL процессы без имени не отображаются в /proc обычными средствами, из-за чего список в synd3 выглядел “аккуратнее”. Проще говоря, эти процессы “фильтруются“ и не видны.
На реальной системе же таких процессов много, и часть из них просто не имеет ничего в строке в /proc/[PID]/cmdline.
Проблема решилась добавлением одной проверки: если при чтении /proc/[PID]/cmdline функция fgets() возвращает NULL (что озночает, что строка пуста и у процесса нет имени), то такой процесс мы просто пропускаем.

Вторая проблема оказалась куда интереснее.
Изначально мы хотели, чтобы интерфейс обновлялся каждую секунду в отдельном потоке, пока логика считывает метрики. Но довольно быстро ncurses буквально "сломался" — текст начинал мигать разными цветами, символы наслаивались друг на друга, а вывод вел себя хаотично, будто "матрица" на минималках.

После нескольких бессоных вечеров и десятков printf-отладок мы наконец поняли причину:
ncurses не является потокобезопасной библиотекой.

Все операции по выводу должны выполнятся строго из одного потока, ина��е внутренние буферы ncurses начинают конфликтовать — именно поэтому происходила "рябь" и разъезжавшийся текст.

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

Да, интерфейс обновляется чуть реже, зато стабильно, без артефактов и цветных глюков.
Этот опыт, пожалуй, стал самым ценным: теперь мы четко понимаем, что TUI-библиотеки (вроде ncurses) требуют однопоточного вывода и аккуратного обращения с буферами.

Планы на будущее

  • Переписать проект полностью на С, отказаться от ООП и снизить уровень абстракции.

  • Сделать архитектуру ближе к POSIX.

  • Реализовать мониторинг потоков.

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

  • Улучшить интерфейс: добавить дерево процессов и адаптивную перерисовку при изменении размера окна.

Репозиторий проекта

Проект лежит на GitHub: oxonomiAK/synd3.

Зачем пишу

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

Мне также интересно, почему кто-то выбирает htop, а кто-то — btop++ или даже glances?
Что именно для пользователя важно в системных мониторах: функциональность, визуальная часть, минимализм, или, может быть, производительность?

Я хочу понять, какие решения делают подобные инструменты удобными и живыми, а не просто «ещё одним монитором процессов».

Всё это поможет точнее направлять развитие как synd3, так и других будущих проектов — чтобы они были не просто учебными, а реально полезными

Спасибо, что дочитали!