Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Динамический расчет приоритета



В предыдущем подразделе мы касались специфики динамического расчета приоритетов задач. Приоритет задачи основан на ее поведении в прошлом, а также на определенном пользователем значении nice. Функцией, динамически определяющей новый приоритет задачи, является recalc__task__prio ():

kernel/sched.с

3 81 static void recalc_task_prio(task_t *p, unsigned long long now)

382 {

3 83 unsigned long long sleep_time = now - p-> timestamp;

3 84 unsigned long sleep_time;
385

3 86 if ( sleep_time > NS_MAX_SLEEP_AVG)

3 87 sleep_time = NS_MAX_SLEEP_AVG;

388 else

3 89 sleep_time = (unsigned long) sleep_time;

391 if (likely(sleep_time > 0)) {

392 /*

3 93 * Слишком долго спавшая задача категоризируется как

3 94 * простаивающая и получает статус интерактивной для того, чтобы


Планировщик Linux



3 95 * оставаться в активном состоянии, предотвращать блокировки

396 * процессора и простой других процессов.

397 */

398 if (p-> ram & & p-> activated! = -1 & &

399 sleep__time > INTERACTIVE_SLEEP(p) ) {

400 p-> sleep_avg = JIFFIES_TO_NS(MAX_SLEEP_AVG -

401 AVG_TIMESLICE);

402 if (! HIGH_CREDIT(p))

403 p-> interactive_credit++;

404 } else {

405 /*

406 * Чем меньше sleep avg задачи,

407 * тем чаще увеличивается ее время сна.

408 */

409 sleep_time *= (MAX_BONUS - CURRENT_BONUS(р))? : 1; 410

 

411 /*

412 * Задача с низким значением интерактивности ограничивается

413 * одним временным срезом в размере бонуса sleep avg.

414 */

415 if (LOW_CREDIT(p) & &

416 sleep_time > JIFFIES_TO_NS(task_timeslice(p)))

417 sleep_time = JIFFIES_TO_NS(task_timeslice(p));
418

419 /*

420 * Задачи без high_credit, пробуждающиеся от беспрерывного

421 * сна, ограничиваются в росте sleep_avg/ так как они

422 * смогут заблокировать процессор, ожидая ввода-вывода

423 */

424 if (p-> activated == -1 & & ! HIGH_CREDIT(p) & & p-> ram) {

425 if (p-> sleep_avg > = INTERACTIVE_SLEEP(p))

426 sleep_time = 0;

427 else if (p-> sleep_avg + sleep_time > =

428 INTERACTIVE_SLEEP(p)) {

429 p-> sleep_avg = INTERACTIVE_SLEEP(p);
43 0 sleep_time = 0;

431 }

432 }
433

434 /*

43 5 * Этот код награждает бонусом интерактивные задачи.

436 *

437 * Это награждение работает с помощью обновления значения

438 * 'average sleep time' на основе -> timestamp. Чем больше 43 9 * времени задача тратит на сон, тем больше average -440 * и выше получаемый приоритет.



Глава 7 • Планировщик и синхронизация ядра


441 */

442 p-> sleep_avg += sleep_time; 443

444 if (p-> sleep_avg > NS_MAX_SLEEP_AVG) {

445 p-> sleep_avg = NS_MAX_SLEEP_AVG;

446 if (! HIGH_CREDIT(p))

447 p-> interactive_credit++;

448 }

449 }

450 }
452

452 p-> prio = effective_prio(p);

453 }

Строки 386-389

На основе времени now мы рассчитываем длительность времени, в течение ко­торого будет спать процесс р, и назначаем sleep_time максимальное значение NS_MAX_SLEEP_AVG. (По умолчанию NS__MAX_SLEEP_AVG равняется 10 мс.)

Строки 391-404

Если процесс р спит, мы сначала проверяем, спит ли он достаточно для того, чтобы задачу можно было классифицировать как интерактивную. Если это так, мы изменя­ем среднее время сна процесса с помощью sleep_tiirie-> INTERACTIVE_ SLEEP (p), а если р классифицируется не как интерактивный процесс, мы уве­личиваем interactive_credit для р.

Строки 405-410

Задача с меньшим временем сна получает большее время сна.

Строки 411-418

Если задача интенсивно нагружает процессор и она классифицирована не как ин­терактивная, мы ограничиваем процесс как минимум одним временным срезом, рав­ным бонусу в виде среднего времени сна.

Строки 419-432

Задачи, еще не классифицированные как интерактивные (без HIGH_CREDIT), раз­буженные от беспрерывного сна, и получают среднее время сна INTERACTIVE ().

Строки 434-450

Мы добавляем новое рассчитанное sleep_time к среднему времени сна процесса, проверяя, чтобы оно не превысило NS_MAX_SLEEP_AVG. Если процессы не призна­ны интерактивными, но спали максимальное время, мы увеличиваем их значение интерактивности.


