26 Mayıs 2017 Cuma

Linux Scheduler'ları

Process Scheduler
Process Scheduler koşmaya hazır durumdaki uygulamaları ve thread'leri sıraya koyar ve sırası geleni koşturur. Linux'ta 3 tip scheduling policy var.

Soft Real Time Nedir?
Standart Linux çekirdeği soft real time bir çekirdektir. Hard real time çekirdek elde etmek için RT PREEMPT gibi bazı yamalar kullanmak gerekir.

Soft Real Time zamanlamayı garanti etmez. En basit tabirle best effort olarak çalışır. Örneğin işi %97 oranında 20 ms. içinde tamamlar ancak bazen bu süreyi aşabilir.

Bu scheduler'ların amacı N tane işlemci varsa her zaman N tane en yüksek önceliğe sahip thread'i koşabilir hale getirmektir. Dolayısıyla soft real time sınıfları içinde daha iyi bir preemption elde edilir. Ancak kesin zamanla garantisinin halen verilmediğine dikkat etmek gerekir.

1. SCHED_OTHER
Linu Scheduler'ları yazısına taşıdım

2. SCHED_FIFO
Linu Scheduler'ları yazısına taşıdım

3. SCHED_RR
Linu Scheduler'ları yazısına taşıdım

4. SCHED_DEADLINE
Bunun ne olduğunu bilmiyorum.

POSIX Uygulama İçin Scheduler API'si
Scheduler'lara baktıktan sonra nasıl kullanacağımıza bakalım. POSIX scheduler için bir sürü API tanımlamış.

API'ler scheduler ve thread ile çalışanlar olarak iki grupta toplanabilir. Scheduler ile ilgili olanlar sched_XXX şeklinde. Thread ile ilgili olanlar pthread_XXX şeklinde.

Scheduler Sabitleri
SCHED_OTHER, SCHED_FIFO ve SCHED_RR scheduler tipleri için kullanılan sabitlerdir. Değerleri şöyle
/*
 * Scheduling policies
 */
#define SCHED_NORMAL    0
#define SCHED_FIFO      1
#define SCHED_RR        2
#define SCHED_BATCH     3
/* SCHED_ISO: reserved but not implemented yet */
#define SCHED_IDLE      5

sched_get_priority_min ve sched_get_priority_max
Her scheduler kendi içinde bir öncelik sırası da içerir. Minimum ve maximum öncelik sırası şöyle alınır.
#include <sched.h>
sched_get_priority_min(SCHED_OTHER),
sched_get_priority_max(SCHED_OTHER));
Örnek
Open BSD'den her scheduler'ın priority değeri şöyledir.
Valid priority range for SCHED_OTHER: 0 - 31
Valid priority range for SCHED_FIFO: 0 - 31
Valid priority range for SCHED_RR: 0 - 31
Örnek
Linux'ta her scheduler'ın priority değeri şöyledir. Bu sonuca göre Linux'ta SCHED_OTHER kullanan uygulamalar aynı priority değerine sahiptir. Aralarındaki tek fark nice değeridir.
Valid priority range for SCHED_OTHER: 0 - 0
Valid priority range for SCHED_FIFO: 1 - 99
Valid priority range for SCHED_RR: 1 - 99
Örnek
Şöyle yaparız.
sched_get_priority_max(SCHED_FIFO) = 99
sched_get_priority_min(SCHED_FIFO) = 1
sched_setscheduler
sched_setscheduler metodu yazısına taşıdım.

sched_setparam
sched_setparam ile uygulamanın önceliği atanabiliyor. Numara büyüdükçe, öncelik te artıyor.

POSIX Thread İçin Scheduler API'si
pthread_getschedparam metodu
Şöyle yaparız.
sched_param param;
int policy;
if(pthread_getschedparam(pthread_self(), &policy, &param) == 0) {
  ...
}
pthread_setschedparam metodu
Bu metod ile thread için yukarıda anlatılan scheduler'lardan birisi seçilebilir. Birinci parametre thread handle, ikinci parametre policy  (SCHED_FIFO vb.), üçüncü parametre sched_param yapısı.

Bu yapı ile sched_priority de atanabilir. Eğer istersek önce pthread_getschedparam () çağrısı ile mevcut değeri alıp aynen kullanabiliriz.

Bir projede policy olarak SCHED_FIFO ve sched_param.priority = 99 yapmıştım. Eğer çağrı başarılı ise 0 döner. Başarısız ise 0'dan farklı bir sonuç döner. Şöyle yaparız.
int priority = 99;
int policy = SCHED_FIFO;

