Embedded Realtime Linux
Last updated
Last updated
Linux 2000’ li yılların başlarında hantal OS olarak bilindiğinden embedded dünyada çokça tercih edilmiyordu. Heleki embedded dünyaca pek yoğun kabul de görmemişti. Bunda etken temel sebepler task switching, blocking, memory barrier işlemlerinde mimarisi gereği yaşattığı sorunlardır. Örneğin, zamanında preemptive olmaması embedded dünyada tercih edilmemesindeki en büyük nedenlerdendir.
Daha sonraları bu problemler “RT Patch” tabiri kapsamında Linux kernel geliştirme grubu kernel.org dışındaki oluşumlarca yapılmaya başlanmıştır. Zamanla bu yaklaşım kabul görmüş ve kernel.org tarafından da artık destekleneceği duyurulmuştur.
Linux kernel’ in de diğer OS gibi temel amacı user space ile kernel space ayırarak kullanıcı uygulamaların sistemi bozmasını engellenmektedir. Linux kernel de bir çok kernel thread den oluşur. Driverlar da kernel de thread olabilmektedır.
Genelde son kullanıcılar donanım bileşeni seçerken hazır linux driverları da var mı diye araştırır. Hazır var olan ürünlerin donanımlarında bileşen olarak kullanılmasını tercih ederler. Büyük firmalarda ürün tedarikinde chip alırken gerekli linux driverlarını da üretici firmalardan temin etmek isterler. Bu ihtiyacı karşılamak için büyük donanım üreticisi firmalar hazırladıkları donanımlar için dünyanın değişik yerlerinde yazılım geliştirme departmanı da kurarlar.
Kernel’ in kendisinin realtime patch’ lerinin yayınlanması ve uygulanmasıyla işler tam olarak bitmemektedir. Kısacası kernelin realtime patchlenmesi yetmeyebilir. Realtime linux elde edebilmek için hazırlanan linux device driver’ larınında realtime gereksinimlerine örneğin preemptive olmaya uygun olması gerekmektedir.
Sonuç olarak, bir linux dağıtımı üzerinde realtime olabilmek için yapılması gereken ön işlemler vardır. Bunların dışında tasarlanacak sistemin hizmet edeceği uygulamaya karşı olan verimliliğinin de arttırılması için özelleştirmeler gerekecektir. Örneğin, networkden gelen paketlere hızlıca cevap vermesi istenen bir uygulama geliştirmek isteyelim. Uygulamamız çalışırken diğer uygulamalar ya da kernel threadleri tarafından kendi sistem çağrıları dışında kesilmesini istemeyiz. Ya da uygulamamızın bizim için önceliği olmayan interruptlar ile kesilmesini istemeyebiliriz.
Uygulamanın verimliliğinin arttırılması için multicore mimariler (SMP mode) kullanarak daha esnek tasarımlar yapılabilmektedir. Linux task scheduler’ ı farklı algoritmalara göre çalışabilir. Günümüzde Linux’ da en çok tercih edilen ve varsayılan task scheduler algoritması Completely Fair Scheduler (CFS) algoritmasıdır. O(n) ve O(1) scheduler adında eski kernel sürümlerde varsayılan olarak kullanılan algoritmalar da vardır. CFS algoritmasının temel amacı hazırda bekleyen proseslere tamamen eşit cpu zamanı vermektir. Örneğin 20 proses, 100 ms latency değeri ile schedule edilmeyi bekliyorsa her proses 5ms çalıştıktan sonra kesilip diğer prosese geçmesi gerekir. Eğer 20 proses yerine 10 proses kalırsa her prosese 10 ms süre verilmesi gerekir. Görüldüğü gibi bu scheduler her taskın çalışabilmesine fırsat vermektedir. Böylece sistem deadlock olmayacağı ve çalışamayan process olmayacağı öngörülmektedir.
Kernelin task scheduling algoritmaları taskların scheduling priority ve policy seçimine göre ilgili algoritmalara yönlendirilmektedir. Önceliklendirme ile çalışma sıralamaları ayarlanabildiği gibi aynı öncelikliler arasında geçişlerin nasıl olacağı policy lerle belirlenmektedir. Örneğin; İlk giren ilk çalışır mantığının (SCHED_FIFO) yanı sıra eşit zaman bölmeli çalışma da seçilebilir (SCHED_RR). Task policy göre uygulanacak scheduler algoritması da değişmektedir. SCHED_FIFO, SCHED_RR policy seçilirse realtime task olacaktır. SCHED_NORMAL (SCHED_OTHER), SCHED_BATCH, SCHED_IDLE seçilirse CFS algoritmasıyla yönetilecek task olacaktır.
Linux scheduler’ ın davranışını etkileyen bir diğer konu da preemption konusudur. Linux işletim sistemi preemption gibi scheduling kararlarını alan metodlarını değişik olaylarda ya da zaman aralıklarında çağırabilmektedir. Bu uygulamalarımızın responsive olmasıyla tek görevde yüksek performans (bulk processing) olması arasında yapılacak seçimlere göre değişiklik gösterecektir. Sadece kernel den dönüş zamanlarında daha öncelikli işlemler var mı diye bakabilirken (No Forced Preemption) kernelde karmaşık yapılan işlemler sırasında arada bir schedule edilmesi gereken daha öncelikli bir iş var mı diye de bakabilir (Voluntary Kernel Preemption). Ya da periyodik olarak scheduling edilecek thread var mı diye de bakılabilir (Preemptible Kernel – Low-Latency Desktop). Hatta periyodik olarak kontroller yapılırken bir yandan da donanımsal interrupt ların threadler oluşturmasını zorlayarak onların da önceliklendirmeye dayalı olaylar olmasını sağlayabilir (Preemptible Kernel – Basic RT). Hepsinden daha üst seviye iyileştirme sağlayan ve böylece tam responsive OS olmasını sağlayan moduyla da çalışılabilir (Fully Preemptible Kernel).
Linux’ un task scheduler yanı sıra diğer bir scheduler’ı da giriş/çıkış işlemlerinin yönetilmesinden sorumlu olan I/O scheduler dan bahsetmeden olmaz. Örneğin disk erişimlerinde yazma/okuma işlemlerinin hangi method ile olacağını belirlemek için kullanılmaktadır. Gelen I/O erişim isteklerinin zaman bölmeli yürütme, erişimleri verimleştirme için sıralama, deadline oluşumlarını engelleme gibi seçenekler sunabilen algoritmalar kullanılacak teknolojiye göre seçilebilmektedir. Multiqueue deadline, Kyber, Budget Fair Queuing (BFQ), NOOP, Completely Fair Queueing (CFQ) gibi seçenekler bulunmaktadır. I/O özellinde değişiklikler yapılabilmektedir.
Bir başka konu da kernel in periyodik olarak timerlarla ürettiği periyodik timer interruptlarının engellenip sadece istendiğinde tetiklenmesini sağlamaktır. Bu şekilde çalışmaya tickless kernel (dynamic tick) denmektedir. İşletim sistemleri normalde belirli periyotlarla load balance yapabilmek, scheduling kararları alabilmek, sistem zamanını düzenleyebilmek, istatistikleri güncelleyebilmek ve interrupt handler larını koşturabilmek için timer modüllerini kullanarak system tick olayını icra eder (no dynticks HZ_PERIODIC). Ancak, bu işlemin periyodik değilde olay tetiklemeli yani taskların "5 ms sonra beni uyandır" şeklinde event girdisiyle timer modulü kurulup süreç tetiklenebilmektedir (Full dynticks system NO_HZ_FULL). Daha öncelikli işlere de zaman ayırabilmek için meşgul CPU larda bu işlem periyodik yapılması mantıklı bir işlem iken idle CPU larda bu işlemin yapılması gereksiz olduğundan tickless idle seçeneği varsayılan olarak kullanılmaktadır (Idle dynticks system NO_HZ_IDLE).
Bir diğer konu da işletim sisteminin system tick timer periyodunu ayarlamaktır. Bu değerin seçimine göre sistemin responsive olması önemli ölçüde etkilenecektir. 100 HZ, 250 HZ, 300 HZ ve 1000 HZ seçenekleri sunulmaktadır.
Tabii ki buraya kadar bir çok seçenekten bahsettik. Ancak, seçenekler bunlarla sınırlı değildir. Bir diğer konu da uygulamamızın çalışabileceği işlemci çekirdeklerinin hangilerinin olabileceğini belirleyerek uygulamamızı belirli bir çekirdekte çalışmaya zorlayabilir ve task scheduler’ ın diğer uygulamaları o çekirdeğe yönlendirmesi engellenebilir. Bu metod isolcpus olarak bilinmektedir. Linux çekirdeği yüklenirken uboot veya grub ön yükleyicisi tarafından kernel komut satırı parametresi ile hangi CPU lara doğru otomatik scheduling kararı verilmeyeceğinin belirlenmesi sağlanabilir.
Bir diğer linux kernel davranışını etkileyen konu Read-Copy-Update (RCU) senkronizasyon mekanizmasıdır. Normalde CPU birimleri içerisinde Level-1, Level-2 ve Level-3 gibi seviyelere ayrılmış bellek yapılanması bulunmaktadır. Böyle bir yapılanmanın temel sebebi harici bellek birimlerine erişim performans kaybına sebep olan bir erişim yöntemidir. Bu nedenle işlemci içerisinde hatta çekirdek içerisindeki bellek birimlerine dış bellekteki datanın bulk kopyası alınarak bilgiye ihtiyaç duyan çekirdeklere sunulur. Tabii bu datanın bellek birimlerince değiştirilmesi durumunda diğer çekirdeklerin güncel veriye erişebilmesi için donanım temelli yapılar bulunmaktadır. Linux okuma işlemlerinde güncellenmiş data üzerinde de olan verimliliği arttırmak için RCU yapısı kullanır. Böylece önceden varolan okumalardan sonra güncellemeleri daha sonraya erteleyerek aynı anda verileri işaretleyerek ve yeni okuyucuların güncellenmiş verileri okuyacağından emin olarak birden çok iş parçacığının paylaşılan bellekten verimli bir şekilde okunmasına olanak tanır. Bu, tüm okuyucuların senkronizasyon yokmuş gibi ilerlemesini sağlar, bu nedenle hızlı olurlar, ancak güncellemeleri daha da zorlaştırırlar. RCU işlemlerini her core kendisi yapmaktadır. Ancak, bu işlemlerin istediğimiz çekirdekte yapılmasını engelleyebiliriz. Ancak, işlem başka bir çekirdek tarafından o çekirdek için yapılmaya devam edecektir. Kernel komut parametlerine rcu_nocbs değişkeni ile istenilen çekirdekler seçilip eklenebilir.
Diğer bir scheduler performansını etkileyen parametre ise real time taskların normal tasklara göre çalışma oranını etkileyen bir parametredir. Örneğin 1 sn zaman döngülerinde en fazla 950 ms realtime tasklar ın kullanabilmesi şeklinde sınırlama getirerek kalan 50 ms zamanın normal tasklara ayrılmasına sistem zorlanabilir.
Sonuç olarak bir işlemcinin herhangi bir çekideğini tamamen bir işe adamak için yapılması gereken bir çok işlem bulunmaktadır. Burada ki esas kriter amacımızın ne kadar responsive ya da ne kadar performans (throughput) elde etmek istediğimiz arasındaki seçimlere bağlıdır.
Bu kadar çok ayrıntıyla uğraşmak yerine daha güçlü işlemcilerle çalışmak daha kolay bir seçenek olabilir. Tabii daha güçlü işlemcilerde de bu metodları uygulayarak daha yüksek performanslara erişmek de bir seçenek olabilir.
Linux çekirdeğinin iyileştirme süreçleri ve güvenirliğinin arttırılma süreçleri devam etmektedir. Gene de daha fazla realtime elde etmeyi isteyenler ancak linux un sağladığı kolaylıkları da bırakmak istemeyenler için sanallaştırma çözümleriyle çekirdeklerin bir kısmında linux koşarken diğer bir kısmında RTOS veya bearmetal uygulama koşturulabilmektedir. Bunun için linux un KVM gibi kendi içinde çözümleri olduğu gibi büyük firmalar tarafından gelişimi desteklenen/sürdürülen Jailhouse veya Xenomai gibi Hatta linux kernel üzerinden donanıma erişmeyip direkt olarak donanıma erişmeyi sağlayan DPDK gibi işlemcilerin VT-x ve chipsetlerin VT-d teknolojilerine dayalı çalışan frameworkler kullanılarak donanıma direkt erişebilen driverların da kendiniz tarafından yazılabildiği ortamlar oluşturabilirsiniz. Günümüzde 2.2 GHz de Cortex-A72 tarlası içeren işlemci soketleri bulunabilmektedir. Bunların da 20Gbps veya 40Gbps ethernet arayüzlerinden giden gelen paket trafiğini yönlendirebildiğini gözlemleme fırsatlarım oldu.
Tabiki daha yüksek verimli mimariler kurabilmek mümkün. Ancak bunun için FPGA, ASIC çözümlere gitmek gerekir. Çarp topla gibi matris işlemlerinin yoğun olduğu sinyal/görüntü işleme metodlarında hala CPU verimli bir çözüm olmamaktadır. Intel AVX512, ARM NEON, FPGA DSP48 primitive, GPU mimarileri paralel procesing için yoğun olarak tercih edilen vektör processörlerdir.
Paralel programlama ve güçlü co-processorlerin varlığı ve de bunları open source kaynaklar ile yazılımcıların kullanımına sunan teknolojileri bir araya getiren yazılım geliştirme platformları sunulmaktadır. Intel OneAPI, Xilinx SDSoC, Xilinx HLS gibi platformlar ile çözümler sunulmaktadır.
Günümüzde machine learning veya deep learning gibi neural network (NN) mimarilerine olan ilgi yoğun bir şekilde artmaktadır. Örneğin geleneksel sinyal/görüntü işleme metodlarıyla nesne tanıma, yüz tanıma, ses tanıma zor bir çözüm yolu iken iyi eğitilmiş bir NN ile çok daha doğruluğu yüksek ve performans içeren sonuçlar elde edilebilir. Zaten günümüzde GPU, FPGA gibi mimarilere olan ihtiyacın artması hatta bu yapıların içerisine Nvidia Tensor Core mimarilerinin eklenmesinde en büyük etken olmaktadır. ML algoritmaları bunları kullanıma sunan Tensorflow, Caffe, Keras gibi NN çözümlerinin hem öğrenme hem de inference yani sonuç çıkarım süreçleri bir arada yapılabilmektedir. ML alanında ARM da çalışmalarını hızlandırıyor ancak NN eğitilmesi için gereken işlem gücü konusunda daha çok ilerlemesi gerekecek görünüyor. Müşterilerini daha çok eğitilmiş networkün modelinin ARMNN ML API yazılım kütüphaneleriyle kendi çözümleri üzerinde çalıştırılabilir hale getirmeyi hedefliyor. Daha yeni duyurduğu ARM ETNOS-N77 mimarisiyle CNN ve RNN networklerininde daha iyi çözümler sunacak gibi görünüyor.
Son söz olarak ihtiyaçlarınıza ve pazara erişim hızınıza göre en doğru seçimleri yapabilmeniz dileğiyle hepimize başarılar dilerim.
Using VS and VS Code for Embedded C/C++ Development - Marc Goodner, Microsoft (53dk)
Operating System #21 Scheduling in Linux: O(n), O(1) Scheduler (24dk)
Operating System #22 Completely Fair Scheduling (CFS) (15dk)
Exploring Linux Kernel Source Code with Eclipse and QTCreator (53dk)
Real Time is Coming to Linux; What Does that Mean to You? - Steven Rostedt, VMware (51dk)