Написание системного вызова для подсчета переключений контекста процесса
Я должен сделать системный вызов для подсчета добровольных и непроизвольных переключений контекста процесса. Я уже знаю шаги по добавлению нового системного вызова в ядро Linux, но я понятия не имею, с чего начать для функции переключения контекста. Любая идея?
4 ответа
Если ваш системный вызов должен сообщать только статистику, вы можете использовать код подсчета переключений контекста, который уже находится в ядре.
системный вызов wait3 или системный вызов getrusage уже сообщает о количестве переключений контекста в struct rusage
поля:
struct rusage {
...
long ru_nvcsw; /* voluntary context switches */
long ru_nivcsw; /* involuntary context switches */
};
Вы можете попробовать это, запустив:
$ /usr/bin/time -v /bin/ls -R
....
Voluntary context switches: 1669
Involuntary context switches: 207
где "/bin/ls -R
это любая программа.
Ища "struct rusage" в исходниках ядра, вы можете найти этоaccumulate_thread_rusage
в kernel / sys.c, который обновляет структуру rusage. Это читает от struct task_struct *t
; поля t->nvcsw;
а также t->nivcsw;
:
1477 static void accumulate_thread_rusage(struct task_struct *t, struct rusage *r)
1478 {
1479 r->ru_nvcsw += t->nvcsw; // <<=== here
1480 r->ru_nivcsw += t->nivcsw;
1481 r->ru_minflt += t->min_flt;
1482 r->ru_majflt += t->maj_flt;
Тогда вы должны искать nvcsw
а также nivcsw
в папке ядра, чтобы найти, как они обновляются ядром.
asmlinkage void __sched schedule (void):
4124 if (likely(prev != next)) { // <= if we are switching between different tasks
4125 sched_info_switch(prev, next);
4126 perf_event_task_sched_out(prev, next);
4127
4128 rq->nr_switches++;
4129 rq->curr = next;
4130 ++*switch_count; // <= increment nvcsw or nivcsw via pointer
4131
4132 context_switch(rq, prev, next); /* unlocks the rq */
Указатель switch_count
из строки 4091 или строки 4111 того же файла.
PS: ссылка из perreal отличная: http://oreilly.com/catalog/linuxkernel/chapter/ch10.html (поиск context_swtch
)
Это уже существует: виртуальный файл /proc/NNNN/status
(где NNNN - это десятичный идентификатор процесса, о котором вы хотите знать) содержит, среди прочего, количество как произвольных, так и недобровольных переключений контекста. В отличие от getrusage
это позволяет узнать количество переключений контекста для любого процесса, а не только для детей. Увидеть proc(5)
man-страницу для более подробной информации.
Общее количество переключений контекста
cat /proc/PID/sched|grep nr_switches
Добровольные переключения контекста
cat /proc/PID/sched | grep nr_voluntary_switches
Непроизвольные переключения контекста
cat /proc/PID/sched|grep nr_involuntary_switches
где PID - это идентификатор процесса, который вы хотите отслеживать.
Однако если вы хотите получить эту статистику путем исправления (создания перехвата) источника Linux, код, связанный с планированием, присутствует в
ядро / Плановое /
папка исходного дерева. Особенно
В файле kernel / sched / core.c содержится функция schedule(), которая является кодом планировщика linux. Код CFS (полностью честный планировщик), который является одним из нескольких планировщиков, представленных в Linux, и наиболее часто используемый, присутствует в
/kernel/sched/fair.c
scheduler () выполняется, когда когда-либо установлен флаг TIF_NEED_RESCHED, поэтому выясните, из каких мест установлен этот флаг (используйте cscope в источнике linux), что даст вам представление о типах переключений контекста, происходящих в процессе.
Процесс выполнит переключение контекста в случае блокировки, истечения кванта времени или прерываний и т. Д. В конце концов вызывается функция schedule(). Поскольку вы хотите посчитать его для каждого процесса отдельно, вы должны сохранить новую переменную для каждого процесса для подсчета количества переключений контекста. И вы можете обновлять эту переменную каждый раз в расписании веселья для текущего процесса. Используя ваш системный вызов, вы можете прочитать это значение. Вот фрагмент расписания функции пинто,
static void
schedule (void)
{
struct thread *cur = running_thread ();
struct thread *next = next_thread_to_run ();
struct thread *prev = NULL;
ASSERT (intr_get_level () == INTR_OFF);
ASSERT (cur->status != THREAD_RUNNING);
ASSERT (is_thread (next));<br/>
if (cur != next)
prev = switch_threads (cur, next); <== here you can update count of "cur"
thread_schedule_tail (prev);
}