sched_param param {};
param.sched_priority = priority;

int ret = pthread_setschedparam(pthread_self(), policy, &param);
if(ret != 0) { 
  ...Error...
}

pthread_setschedprio
Bu metod ile thread için öncelik sırası atanır. Örnekte direkt sched_get_priority_max kullanılmamış. Bunun yerine önce scheduler bulunuyor. Daha sonra en yüksek öncelik değeri bulunuyor ve bu değer thread'e atanıyor.
#include <pthread.h>

int main()
{
    pthread_t thId = pthread_self();
    pthread_attr_t thAttr;
    int policy = 0;
    int max_prio_for_policy = 0;
    //Scheduler'ı öğren
    pthread_attr_init(&thAttr);
    pthread_attr_getschedpolicy(&thAttr, &policy);
    max_prio_for_policy = sched_get_priority_max(policy);

    //Thread için en yüksek önceliği ata
    pthread_setschedprio(thId, max_prio_for_policy);
    pthread_attr_destroy(&thAttr);

    return 0;
}

Diğer Platformlar
Yazının bütünlüğü açısından diğer platformlarda da thread önceliğinin nasıl değiştirildiğine bakmak gerekir. Windows'ta da Linux'ta olduğu gibi scheduler'lar var. Yine aynı şekilde thread önceliğini değiştirmek mümkün.

Windows
SetPriorityClass
Bu metod ile farklı bir scheduler kullanılıyor.
SetPriorityClass(HProcess, REALTIME_PRIORITY_CLASS);
SetThreadPriority
Bu metod ile thread'in önceliği değiştiriliyor.Windows'ta thread önceliği için şu sabitler kullanılır.
  • THREAD_PRIORITY_IDLE (-15)
  • THREAD_PRIORITY_LOWEST (-2)
  • THREAD_PRIORITY_BELOW_NORMAL (-1)
  • THREAD_PRIORITY_NORMAL (0)
  • THREAD_PRIORITY_ABOVE_NORMAL (1)
  • THREAD_PRIORITY_HIGHEST (2)
  • THREAD_PRIORITY_TIME_CRITICAL (15)
SetThreadPriority(HThread, THREAD_PRIORITY_TIME_CRITICAL);
Bir başka örnek
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST);
Bir projede THREAD_PRIORITY_TIME_CRITICAL kullanmıştım.
Java
Thread.setPriority yazısına taşıdım

Process Scheduler ve CPU Affinity
Bir uygulamayı veya thread'i sistemdeki CPU'ya bağlamak için programın programlarken belli metodlar kullanılabilir veya komut satırından işlem gerçekleştirilebilir. Ancak unutulmaması gereken nokta, bir uygulamayı CPU'ya bağlamak diğer uygulamaların bu CPU'yu kullanmasını engellemez!

Linux
sched_setaffinity metodu yazısına taşıdım.

GNU
pthread_setaffinity_np
pthread_setaffinity_np metodu yazısına taşıdım

Komut Satırı
Linux'ta taskset komutu kullanılır.

Windows
SetProcessAffinityMask veya SetThreadAffinityMask kullanılabilir.


Process Scheduler ve Pre-Emptive Multitasking
Bu soruda Process Scheduler'ın donanım tarafından periyodik olarak çağırılan bir kesmeyi kullandığı, çalışan bir uygulamayı yarıda kesebileceği ve sırayı bir başka uygulamaya verebileceği anlatılıyor. Dolayısıyla burada da açıklandığı gibi Process Scheduler bir thread gibi değilde, direkt işlemci üzerinde koşuyor gibi düşünülmeli.


Çalışan uygulamayı yarıda kesme işlemine Pre-emptive multitasking deniyor. Türkçesi ise sanırım geçişli çoklu görev olarak kullanılıyor. Understanding the Linux Kernel bölüm 10'da güzel bilgiler mevcut.

Thread scheduling Round Robin / scheduling dispatch sorusunda ise kesme koduna ait bir örnek var.

Pre-emptive multitasking ile ses kartları arasında ilginç bir ilişki var. Bazen CPU ses kartının tampon belleğini doldurup başka işlerle meşgul olsa bile ses kartının donanımı müziği çalmaya devam edebiliyor.

I/O Scheduler
Process Scheduler sadece koşmaya hazır/koşan durumdaki uygulamalar ile ilgilenirken I/O Scheduler giriş/çıkış işlemleri için bekleyen uygulamaları yönetir.

Hiç yorum yok:

Yorum Gönder