Ders 04 / 22
Süreç Öncelikleri
En çok işleyen sürecin öncelik değeri en düşükten en yükseğe çekildiğinde payı 41.878 birimden 0'a iniyor, ama toplam iş 237.906'dan 238.244'e ve yük 3,97'den 3,97'ye gidiyor: boşalan kapasitenin yüzde 94'ü öteki ağır süreçlere, hafif süreçlere yüzde 0'ı gidiyor.
İçindekiler
Önceki ders süreci durdurmayı ölçtü. Durdurmak her zaman doğru yanıt değildir: ağır bir süreç gerekli bir iş yapıyor olabilir ve istenen şey onu bitirmek değil, yavaşlatmaktır. Bunun için tasarlanmış bir düğme vardır ve süreç tablosunun bir sütununda durur.
Bu ders o düğmeyi ölçer. Soru şudur: bir sürecin önceliğini değiştirmenin görülebilir etkisi ne kadardır, ve değişen sütun ile değişen davranış aynı şey midir.
Öncelik Değeri
Süreç tablosundaki NI sütunu öncelik değerini (nice value) taşır. Ölçeği terstir:
değer büyüdükçe sürecin önceliği düşer. Aralık -20 ile 19 arasındadır; -20 en
saldırgan, 19 en geri çekilmiş süreçtir. Varsayılan 0’dır.
Yanındaki PRI sütunu farklı bir şeydir. NI operatörün girdisidir; PRI çizelgeleyicinin
o girdiden ve sürecin geçmiş davranışından hesapladığı değerdir. Operatör PRI sütununu
doğrudan yazamaz. İkisini karıştırmak, girdi ile sonucu karıştırmaktır.
$ nice -n 10 ./yedek-gorevi --tam &
$ renice -n 5 -p 1014
1014 (process ID) old priority -5, new priority 5
$ renice -n 5 -u yedek
$ ps -eo pid,ni,pri,comm --sort=ni
PID NI PRI COMMAND
1014 -5 24 kuyruk-isleyici
1128 0 19 rapor-uretici
1043 5 14 olcum-toplayici
1071 10 9 yedek-gorevi
Bu döküm örnektir ve çalıştırılmamıştır. nice değeri süreç başlarken verir, renice
çalışan bir süreci değiştirir; -u seçeneği bir kullanıcının bütün süreçlerini kapsar.
Bir kural burada gizlidir: yetkisiz bir kullanıcı öncelik değerini yalnız artırabilir, yani
kendi sürecini yalnız geri çekebilir. Geri alma yetkisi yoktur — 10’a çekilen bir süreç,
yetkisiz kullanıcı tarafından 5’e döndürülemez. Bu, dikkatsiz bir renice çağrısının kalıcı
olabileceği anlamına gelir.
İşletim Sistemi Kavramları kursu çizelgeleyici yordamlarını birbiriyle karşılaştırmıştı; o karşılaştırma burada tekrarlanmaz. Buradaki soru yordamın hangisi olduğu değil, operatörün elindeki tek düğmenin çıktıda ne kadar göründüğüdür.
- SY22. Kurgu sunucunun 4 çekirdeği vardır; saniyelik kapasite 400 birimdir.
- SY23. Süreçlerin toplam talebi kapasiteyi aşar; sistem doymuştur.
- SY24. Öncelik değeri bir ağırlığa çevrilir: her birim ağırlığı yaklaşık dörtte bir
oranında değiştirir.
0değerinin ağırlığı 1024’tür. - SY25. Kapasite ağırlığa göre bölüşülür, ama hiçbir süreç istediğinden fazlasını almaz. Doyan süreçlerin artığı kalanlar arasında yeniden bölüşülür.
- SY26. Kâhin, pencere boyunca gerçekten yapılan toplam iştir. Kapasite sabit olduğu için bu sayının üst sınırı da sabittir.
- SY27. Çözünürlük toplam işin yüzde 1’idir. Bunun altındaki fark ölçülmemiş sayılır.
- SY28. Tanı şudur: “en çok işleyen sürecin önceliğini düşürmek sistemin yükünü azaltır.” Yanlış tanı, bu cümlenin ayakta kalmadığı deneme sayısıdır.
- SY29. İkinci tohum 20260219’dur.
# --- ortak tanim, birinci dersteki bicimiyle TOHUM, IKINCI_TOHUM, DONEM = 20260218, 20260219, 600 KULLANICI = ("kok", "uygulama", "yedek", "izleme") KOMUT = ("veri-alici", "rapor-uretici", "yedek-gorevi", "olcum-toplayici", "kuyruk-isleyici", "onbellek-temizleyici") def uretec(tohum): d = tohum def sonraki(n): nonlocal d d = (d * 1103515245 + 12345) % 2147483648 return d % n return sonraki def surecler(tohum=TOHUM, sayi=24): r = uretec(tohum) liste = [] for i in range(sayi): tur = r(10) desen = "duz" if tur < 5 else ("ani" if tur < 8 else "agir") liste.append({"pid": 1000 + i * 7 + r(5), "kullanici": KULLANICI[r(len(KULLANICI))], "komut": KOMUT[r(len(KOMUT))], "desen": desen, "oncelik": r(11) - 5, "bellek": 20 + r(400), "sinyal_yok_sayar": r(10) < 2}) return liste def kullanim(surec, saniye): d = surec["desen"] if d == "duz": return 3 + (surec["pid"] + saniye) % 4 if d == "agir": return 60 + (surec["pid"] + saniye) % 25 faz = (saniye + surec["pid"]) % 60 return 88 + faz if faz < 5 else 2 + faz % 3 # --- bu dersin katmani: oncelik degeri kapasiteyi nasil bolusturur CEKIRDEK, KAPASITE = 4, 400 def agirlik(oncelik): """Oncelik degeri BUYUDUKCE pay KUCULUR. Her birim yaklasik dortte bir.""" a = 1024 for _ in range(abs(oncelik)): a = a * 5 // 4 if oncelik < 0 else a * 4 // 5 return a def pay_dagit(surecler_, saniye, kapasite=KAPASITE): """Talep kapasiteyi asarsa pay AGIRLIGA gore bolusulur; kimse istediginden fazlasini almaz. Cizelgeleyicinin kendisi baska bir kursta olculdu.""" talep = {s["pid"]: kullanim(s, saniye) for s in surecler_} pay = {p: 0 for p in talep} bekleyen, kalan = list(surecler_), kapasite while bekleyen and kalan > 0: toplam = sum(agirlik(s["oncelik"]) for s in bekleyen) doyan = [s for s in bekleyen if kalan * agirlik(s["oncelik"]) // toplam >= talep[s["pid"]]] if not doyan: for s in bekleyen: pay[s["pid"]] = kalan * agirlik(s["oncelik"]) // toplam break for s in doyan: pay[s["pid"]] = talep[s["pid"]] kalan -= talep[s["pid"]] bekleyen.remove(s) return pay def pencere_payi(surecler_, pencere=DONEM): toplam = {s["pid"]: 0 for s in surecler_} for t in range(pencere): for p, v in pay_dagit(surecler_, t).items(): toplam[p] += v return toplam S = surecler() print("cekirdek:", CEKIRDEK, "| kapasite:", KAPASITE, "| t=0 talebi:", sum(kullanim(s, 0) for s in S)) print("oncelik ", " ".join(f"{o:4d}" for o in (-5, -3, 0, 3, 5, 10, 19))) print("agirlik ", " ".join(f"{agirlik(o):4d}" for o in (-5, -3, 0, 3, 5, 10, 19))) EN_AGIR = max(S, key=lambda s: sum(kullanim(s, t) for t in range(DONEM))) print("en cok isleyen surec:", EN_AGIR["pid"], EN_AGIR["komut"], "| oncelik degeri", EN_AGIR["oncelik"])
cekirdek: 4 | kapasite: 400 | t=0 talebi: 736 oncelik -5 -3 0 3 5 10 19 agirlik 3125 2000 1024 524 335 108 12 en cok isleyen surec: 1014 kuyruk-isleyici | oncelik degeri -5
Ağırlık tablosu ölçeğin ne kadar sert olduğunu gösteriyor: -5 ile 19 arasında ağırlık
3125’ten 12’ye, yani 260 kat düşüyor. Talep 736, kapasite 400 — sistem doymuş
durumdadır ve öncelik değerinin bir anlamı ancak bu koşulda vardır. Doymamış bir sistemde
herkes istediğini alır ve ağırlıkların hiçbir etkisi olmaz.
Önceliği Düşürmenin Görülebilir Etkisi
En çok işleyen süreç 1014’tür ve öncelik değeri şu anda -5, yani en saldırgan uçtadır.
Operatörün alışılmış hamlesi onu geri çekmektir.
# Onceki blogun uzerine: S, EN_AGIR, pencere_payi, DONEM oradan gelir. import copy def yeniden_oncelikle(surecler_, pid, yeni): k = copy.deepcopy(surecler_) for s in k: if s["pid"] == pid: s["oncelik"] = yeni return k HEDEF = EN_AGIR["pid"] TABAN = pencere_payi(S) TOPLAM_TABAN = sum(TABAN.values()) print("yeni oncelik hedefin payi degisim otekilerin payi toplam is yuk") for y in (-5, -4, -3, 0, 5, 10, 19): p = pencere_payi(yeniden_oncelikle(S, HEDEF, y)) toplam = sum(p.values()) print(f"{y:12d} {p[HEDEF]:12d} {p[HEDEF] - TABAN[HEDEF]:7d}" f" {toplam - p[HEDEF]:15d} {toplam:9d}" f" {toplam / DONEM / 100:5.2f}") print("kahin: kapasite", KAPASITE * DONEM, "birim | taban kullanimi", TOPLAM_TABAN)
yeni oncelik hedefin payi degisim otekilerin payi toplam is yuk
-5 41878 0 196028 237906 3.97
-4 37372 -4506 200460 237832 3.96
-3 31462 -10416 206434 237896 3.96
0 17668 -24210 220318 237986 3.97
5 6120 -35758 231974 238094 3.97
10 1830 -40048 236342 238172 3.97
19 0 -41878 238244 238244 3.97
kahin: kapasite 240000 birim | taban kullanimi 237906
İkinci sütun operatörü ikna eder. Tek bir adımlık değişiklik — -5‘ten -4‘e — hedefin payını
4.506 birim düşürüyor; uca kadar çekildiğinde pay **41.878’den 0’a** iniyor. Araç çıktısında
bu sütun gerçekten değişir, NI sütunu her denemede yeni değeri gösterir ve %CPU sütununda
hedef listenin dibine düşer. Yapılan işin görüldüğü tek yer burasıdır.
Son iki sütun tanıyı bozar. Toplam iş 237.906’dan 238.244’e gidiyor — 338 birimlik, yani yüzde 0,14’lük bir fark. Çözünürlük yüzde 1 olduğu için bu fark ölçülmemiş sayılır. Yük sütunu yedi satırın altısında 3,97, birinde 3,96: hiç değişmemiştir. Sistem doymuş durumdaydı ve doymuş kaldı.
Nedeni tek cümlelik bir gözlemdir: öncelik değeri işi azaltmaz, işi bölüştürür. Kapasite
kaç birimse o kadar iş yapılır; kimin yaptığı değişir, ne kadar yapıldığı değişmez. Yükten
şikâyet eden bir operatörün renice ile aradığı şey ise tam olarak “ne kadar yapıldığı”dır.
Boşalan Kapasite Kime Gidiyor
Hedefin bıraktığı 41.878 birim yok olmadı; başka süreçlere gitti. Hangilerine gittiği,
renice hamlesinin gerçekten kime yaradığını söyler.
# Onceki bloklarin uzerine: S, HEDEF, TABAN, TOPLAM_TABAN, yeniden_oncelikle. son = pencere_payi(yeniden_oncelikle(S, HEDEF, 19)) bosalan = TABAN[HEDEF] - son[HEDEF] kazanc = {d: 0 for d in ("duz", "ani", "agir")} for s in S: if s["pid"] != HEDEF: kazanc[s["desen"]] += son[s["pid"]] - TABAN[s["pid"]] print("hedeften bosalan is:", bosalan, "birim | nereye gitti:") for d in ("duz", "ani", "agir"): print(f" {d:5s} desenli surecler: {kazanc[d]:6d}" f" ({round(100 * kazanc[d] / bosalan):3d} yuzde)") print("toplam is degisimi:", sum(son.values()) - TOPLAM_TABAN, "birim |", f"{100 * (sum(son.values()) - TOPLAM_TABAN) / TOPLAM_TABAN:.2f} yuzde") print("`NI` sutunu kac denemede degisti: 6 / 6 | yuk kac denemede dustu: 0 / 6") print() for tohum in (TOHUM, IKINCI_TOHUM): S2 = surecler(tohum) h = max(S2, key=lambda s: sum(kullanim(s, t) for t in range(DONEM)))["pid"] t0, t1 = pencere_payi(S2), pencere_payi(yeniden_oncelikle(S2, h, 19)) print(f"tohum {tohum}: hedefin payi {t0[h]:6d} -> {t1[h]:5d}" f" | toplam is {sum(t0.values()):6d} -> {sum(t1.values()):6d}" f" | yuk {sum(t0.values()) / DONEM / 100:.2f} ->" f" {sum(t1.values()) / DONEM / 100:.2f}")
hedeften bosalan is: 41878 birim | nereye gitti: duz desenli surecler: 0 ( 0 yuzde) ani desenli surecler: 2774 ( 7 yuzde) agir desenli surecler: 39442 ( 94 yuzde) toplam is degisimi: 338 birim | 0.14 yuzde `NI` sutunu kac denemede degisti: 6 / 6 | yuk kac denemede dustu: 0 / 6 tohum 20260218: hedefin payi 41878 -> 0 | toplam is 237906 -> 238244 | yuk 3.97 -> 3.97 tohum 20260219: hedefin payi 43200 -> 12786 | toplam is 239078 -> 239450 | yuk 3.98 -> 3.99
Boşalan kapasitenin yüzde 94’ü öteki ağır süreçlere gidiyor. Hafif desenli süreçlere gidenin oranı yüzde 0’dır — tam olarak sıfır birim. Bunun nedeni açıktır ve önceliğin gerçek kuralını verir: hafif süreçler zaten doyuyordu. Az isteyen bir süreç, doymuş bir sistemde bile istediğini alır; ona verilecek fazla bir şey yoktur.
Sonuç, renice hamlesinin ne zaman işe yaradığını belirler. Öncelik değeri yalnız
çekişenler arasında bir şey değiştirir. Yavaş açılan bir kabuk, geciken bir bağlantı ya da
takılan bir düzenleyici genellikle az isteyen süreçlerdir ve onların sorunu öncelik değil,
başka bir kaynaktır. Ağır bir toplu işi geri çekmek ise gerçekten işe yarar — ama kazanan,
operatörün önemsediği süreç değil, öteki ağır süreçler olur.
Yanlış tanı sayısı son satırlarda duruyor: NI sütunu 6 denemenin 6’sında değişti, yük
6 denemenin 0’ında düştü. “Önceliği düşürdüm, yük azaldı” cümlesi altı denemenin
altısında yanlıştır. İkinci tohumda hedefin payı 43.200’den 12.786’ya iniyor, toplam iş
239.078’den 239.450’ye çıkıyor ve yük 3,98’den 3,99’a gidiyor: pay büyük ölçüde değişiyor,
yük yine değişmiyor. Payın ne kadar düşeceği kurguya bağlıdır; yükün değişmemesi değildir.
İşlemci önceliğinin hiç işe yaramadığı bir durum daha vardır ve ölçüm dışında kalır: darboğaz
işlemci değilse renice hiçbir şeye dokunmaz. Diske ya da ağa bağlı bekleyen bir süreç zaten
çekirdek istemiyordur. Girdi/çıktı önceliği için ayrı bir araç, ionice vardır; katı zamanlama
sınıfları ise chrt ile ayarlanır ve yanlış kullanıldığında bir sürecin sistemi tamamen
kilitlemesine yol açabilir. Darboğazın hangisi olduğunun ayrımı bu kursun günlükler konusunda
ölçülür.
Kalıtım ve Doğru Kullanım
Öncelik değerinin ölçülmeyen ama belirleyici bir özelliği vardır: çocuk süreçler onu
devralır. Çatallanan her süreç ana sürecin değeriyle doğar. Bunun pratik sonucu, bir ağacın
tamamını geri çekmenin tek çağrıyla yapılabilmesidir — sarmalayıcı betik nice ile
başlatıldığında altındaki bütün adımlar aynı değerle koşar. Aynı özellik ters yönde de
işler: bir zamanlayıcının ya da servis yöneticisinin verdiği değer, oradan başlayan her şeye
yapışır ve etkileşimli oturumda ölçülen davranış orada yeniden üretilmez.
Ölçümden çıkan üç kullanım kuralı vardır.
Değeri başlangıçta ver. renice çalışan bir sürecin o ana kadarki payını geri getirmez;
yalnız bundan sonrasını değiştirir. Uzun bir toplu iş, çekişmeye girdikten sonra değil,
başlarken geri çekilmelidir. Bir işin geri çekilmiş başlatılması nice ile tek satırdır ve
kalıtım sayesinde alt adımları da kapsar.
Yararlanacak tarafın çekişiyor olduğunu doğrula. Ölçümün en keskin sayısı buydu: hafif süreçlere giden pay sıfır. Bir sürecin yavaşlığı öncelikten geliyorsa o süreç çekirdek için sıraya girmiş olmalıdır. Sıraya girmemiş bir sürece öncelik vermek hiçbir sayıyı değiştirmez.
Yükü öncelikle çözmeye çalışma. Yük, yapılan işin toplamıdır; öncelik o toplamı bölüştürür. Yükü gerçekten azaltan şeyler başkadır: işi azaltmak, işi zamana yaymak, kapasite eklemek ya da işi durdurmak. İlk üçü bu kursun kapsamı dışındadır; dördüncüsü önceki dersin konusuydu ve bedeli oradaki tabloda ölçüldü.
Bir uyarı da ters uçtan gelir. Öncelik değerini negatife çekmek yalnız yetkili kullanıcının yapabileceği bir işlemdir ve etkisi bu tablonun aynadaki görüntüsüdür: kayırılan süreç pay kazanır, kaybeden öteki her şeydir. Sistem yönetim araçlarının kendisi geri çekilmiş değerlerle koşuyorsa, arıza anında operatörün kabuğu da yavaşlar.
Özet
NIsütunu operatörün girdisi olan öncelik değerini,PRIsütunu çizelgeleyicinin ondan hesapladığı değeri taşır; ölçek terstir ve yetkisiz kullanıcı değeri yalnız artırabilir.- Öncelik değeri bir ağırlığa çevrilir:
-5ağırlığı 3125,19ağırlığı 12’dir. Ağırlıkların anlamı yalnız doymuş bir sistemde vardır. - En çok işleyen sürecin değeri uca çekildiğinde payı 41.878’den 0’a iner; bu, araç çıktısında görülen tek değişikliktir.
- Toplam iş 237.906’dan 238.244’e gider (yüzde 0,14, çözünürlüğün altında) ve yük yedi denemede de 3,97 kalır. Öncelik işi azaltmaz, bölüştürür.
- Boşalan 41.878 birimin yüzde 94’ü öteki ağır süreçlere, hafif süreçlere yüzde 0’ı gider; hafif süreçler zaten doyuyordu.
- “Önceliği düşürdüm, yük azaldı” tanısı altı denemenin altısında yanlıştır:
NIsütunu 6/6 değişir, yük 0/6 düşer.
Sonraki Adım
Öncelik bir sürecin ne kadar hızlı koşacağını etkiler, ne kadar tüketebileceğini sınırlamaz. Sınırlamanın kendi mekanizması vardır: süreç başına konan kaynak kısıtları. Sonraki ders bu kısıtları ölçer ve şu soruyu sorar: bir sınır aşıldığında ortaya çıkan hata iletisi, sınırın hangisi olduğunu söylüyor mu — yoksa iki ayrı neden aynı cümleyle mi görünüyor.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.