7.1 Планировщик Linux



Строка 452

Наконец, приоритет устанавливается с помощью ef fective_prio () с учетом нового рассчитанного поля sleep_avg для р. Это делается с помощью масшта­бирования среднего времени от 0 до MAXSLEEPAVG в диапазоне от -5 до +5. Поэтому процесс со статическим приоритетом 70 может иметь динамический приоритет в пределах от 65 до 85, в зависимости от своего поведения в прошлом.

И еще одна финальная черта: процесс, не являющийся процессом реального времени, попадает в диапазон от 101 до 140. Процессы, обрабатываемые с большим приоритетом, попадают в диапазон 105 и ниже, хотя и не могут перевалить за барьер процессов реаль­ного времени. Поэтому интерактивный процесс с большим приоритетом может никогда не иметь динамического приоритета ниже 101. (В конфигурации по умолчанию процессы реального времени покрывают диапазон от 0 до 100.)

Вывод из активного состояния

Мы уже обсуждали, как задача попадает в планировщик после вызова fork и как задача перемещается из массивов активных приоритетов в истекшие в очереди выполнения на процессоре. Но когда же задача удаляется из очереди выполнения?

Задача может быть удалена из очереди выполнения двумя основными способами:

• задача прерывается ядром и изменяет состояние на незапущенное, после чего в задачу перестают поступать сигналы (см. строку 2240 в kernel/sched. с);

• на SMP-машинах задача может быть удалена из очереди выполнения и помещена в другую очередь выполнения (см. строку 3384 в kernel /sched. с).

Первый случай происходит, когда schedule () вызывается после того, как процесс погружается в сон в очереди ожидания. Задача помечает себя как невыполняемая (TASK_INTERRUPTIBLE, TASK_UNINTERRUPTIBLE, TASK_STOPPED и т. д.), и ядро перестает предоставлять ей доступ к процессору, удаляя ее из очереди выполнения.

Случай, когда процесс перемещается в другую очередь выполнения, обрабатывается в SMP-разделе ядра Linux, который мы здесь не рассматриваем.

Теперь мы проследим, как процесс удаляется из очереди выполнения с помощью deactivate_task ().

kernel/sched.c

507 static void deactivate_task(struct task_struct *p, runqueue_t *rq)

508 {

 

509 rq-> nr_running—;

510 if (p-> state == TASK_UNINTERRUPTIBLE)

511 rq-> nr_uninterruptible++;

512 dequeue_task(p, p-> array);



Глава 7 • Планировщик и синхронизация ядра


513 p-> array = NULL;

514 }

Строка 509

Сначала планировщик уменьшает количество запущенных процессов, так как р больше не является запущенной.

Строки 510-511

Если задача непрерывна, мы увеличиваем количество непрерывных задач в очереди выполнения. Соответствующие операции декрементации вызываются, когда непрерывный процесс просыпается [см. строку 824 в kernel/sched.c в функции try_to__wake___up () ].

Строки 512-513

Статистика нашей очереди выполнения обновляется, как только мы удаляем процесс из очереди выполнения. Ядро использует поле р-> аггау для проверки то­го, является ли процесс запущенным и находится ли он в очереди выполнения. Так как больше ни одно из этих условий не выполняется, мы устанавливаем его в NULL.

Необходимо сделать еще кое-что с очередью выполнения; давайте рассмотрим спе­цифику dequeue__task ().

kerne1/sched.с

3 03 static void dequeue_task(struct task_struct *p, prio_array__t

*array)

304 {

305 array-> nr_active—;

3 06 list_del(& p-> run_list);

307 if (list_empty(array-> queue + p-> prio))

308 clear__bit (p-> prio/ array-> bitmap);

309 }

Строка 305

Мы изменяем количество активных задач в массиве приоритетов, в котором нахо­дится процесс р; не важно, активный ли это массив или истекший.

Строки 306-308

Мы удаляем процесс из списка процессов в массиве приоритетов с приоритетом р. Если результирующий список будет пустым, нам нужно очистить бит в битовой карте массива приоритетов для того, чтобы указать, что в p-> prio () не осталось процессов.


7.2 Приоритетное прерывание обслуживания



list_.de 1 () выполняет всю работу по удалению за один шаг, так как р-> run_list представляет собой структуру list_head и поэтому содержит указате­ли на предыдущее и следующее вхождения в списке.

Мы достигли точки, где процесс удаляется из очереди выполнения и становится пол­ностью неактивным. Если этот процесс находится в состоянии TASK_INTERRUPTIBLE или TASK_UNINTERRUPTIBLE, он может быть разбужен и помещен обратно в очередь выполнения. Если процесс находится в состоянии TASK_STOPPED, TASK_ZOMBIE или TASK_DEAD, все его структуры удаляются и сбрасываются.


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-03-25; Просмотров: 920; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.029 с.)
Главная | Случайная страница | Обратная связь