isolcpus ne yapar, ne yapmaz
Çok çekirdekli bir SoC'ta gerçek zamanlı döngüyü ayrı bir çekirdeğe taşımanın refleks cevabı isolcpus. Boot argümanına bir CPU listesi yazılır, çekirdek "izole" ilan edilir ve konu kapanmış sayılır. Oysa bu parametre tek bir iş yapar: verilen çekirdekleri zamanlayıcının yük dengeleme alanlarının (sched domain) dışına çıkarır. Sonucu tek cümleyle özetlemek mümkün: o çekirdeğe kendiliğinden görev gelmez. Geri kalan her şey — tick, RCU, per-CPU kworker'lar, başka çekirdeklerden gelen IPI'lar, per-CPU kesmeler, paylaşılan cache, bellek denetleyicisi ve saat alanı — olduğu yerde durur.
Linux'un kendi belgeleri de bu parametreyi artık ilk tercih olarak sunmuyor: Documentation/admin-guide/kernel-parameters.txt içindeki isolcpus girdisi "Deprecated - use cpusets instead" notunu taşır. Parametre çalışmaya devam eder; ama bir izolasyon stratejisinin tamamı değil, ilk satırıdır.
Bu yazı temel yapılandırma zincirini tekrar etmiyor — bayraklar, IRQ affinity, SCHED_FIFO hiyerarşisi ve cyclictest için PREEMPT_RT çekirdek yapılandırması rehberimiz var. Buradaki soru daha dar ve daha pahalı: o zinciri doğru kurduktan sonra izolasyon nerede sızıyor? Sızıntıları dört katmanda ele alacağız; ilk üçü bir bayrakla veya bir mimari kararla kapanır, dördüncüsü kapanmaz, yalnızca yönetilir.
Katman 1: zamanlayıcı, tick ve RCU
Tick durur, ama koşullu
nohz_full= verdiğiniz çekirdek tick'i ancak üzerinde tek bir runnable görev varken durdurur. İkinci bir runnable thread — sizin yardımcı thread'iniz, uyanmış bir ksoftirqd, bir sürücü kthread'i — o çekirdeği sessizce periyodik tick'e geri döndürür. Hiçbir uyarı çıkmaz; yalnızca /proc/interrupts içindeki yerel zamanlayıcı sayacı artmaya başlar.
İkinci nokta daha temel: adaptive-tick modda tick sıfırlanmaz. Documentation/timers/no_hz.rst, bu çekirdeklerde zamanlama tick'inin saniyede en fazla bire indirildiğini söyler; zamanlayıcı muhasebesi için kalan bu tick tasarımın parçasıdır, hatası değil. Bütçesi bunu kaldıramayan bir döngü Linux tarafında yanlış yerdedir — bu durumda tartışma izolasyon değil, ayrı bir gerçek zamanlı alan tartışmasıdır.
Üçüncüsü: boot CPU her zaman housekeeping tarafında kalır, nohz_full listesine yazılsa bile dışarıda tutulur. Zaman tutma işini bir çekirdeğin yapması gerekir.
RCU'yu offload etmek yetmez
rcu_nocbs=, geri çağrıları izole çekirdekten alıp rcuo kthread'lerine devreder. Ama RCU'nun izole çekirdeğe dokunduğu ikinci bir yol vardır: expedited grace period. Bu yol, grace period'u kısaltmak uğruna çekirdeklere IPI gönderir ve izole olup olmadıklarına bakmaz. rcupdate.rcu_normal_after_boot=1, boot sonrasında bu yolu kapatıp normal grace period'a döner. Bunun yanında rcutree.use_softirq=0, RCU çekirdek işini softirq bağlamından çıkarıp önceliklendirilebilir rcuc kthread'lerine taşır; RT çekirdeğinde bu ayrım, "açıklayamadığım bir softirq gecikmesi var" ile "önceliğini benim belirlediğim bir thread var" arasındaki farktır.
kworker: taşınabilen iş, taşınamayan iş
Workqueue'ların iki türü vardır ve izolasyon açısından tamamen farklı davranırlar.
- Unbound workqueue'lar bir maskeye uyar.
nohz_fullverildiğinde bu maske housekeeping tarafına daraltılır; ama varsaymak yerine okumak gerekir:/sys/devices/virtual/workqueue/cpumask. - Per-CPU workqueue'lar taşınamaz. Bir sürücü izole çekirdek üzerinde
schedule_work()çağırdıysa, o iş oradakikworker/Niçinde koşar. Çözüm bir maske değildir; o sürücüyü o çekirdekten uzak tutmaktır.
Aynı ayrım kthread'ler için de geçerli: migration/N, cpuhp/N ve ksoftirqd/N per-CPU'dur, taşınamaz ve kaldırılamaz. Yapabileceğiniz tek şey, onları uyandıracak işi ortadan kaldırmaktır.
stop_machine: izolasyonu tanımayan tek mekanizma
stop_machine() bütün çekirdekleri durdurup tek bir işi çalıştırır. İzole olmanıza da, SCHED_FIFO önceliğinize de bakmaz. Tetikleyicileri sıradan sistem olaylarıdır: CPU hotplug, bazı mimarilerde jump label ve ftrace kod yaması yolları, bazı sürücü ve cpufreq geçişleri. Pratik sonucu şudur: çalışan bir üretim sisteminde tracing açmak, modül yüklemek veya bir çekirdeği çevrimdışı almak, gerçek zamanlı döngüye görünmez bir duraklama enjekte edebilir. Bunlar bakım penceresine ait işlerdir.
Sessiz ama sürekli gürültü
vmstat güncellemesi per-CPU ertelenmiş bir iştir; /proc/sys/vm/stat_interval değerini büyütmek frekansını düşürür. /proc/sys/kernel/timer_migration, zamanlayıcıların çekirdekler arasında taşınmasını yönetir. /proc/timer_list ise izole çekirdekte kuyrukta bekleyen zamanlayıcıları isim isim gösterir; izolasyon denetiminde ilk açılacak dosyalardan biridir.
Katman 2: kesmeler
irqaffinity= yalnızca varsayılan maskeyi belirler. Boot sırasında kurulan bazı kesmeler ve sonradan yüklenen sürücüler bu varsayılanın dışında kalabilir; dolayısıyla parametreyi vermek denetimi bitirmez, başlatır. İki sert sınırla karşılaşırsınız:
- Per-CPU kesmeler taşınamaz. Mimari zamanlayıcı, PMU ve IPI'lar
IRQF_PERCPUişaretlidir;/proc/irq/N/smp_affinityüzerinden taşımayı denemek hata döndürür. Bunlar tasarım gereği her çekirdektedir. - Managed IRQ'ları sürücü yönetir. Çok kuyruklu ağ ve depolama sürücüleri kuyruk-CPU eşlemesini kendileri kurar; elle yazdığınız affinity kalıcı olmaz.
isolcpus=managed_irq,...bayrağı tam bunun için vardır: çekirdeğe, managed kesmeleri izole CPU'lara yöneltmemesini söyler.
Bir de tamamen yazılım tarafında duran bir kaçak var: RPS ve XPS. /sys/class/net/<iface>/queues/rx-0/rps_cpus bir bit maskesidir ve ağ softirq işini istediği çekirdeğe dağıtır. irqbalance kapatılmış olsa bile burası açık kalırsa, izolasyon ilk yoğun trafikte delinir.
Katman 3: cpuset ile dinamik ve doğrulanabilir sınır
cgroup v2, isolcpusun yapamadığını yapar: sınırı çalışma zamanında kurar, durumunu geri bildirir ve görevleri açıkça yerleştirir. cpuset.cpus.partition dosyasının isolated değeri, bölmedeki çekirdekleri yük dengelemenin dışına çıkarır; isolcpus=domain bayrağının cgroup karşılığıdır. Geri bildirim kısmı önemlidir: yanlış kurulmuş bir bölme sessizce çalışmaz, dosyayı geri okuduğunuzda geçersiz olduğunu söyler.
# cgroup v2: cpuset denetleyicisini alt agaca ac
echo "+cpuset" > /sys/fs/cgroup/cgroup.subtree_control
mkdir -p /sys/fs/cgroup/rt
echo "2-3" > /sys/fs/cgroup/rt/cpuset.cpus
echo "2-3" > /sys/fs/cgroup/rt/cpuset.cpus.exclusive
echo "isolated" > /sys/fs/cgroup/rt/cpuset.cpus.partition
# Durumu geri okumadan "kuruldu" saymayin:
# "isolated" beklenir. "isolated invalid (...)" izolasyonun KURULMADIGINI soyler.
cat /sys/fs/cgroup/rt/cpuset.cpus.partition
# RT surecini bolmeye yerlestir
echo $RT_PID > /sys/fs/cgroup/rt/cgroup.procs
# Geri kalan her seyin varsayilan yerini housekeeping yap:
# /etc/systemd/system.conf -> CPUAffinity=0-1
# (PID 1'in varsayilan affinity'si tum servislere miras kalir)
Son satır, sahada en çok işe yarayan tek satırdır. isolcpus yeni görevlerin izole çekirdeğe dengeleme yoluyla gelmesini engeller, ama açık bir affinity ile oraya yerleşen bir servisi engellemez. systemd tarafındaki varsayılanı housekeeping'e sabitlemek, bu kapıyı kapatır.
Katman 4: bölüşülemeyen donanım
Buraya kadarki her sızıntı bir bayrakla, bir maskeyle veya bir yerleştirme kararıyla kapanıyordu. Bundan sonrası kapanmaz.
Paylaşılan son seviye cache
Tipik bir gömülü SoC'ta bir kümedeki uygulama çekirdeklerinin tamamı aynı L2/LLC'yi paylaşır. Housekeeping tarafında koşan bir video kopyalaması veya bir model çıkarımı sizin çalışma kümenizi cache'ten atar; döngünüz aynı kodu çalıştırdığı hâlde bazı iterasyonlarda bellekten okur. Hiçbir zamanlayıcı bayrağı bunu görmez.
Donanımda bölümleme mümkündür ama gömülü sınıfta yaygın değildir: x86 tarafında Intel RDT/CAT çekirdeğin resctrl arayüzüyle kullanılır; Arm tarafındaki karşılığı MPAM'dir (Arm mimari eki, ARM DDI 0598) ve hem silikon hem çekirdek desteği parçalıdır. Var olduğunu varsaymadan önce TRM'den ve kullandığınız çekirdek sürümünden doğrulayın.
Erişilebilir çare mimaridir: RT döngüsünün sıcak yolunu küçük tutmak, veri yapılarını yerelleştirmek, döngü içinde büyük tamponlar dolaşmamak. Cache'i bölemiyorsanız, cache'e olan bağımlılığınızı küçültürsünüz.
Bellek yolu ve DMA
Kamera, ağ, depolama ve NPU DMA'ları bellek denetleyicisini sizinle paylaşır ve zamanlayıcıya danışmaz. Birçok SoC interconnect tarafında QoS ayarları sunar — öncelik sınıfı, bant genişliği sınırlayıcı — ve bunlar TRM'de belgelidir, ama pratikte neredeyse her zaman varsayılan değerlerle bırakılır. En kötü durum bütçenizi kurarken sorulacak soru nettir: bu döngü, karttaki bütün DMA motorları aynı anda çalışırken de zamanında bitiyor mu?
Saat alanı: izolasyon çekirdek başına, DVFS küme başına
En sık gözden kaçan sızıntı budur. Çoğu ARM SoC'ta bir kümedeki tüm çekirdekler tek bir saat ve gerilim alanını paylaşır. Yani housekeeping tarafındaki bir governor kararı sizin çekirdeğinizin frekansını da değiştirir; "kendi çekirdeğim var" cümlesi frekans için geçerli değildir. Doğrulama tek dosyadır: /sys/devices/system/cpu/cpufreq/policyN/related_cpus içinde kaç çekirdek listeleniyorsa, bir frekans kararı o kadar çekirdeği birlikte etkiler. affected_cpus ile karşılaştırın; ikisi arasındaki fark size donanımın gerçek granülaritesini söyler.
Aynı şey idle için de geçerlidir. Derin bir idle durumundan çıkış gecikmesi ve küme seviyesinde güç kapamada L2'nin boşaltılması, döngünüzün ilk erişimlerini yavaşlatır. Çekirdek başına sınır /sys/devices/system/cpu/cpuN/power/pm_qos_resume_latency_us ile, sistem geneli sınır /dev/cpu_dma_latency ile konur. İkincisinde kritik ayrıntı şudur: kısıt dosya açık kaldığı sürece geçerlidir; yazıp kapatan bir kabuk komutu hiçbir şey yapmaz.
/* Sistem genelinde derin idle durumlarini kapali tut.
Kisit yalnizca fd acik kaldigi surece gecerlidir. */
int fd = open("/dev/cpu_dma_latency", O_WRONLY);
int32_t hedef_us = 0;
write(fd, &hedef_us, sizeof(hedef_us));
/* fd BILEREK kapatilmaz: surec yasadigi surece kisit ayakta kalir. */
Termal
Termal governor frekansı politika seviyesinde kısar. Yani izole çekirdeğiniz, yanındaki çekirdeğin ürettiği ısı yüzünden yavaşlar. Bu nedenle gerçek zamanlı doğrulama açık tezgâhta değil, kapağı kapalı muhafazada ve hedef ortam sıcaklığında tekrarlanmalıdır.
Sızıntıyı nasıl bulursunuz
Denetim sırası şudur: önce izole çekirdekte ne olduğunu sayın, sonra neden olduğunu izleyin.
# 1. Izolasyon gercekten kuruldu mu?
cat /sys/devices/system/cpu/isolated
cat /proc/cmdline
# 2. O cekirdekte hangi thread'ler var? (ideal: yalnizca sizinkiler)
ps -eLo pid,tid,class,rtprio,psr,comm --sort=psr | awk '$5 == 2'
# 3. Kesme ve softirq sayaclari: mutlak deger degil, iki olcum arasindaki FARK
cp /proc/interrupts /tmp/irq.before
cat /proc/softirqs > /tmp/softirq.before
# 4. Izole cekirdekte bekleyen zamanlayicilar
grep -A 20 "cpu: 2" /proc/timer_list
# 5. Cekirdek neden uyaniyor? sched_switch izini yalnizca CPU2 icin topla
cd /sys/kernel/tracing
echo 4 > tracing_cpumask # CPU2 icin bit maskesi
echo 1 > events/sched/sched_switch/enable
# 6. Isletim sistemi gurultusunu dogrudan olcen araclar (cekirdek 6.x)
rtla osnoise top -c 2 -d 10m
rtla timerlat hist -c 2 -d 10m
Beklenti nettir: izole çekirdekte sizin thread'iniz dışında bağlam değişimi görünmemeli, kesme sayaçlarındaki artış per-CPU kesmelerle sınırlı kalmalıdır. Görünen her ek satırın bir adı ve bir açıklaması olmalıdır. Ölçümü yalnızca boştayken yapmak bu tabloyu anlamsızlaştırır; gürültü tam olarak sistem yüklüyken doğar. Ölçüm disiplininin nasıl kurulduğunu EtherCAT ölçüm metodolojisi yazımızda ayrıntılandırıyoruz.
Nerede yanlış gider
1. İzole edip yerleştirmemek. isolcpus verilir, RT süreci hâlâ housekeeping çekirdeğinde koşar; kimse taskset -pc <pid> ile bakmamıştır. İzole çekirdek bomboş, döngü kalabalığın içindedir.
2. nohz_full verip çekirdeğe ikinci bir runnable thread bırakmak. Tick hiç durmaz, yapılandırma "yapılmış" sayılır. Kontrol yöntemi: yerel zamanlayıcı kesme sayacının artış hızı.
3. cpuset.cpus.partition dosyasını geri okumamak. Bölme isolated invalid durumundadır, hiçbir hata mesajı çıkmaz, izolasyon yoktur.
4. Kesme affinity'sini bir kez ayarlayıp bitmiş saymak. Sürücü yeniden yüklenir, ağ arayüzü yeniden açılır, managed IRQ'lar kendi eşlemesini yeniden kurar. Affinity bir kurulum adımı değil, boot sonrası doğrulanan bir durumdur.
5. RPS/XPS'i unutmak. IRQ housekeeping'de, ağ softirq işi RPS maskesi üzerinden izole çekirdekte. Klasik ve bulunması zor.
6. RT sürecinin init'ten sonra bellek haritasını değiştirmesi. mmap, munmap ve büyümeye devam eden bir yığın, diğer çekirdeklerden TLB shootdown IPI'ları çeker. mlockall(MCL_CURRENT | MCL_FUTURE) ve başlangıçta yapılan prefault, bu trafiği kaynağında keser.
7. Üretimde tracing veya modül yükleme. stop_machine yolunu tetikleyen her işlem, en yüksek öncelikli görevi de durdurur. Bakım penceresi dışında yapılmaz.
8. Frekansı ve ısıyı denklemin dışında bırakmak. related_cpus bakılmamıştır, governor performancea sabitlenmemiştir, doğrulama açık tezgâhta yapılmıştır. Sahada aynı yazılım daha yavaş bir çekirdekte koşar.
9. Boştaki sistemde ölçüp sonucu üretim davranışı sanmak. İzolasyonun bütün amacı yük altındaki kuyruğu düzeltmektir; boştaki histogram bunun hakkında hiçbir şey söylemez.
Karar kriteri
Karar sırası şu üç soruyla kurulur.
Kaçırılan bir teslim tarihinin fiziksel sonucu var mı? Varsa — eksen kayması, güvenlik zinciri, aktüatör — soru artık "izolasyonu nasıl sıkılaştırırım" değildir. Kritik yol, üzerinde genel amaçlı bir işletim sistemi koşmayan bir alana taşınır; heterojen bir SoC'ta bu alan bir R5F ya da MCU alt sistemidir. İzolasyon o alanın yerine geçmez, bölüşüm kararının yerine hiç geçmez.
Bütçe yumuşak ama dar mı? O zaman izolasyon doğru araçtır, ancak şu sırayla: nohz_full + rcu_nocbs + rcupdate.rcu_normal_after_boot=1 ile tick ve RCU; cgroup v2 isolated bölmesi ve systemd CPUAffinity= ile yerleştirme; IRQ, RPS/XPS ve workqueue maskeleriyle kesme yolu; governor ve PM QoS ile saat alanı. Her adımdan sonra ölçün — sıradaki adımı, bir öncekinin ne kadar kazandırdığını görmeden atmayın.
Kalan sızıntıyı taşıyabiliyor musunuz? LLC, bellek yolu, DVFS ve termal bir noktadan sonra kapanmaz. Bunlar kapatılamıyorsa iki seçenek kalır: RT görevinin bu kaynaklara bağımlılığını küçültmek ya da rakip iş yükünü karttan çıkarmak. Üçüncü bir seçenek — "daha çok bayrak" — yoktur.
Kısacası: isolcpus bir başlangıç bayrağıdır, bir garanti değil. İzolasyon, çekirdek parametreleriyle kurulan ve ölçümle doğrulanan bir sistem özelliğidir; doğrulanmadığı sürece yalnızca bir niyettir. Kendi platformunuzda bu zinciri kurmayı ve gecikme bütçesini birlikte çıkarmayı değerlendiriyorsanız, hard real-time yetkinliğimiz ve gömülü sistem mimari denetimi tam olarak bu sorularla başlar.
Kaynaklar
- Linux çekirdek dokümantasyonu — The kernel's command-line parameters (
isolcpus,nohz_full,rcu_nocbs,rcupdate.rcu_normal_after_boot) — https://docs.kernel.org/admin-guide/kernel-parameters.html - Linux çekirdek dokümantasyonu — NO_HZ: Reducing Scheduling-Clock Ticks — https://docs.kernel.org/timers/no_hz.html
- Linux çekirdek dokümantasyonu — Control Group v2, cpuset bölümü (
cpuset.cpus.partition) — https://docs.kernel.org/admin-guide/cgroup-v2.html - Linux çekirdek dokümantasyonu — Concurrency Managed Workqueue (cmwq) — https://docs.kernel.org/core-api/workqueue.html
- Linux çekirdek dokümantasyonu — RTLA: Real-Time Linux Analysis tools — https://docs.kernel.org/tools/rtla/index.html
- Linux çekirdek dokümantasyonu — User Interface for Resource Control feature (resctrl) — https://docs.kernel.org/arch/x86/resctrl.html
- Arm — Arm Architecture Reference Manual Supplement, Memory System Resource Partitioning and Monitoring (MPAM), ARM DDI 0598 — https://developer.arm.com/documentation/ddi0598/latest
Kaynaklara erişim tarihi: 5 Eylül 2026. Çekirdek arayüzleri sürüm alır: cpuset.cpus.partition değerleri, workqueue maske dosyaları ve rtla alt komutları kullandığınız çekirdek sürümünün belgesinden doğrulanmalıdır.
