Cgroups sistematiği içerisindeki en önemli kalemlerden biri cpu ve bellek kaynaklarının hiyerarşik yönetimidir.
Bunun için cgroup sanal dosya sistemi mount edilmişse, dosya sistemi arayüzü üzerinden dizin açma, dosyaların içerisine değer atama yöntemleriyle konfigürasyon yapmak mümkündür.
Örnek olarak cgroup sistemi /sys/fs/cgroup
dizini altına mount edilmiş ise, cpuset işlemleri için /sys/fs/cgroup/cpuset
dizini kullanılır.
# mkdir /sys/fs/cgroup/cpuset/egitim
şeklinde bir komut çalıştırdığımızda otomatik olarak yeni bir grup oluşturulmuş olur.
Bu dizin içerisine baktığımızda aşağıdaki sanal dosyaların olduğunu görürüz:
# ls /sys/fs/cgroup/cpuset/egitim
cgroup.clone_children
cpuset.cpus
cpuset.memory_migrate
cpuset.memory_spread_slab
cpuset.sched_relax_domain_level
cgroup.procs
cpuset.mem_exclusive
cpuset.memory_pressure
cpuset.mems
notify_on_release
cpuset.cpu_exclusive
cpuset.mem_hardwall
cpuset.memory_spread_page
cpuset.sched_load_balance
tasks
Örnek olarak 4 çekirdekli bir sistemde, 2 ve 3 nolu çekirdekleri egitim adını verdiğimiz cpu kümesine dahil etmek istersek aşağıdaki komutu vermemiz yeterlidir:
# echo 2,3 > /sys/fs/cgroup/cpuset/egitim/cpuset.cpus
Bir NUMA bellek node'unu atamak istersek bu defa komutumuz aşağıdaki gibi olacaktır:
# echo 0 > /sys/fs/cgroup/cpuset/egitim/cpuset.mems
Çalışan bir uygulamanın PID (proses numarası) değerini ilgili cpuset dizini altındaki tasks
dosyasına yazdığımızda, uygulamanın dahil olduğu cpu kümesi değiştirilmiş olur. Örnek olarak 12345 PID değerine sahip uygulamayı egitim
adındaki cpu kümemize aktaracak olursak aşağıdaki komutu kullanabiliriz:
# echo 12345 > /sys/fs/cgroup/cpuset/egitim/tasks
Bu kullanım modeli pek pratik olmadığından, işleri bizim için kolaylaştıran cset uygulamasını kullanmanız önerilir. Uygulamayı aşağıdaki komutla sisteminize kurabilirsiniz:
$ sudo apt-get install cpuset
NOT: cset uygulaması henüz yeni 3.X serisi çekirdeklerdeki isimlendirme değişiklikleriyle düzgün çalışamamaktadır. Bu nedenle hiç cpuset yaratılmamış ise,
No such file or directory: '/cpusets//cpus'
şeklinde hata mesajlarıyla sonlanmaktadır. Geçici çözüm için ilk cpuset'ini yukarıda anlatıldığı şekliylemkdir
komutuyla dizin oluşturarak yapmamız yeterlidir.
Örnek senaryomuzda şunları yapalım:
4 çekirdekli bir sistemimiz olduğunu düşünelim
system
adında bir cpuset oluşturup 0 ve 1 nolu çekirdekleri bu kümeye atalım
producer
adında bir cpuset oluşturup 2 nolu çekirdeği atayalım, aynı sistem üzerindeki bir başka yazılımımıza yoğun hızda paket gönderimi yapacak bir uygulamayı bu kümeye dahil edelim
consumer
adında bir cpuset oluşturup 3 nolu çekirdeği atayalım, producer yazılımından yoğun olarak gelen paketleri aynı hızda işleyebilmek için hazırladığımız server yazılımını bu kümeye dahil edelim
İşlemlere başlarken ilk kümeyi cset bug'ı nedeniyle mkdir
ile oluşturuyoruz:
# mkdir /sys/fs/cgroup/cpuset/system
Ardından mevcut cpuset'lerin listesini alalım:
# cset set --list
cset:
Name CPUs-X MEMs-X Tasks Subs Path
------------ ---------- - ------- - ----- ---- ----------
root 0-3 y 0 y 492 1 /
system ***** n ***** n 0 0 /system
Sonrasında 0 ve 1 nolu çekirdekleri system
kümesine dahil edelim ve son durumu listeleyelim:
cset set -c 0,1 -m 0 -s system
cset: --> modified cpuset "system"
# cset set --list
cset:
Name CPUs-X MEMs-X Tasks Subs Path
------------ ---------- - ------- - ----- ---- ----------
root 0-3 y 0 y 493 1 /
system 0-1 n 0 n 0 0 /system
Devamında 2 ve 3 nolu çekirdekleri sırasıyla producer
ve consumer
kümelerini oluşturarak ilişkilendirelim:
# cset set -c 2 -s producer
cset: --> created cpuset "producer"
# cset set -c 3 -s consumer
cset: --> created cpuset "consumer"
# cset set --list
cset:
Name CPUs-X MEMs-X Tasks Subs Path
------------ ---------- - ------- - ----- ---- ----------
root 0-3 y 0 y 475 3 /
consumer 3 n 0 n 0 0 /consumer
system 0-1 n 0 n 0 0 /system
producer 2 n 0 n 0 0 /producer
Çıktıda görüleceği üzere root
cpuset'i sistemde öntanımlı olarak bulunmakta ve tüm eski prosesler ile yeni başlayan prosesler bu kümeye girmektedir. root
kümesi içerisinde tüm işlemci çekirdek dahil olduğu için (0-3), öncelikle root
altındaki tüm prosesleri yeni oluşturduğumuz system
adındaki kümeye taşımak için aşağıdaki komutu kullanalım:
# cset proc -m -f root -t system
cset: moving all tasks from root to /system
cset: moving 390 userspace tasks to /system
[==================================================]%
cset: done
# cset set --list
cset:
Name CPUs-X MEMs-X Tasks Subs Path
------------ ---------- - ------- - ----- ---- ----------
root 0-3 y 0 y 80 3 /
consumer 3 n 0 n 0 0 /consumer
system 0-1 n 0 n 390 0 /system
producer 2 n 0 n 0 0 /producer
Görüldüğü üzere 390 adet proses system
kümesine geçti, ancak halen 80 tanesi root
kümesinde durmaya devam ediyor. Bunlar kernel seviyesinde çalışan kernel thread'leridir. Eğer realtime ihtiyaçları olan uygulamalarımız söz konusu ise, bu kernel thread'lerini de root
kümeden alıp system
kümesine taşımak için aşağıdaki komutu verebilirsiniz:
# cset proc -k -f root -t system
cset: moving all kernel threads from / to /system
cset: moving 50 kernel threads to: /system
cset: --> not moving 28 threads (not unbound, use --force)
[==================================================]%
cset: **> 32 tasks are not movable, impossible to move
cset: done
# cset set --list
cset:
Name CPUs-X MEMs-X Tasks Subs Path
------------ ---------- - ------- - ----- ---- ----------
root 0-3 y 0 y 60 3 /
consumer 3 n 0 n 0 0 /consumer
system 0-1 n 0 n 408 0 /system
producer 2 n 0 n 0 0 /producer
Bazı task'lar daha system
kümesine taşındı ama diğerlerini taşımak mümkün olmadı. Bu noktada sistem ayarlarını bırakıp uygulamalarımızı ilgili kümelerde çalıştırma işlemine geçelim.
Yapacağımız test şu adımlardan oluşacak:
udp_msg_server
adındaki uygulamamızı consumer
kümesi içerisinde başlatacağız
udp_msg_client
uygulamamızı producer
kümesi içerisinde başlatacağız
Başka bir konsolda normalde sistem kaynağının tümünü tüketecek olan kernel kaynak kod derleme sürecini make -j 8
parametresiyle başlatacağız
Tüm bunlara rağmen uygulamamızın düzgün çalışıp çalışmadığını kontrol edeceğiz
Yeni başlattığımız uygulamaları bir kümeye dahil etmek için normalde uygulamanın PID değerini öğrenip, ilgili küme dizini altındaki tasks
dosyasına yazmak gereklidir. Bunu elle yapmak zaman kaybı olduğu için cset
uygulaması üzerinden uygulamamızı başlatacağız ve bizim için PID değerininin yazımı işlemini cset halledecek. Dikkat etmemiz gereken tek nokta, uygulamamız eğer parametre alıyorsa, uygulamanın parametlerini yazmaya başlamadan önce, konsolda parametre parsing işlemini sonlandıran --
kısayolunu kullanmak olacaktır.
# consumer için
# cset proc -s consumer -e ./udp_msg_server -- -s RR -r 16000000
cset: --> last message, executed args into cpuset "/consumer", new pid is: 3059
# producer için
# cset proc -s producer -e ./udp_msg_client -- -t 1000000
cset: --> last message, executed args into cpuset "/producer", new pid is: 10058