Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Динамический расчет приоритета
В предыдущем подразделе мы касались специфики динамического расчета приоритетов задач. Приоритет задачи основан на ее поведении в прошлом, а также на определенном пользователем значении 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; 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)); 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); 431 } 432 } 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 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; Нарушение авторского права страницы