Невероятно высокое пользовательское и системное время, показанное командой time в Linux

Я запускаю следующую команду в каталоге с ~7000 файлами:

time find . | xargs -P8 -n1 grep -F 'xxx'

Результаты:

real    0m1.638s
user    1m1.090s
sys     0m5.080s

Я очень хорошо понимаю, что (user+cpu) может быть < or > cpuTime, но должно выполняться следующее ограничение:

(user + sys) < real * NCPU

Где NCPU — количество логических ядер в системе. В любой момент должно быть запущено не более процессов NCPU, которым назначено либо пользовательское, либо системное время. И все же у меня 12 логических ядер (6 реальных ядер x 2 гиперпотока), но 1.638 * 12 = ~20 seconds, тогда как мой процесс каким-то образом ухитрился потреблять больше минуты процессорного времени.

Субъективно 1.6s в реальном времени примерно соответствует (и я пробовал это на больших каталогах).

Воздействие со значением -P изменяет сообщаемое реальное и системное время, но оно выравнивается вокруг значения где-то около 8-12.

Обратите внимание, что ни один из файлов не содержит xxx, но результаты будут такими же, если я использую строку, которая получает несколько совпадений.


person BeeOnRope    schedule 10.03.2014    source источник
comment
Вы можете показать результат find . | wc -l? Linux может округлять пользовательское/системное время для кратковременных процессов...   -  person osgx    schedule 10.03.2014
comment
Также мне нужна точная версия вашего ядра uname -a для проверки его конфигов. Если у вас кастомное ядро, загрузите конфиг вашего ядра на какой-нибудь текстовый хостинг, например pastebin (проверьте /boot/).   -  person osgx    schedule 10.03.2014


Ответы (1)


Наиболее распространенный механизм учета «пользовательского» и «системного» времени в Linux основан на периодическом таймере. Этот метод неточен, особенно для коротких процессов:

http://www.cs.rochester.edu/courses/252/spring2014/notes/XX_timing

Ядро использует регулярные прерывания таймера для переключения контекста, доставки сигналов SIGALARM, отслеживания времени суток (буквально, путем подсчета тактов таймера), планирования задач учета и т. д.

Ядро ведет с каждым процессом подсчет того, сколько раз обработчик прерывания таймера нашел его (процесс) в (а) пользовательском режиме или (б) режиме ядра (системном). Эти подсчеты работают подобно статистическому профилированию gprof, чтобы дать вам хорошее представление, усредненное за длительный период времени, о том, какую часть времени выполнялся процесс и какую часть этого времени он провел в ядре (системе). ... Поскольку степень детализации статистической выборки примерно эквивалентна кванту планирования (~ 5-20 мс), интервальная синхронизация ужасно неточна для времени ниже примерно 100 мс. Даже сверх этого, это хорошо только с точностью до 10%. Это также имеет тенденцию взимать плату с процессов за некоторые накладные расходы на обработку прерываний таймера. Авторы сообщают, что в их системе Linux это завышает потребляемое время на 4-5%.

Также http://www.cs.toronto.edu/~demke/469F.06/Lectures/Lecture5.pdf слайды 5, 6, 7 «Точность интервального счета».

Если мы проверим базовую реализацию, то узнаем, что «процессорное» и «системное» время обновляются в kernel/timer.c файле ядра Linux, в «update_process_times» http://lxr.free-electrons.com/source/kernel/timer.c#L1349

1345 /*
1346  * Called from the timer interrupt handler to charge one tick to the current
1347  * process.  user_tick is 1 if the tick is user time, 0 for system.
1348  */
1349 void update_process_times(int user_tick)
1350 {
1351         struct task_struct *p = current;
1352         int cpu = smp_processor_id();
1353 
1354         /* Note: this timer irq context must be accounted for as well. */
1355         account_process_tick(p, user_tick);  // <<<<<<<<<<< here
1356         run_local_timers();
1357         rcu_check_callbacks(cpu, user_tick);
    ...
1362         scheduler_tick();
1363         run_posix_cpu_timers(p);
1364 }

"update_process_times" вызывается из tick_nohz_handler или tick_sched_timer -> tick_sched_handle (kernel/time/tick-sched.c#L147) и из tick_handle_periodic -> tick_periodic (kernel/time/tick-common.c#L90). Я думаю, что в некоторых случаях update_process_times может вызываться чаще, чем прерывание по таймеру.

person osgx    schedule 10.03.2014