[cdev] обсуждение реализации ps
Grigoriy A. Sitkarev
sitkarev на komitex.ru
Пн Мар 15 22:23:20 MSK 2010
Отвечу по-порядку.
Анатолий Кораблёв пишет:
> Все таки мне совершенно не понятен смысл перегружать структуру process
> указателем на следующй элемент списка (struct process *next) и можно сказать
> усложнять читаемость кода.
> Как оговаривалось с субботу может появиться необходимость расширить
> функционал программы и создавать динамический массив процессов после
> применения фильтра - тогда как раз структура process в текущем виде может
> оказаться более внятной.
> При наличиии отдельной структуры для связного списка сама структыра
> программы становится более понятной для чтения (четко видно что есть связный
> список структур-процессов а не какая то двусмысленная структыра которая для
> каждого процесса определяет некоторый следующий процесс) и более гибкой
> (позволяет легко расширить этот список до более сложных структыр не
> переписывая половину кода). Поэтому позволю себе не согласиться с тем, что
> уплотнение структуры "связный список процессов" до одной структуры является
> оправаднным (выигрыш в быстродействии минимален а читаемость кода резко
> ухудшается и появляется двусмысленность структуры).
Правильно делаете что сомневаетесь.
В Си программах это идиоматический приём - включение в структуру
описателя указателей, которые позволяют формировать различные структуры
(списки, деревья и т.д.). В таком случае сразу видно что из них будет
формироваться список или много списков. А глобальная переменная, которая
будет указывать на начало списка, снабжается комментарием.
struct process *plist; /* list of processes data */
Си упаковывает структуры в том порядке, в каком они перечислены в
определении. Сейчас ваша struct tnode аналогична структуре:
struct process {
int pid;
char state;
...
struct process *next;
};
и она здесь лишняя.
А надо бы:
struct process {
struct process *next;
int pid;
char state;
...
};
Это идиома в Си и никакой двусмысленности здесь нет, также как и
ухудшения читаемости.
Если тебе надо будет хранить этот элемент в ещё одном списке, то вы
добавите ещё один указатель.
Список бы тогда вы обходили так:
struct process *pp;
for (pp = plist; pp != NULL; pp = pp->next) {
...
}
что тоже является идиомой. И никаких счётчиков не надо.
Когда вы будете делать сортированный массив, то вы будете делать массив
указателей - struct process **. Если там будет абстрактный void ** то
это тоже оправдано только в случае если вы пишете абстрактный тип
"массив указателей". Уловили в чём соль?
С производительностью тоже дело такое, indirections ведут к тому что кеш
используется неэффективно. И на самом деле производительность там
заметно возрастает. По этой же причине часто самые простые алгоритмы
оказываются быстрее чем сложные. Честно - массив это самая эффективная
структура, всё дело в кеше.
> С удовольствием уже сейчас услышу про получение количества тиков в секунду и
> про использование lookup table - не целыми же днями готовиться к экзамену -
> ночью можно и код пописать.
Про тики я вам расскажу, а вот как вам завернуть в цикл распечатку
заголовка и таблицы подумаете сами. Подумайте, какие данные вам нужны
для этого, какими полями они должны быть представлены в структуре,
сформируйте такую структуру, статически инициализируйте её. Потом
напишите в цикле уже вывод.
По поводу тиков идея такая ещё появилась:
а) в /proc/uptime есть два числа, в первом секунды uptime системы во
втором секунды в течении которых система простаивала без загрузки.
б) в /proc/stat в строке, начинающейся с "cpu " дано четыре числа. Сумма
этих чисел - количество тиков прошедших с момента инициализации
системы, т.е. времени отсчёта uptime.
Если мы возьмём (uptime / total_ticks) то получим приблизительно сколько
у нас тиков в секунду. Это в теории. На практике при чтении файлов и
выковыривании полей у нас могут быть задержки, и надо проверить что
промежуток времени, в течении которого читались файлы из /proc, был
небольшой. Считать надо аккуратно, да ещё и прикинуть погрешность и если
она велика, заново пересчитать (перечитать) значения.
Далее, примерно прикинуть, по результату, какое CONFIG_HZ могло быть в
ядре. В нашем случае можно ограничиться случаями 100 Hz, 250 Hz и 1000
Hz. Хотя для других архитектур там могут быть и другие значения.
> Что касается предыдущих замечаний - все замечания выписаны отдельно и будут
> исправлены в обязательном порядке - просто есть привычка сначала
> реализовывать функционал и порадоваться за то, что хоть что то работает, а
> затем уже "причесывать" код.
Хорошо, если так.
--
Г.А.
Подробная информация о списке рассылки cdev