# nice -n-19 p4-2 10
Rescheduling interval = 3.99939 msec.
Threads scheduling time: 5919.82 msec. [3165049513 cycles]
# nice -n-19 p4-1 10
Rescheduling interval = 3.99939 msec.
Forks scheduling time: 5962.21 msec. [3187713371 cycles]
# nice -n-19 p4-3 10 50
Rescheduling interval = 0.197788 msec
Single scheduling time: 6427.33 msec. [3436394566 cycles]
# nice -n-19 p4-2 10 50
Rescheduling interval = 0.197788 msec.
Threads scheduling time: 6207.96 msec. [3319104030 cycles]
# nice -n-19 p4-1 10 50
Rescheduling interval = 0.197788 msec
Forks scheduling time 6029.23 msec. [3223548073 cycles]
# nice -n-19 p4-3 10 20
Rescheduling interval = 0.077104 msec.
Single scheduling time: 6745.37 msec. [3606433666 cycles]
# nice -n-19 p4-2 10 20
Rescheduling interval = 0.077104 msec
Threads scheduling time: 6762.69 msec [3615692975 cycles]
# nice -n-19 p4-1 10 20
Rescheduling interval = 0.077104 msec
Forks scheduling time: 6647.42 msec [3554062343 cycles]
# nice -n-19 p4-3 10 11
Rescheduling interval = 0.04358 msec
Single scheduling time. 7517.74 msec [4019381476 cycles]
# nice -n-19 p4-2 10 11
Rescheduling interval = 0.04358 msec
Threads scheduling time: 7638.89 msec. [4084155676 cycles]
# nice -n-19 p4-1 10 11
Rescheduling interval = 0.04358 msec.
Forks scheduling time: 7679 29 msec. [4105758575 cycles]
# nice -n-19 p4-3 10 10
Rescheduling interval = 0.036876 msec.
Single scheduling time: 7937.35 msec. [4243731124 cycles]
# nice -n-19 p4-2 10 10
Rescheduling interval = 0.036876 msec.
Threads scheduling time. 8136.42 msec. [4350159949 cycles]
# nice -n-19 p4-1 10 10
Rescheduling interval = 0.036876 msec
Forks scheduling time: 8172.35 msec [4369372230 cycles]
Результаты могут показаться достаточно неожиданными: во всех 3-х вариантах (в группах) это практически одни и те же цифры — различия затрат на выполнение и в едином последовательном потоке, и во многих параллельных процессах (как предельные случаи) не превышают 0,5–2%! Но результат есть результат, и его нужно как-то интерпретировать, ведь, как известно, «из песни слова не выкинешь».
Эти результаты позволяют (пусть грубо и оценочно) «разложить» затраты производительности между обслуживанием системного таймера (службы времени ОС) и диспетчеризацией. Еще раз обратимся к отдельным выборочным результатам:
# nice -n-19 p4-3 10
Rescheduling interval = 3.99939 msec.
Single scheduling time: 5928.8 msec. [3169850746 cycles]
To есть на протяжении «работы» было 5928,8/0,9998475 = 5929 прерываний от службы времени.
# nice -n-19 p4-3 10 10
Rescheduling interval = 0.036876 msec
Single scheduling time: 7937.35 msec. [4243731124 cycles]
На этот раз за счет уменьшения периода системного тика на 2 порядка на протяжении «работы» (того же объема полезной работы!) было уже 7937,35/0,009219 = 860977 событий диспетчеризации.
Поскольку объем работы программы, выполняемый в этих двух случаях, остается неизменным, то на обслуживание дополнительных 860 977 – 5929 = 855 048 системных тиков (совместно с 855 048/4 = 213 762 точками диспетчеризации) и потребовались те 4 243 731 124 – 3 169 850 746 = 1 073 880 378 дополнительных тактов процессора, или около 1256 тактов на один системный тик. Ранее мы уже получали оценки затрат собственно на переключение контекстов между процессами (617) и потоками (374), которые происходят каждый четвертый системный тик, то есть непосредственно переключение контекста «отъедает» в среднем 90–150 (¼ часть затрат переключения контекста) на каждый системный тик или, другими словами, не более 10% затрат на обслуживание службы системных часов.
Попытаемся осмыслить полученные результаты:
• Время переключения адресных пространств процессов, управляемых MMU аппаратно, в принципе должно быть продолжительнее времени переключения контекстов потоков и тем более восстановления контекста единого последовательного потока, но…
• …но объем работы по обслуживанию каждого системного тика (прерывания таймера) настолько превышает объем операций переключения контекстов (рис. 2.7), что это практически полностью нивелирует разницу, будь то приложение в виде многих автономных процессов, многопоточное приложение или приложение в виде единого последовательного потока.
Рис. 2.7. Эффекты, возникающие при принудительном изменении частоты системных часов
На рис. 2.7 показана последовательность тиков системных часов и связанная с нею последовательность актов диспетчеризации. При уменьшении периода наступления системных тиков (частоты аппаратных прерываний от системных часов) в силу фиксированных объемов операций, требуемых как для одних, так и для других действий, относительная доля времени, остающаяся для выполнения полезной работы, падает.
• И это будет выполняться не только для потоков, диспетчеризуемых с дисциплиной RR (вытесняемых по истечении бюджета времени выделенного им кванта), но и для потоков с любой дисциплиной диспетчеризации, в том числе и FIFO, когда выполняющийся поток (а значит, поток наивысшего приоритета в системе) вообще «не собирается» никому передавать управление.
• Для программиста-разработчика результаты этого теста позволяют сформулировать правило, возможно абсурдное с позиций элементарной (но поверхностной) логики: Распараллеливание задачи (если это возможно) на N ветвей (будь то использование потоков или процессов) практически не изменяет итоговое время ее выполнения.
Еще одним побочным результатом рассмотрения можно назвать следующее: эффективность диспетчеризации потоков (сохранения и переключения контекстов), принадлежащих одному процессу, ни в чем не превосходит эффективность диспетчеризации группы потоков, принадлежащих различным