Всем привет!

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

Мне 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, так и других будущих проектов — чтобы они были не просто учебными, а реально полезными

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