Jawabannya adalah dengan menggunakan cpusets. Utilitas cpuset python memudahkan untuk mengonfigurasinya.
Konsep dasar
3 cpuset
root
:ada di semua konfigurasi dan berisi semua cpu (unshielded )system
:berisi cpu yang digunakan untuk tugas sistem - tugas yang perlu dijalankan tetapi tidak "penting" (tidak terlindung )user
:berisi cpus yang digunakan untuk tugas "penting" - tugas yang ingin kita jalankan dalam mode "waktu nyata" (terlindung )
shield
perintah mengelola 3 cpuset ini.
Selama penyiapan, ini memindahkan semua tugas yang dapat dipindahkan ke cpuset yang tidak dilindungi (system
) dan selama pembongkaran itu memindahkan semua tugas yang dapat dipindahkan ke root
cpuset.Setelah penyiapan, subperintah memungkinkan Anda memindahkan tugas ke perisai (user
) cpuset, dan sebagai tambahan, untuk memindahkan tugas khusus (kernel thread) dari root
ke system
(dan karenanya keluar dari user
cpuset).
Perintah:
Pertama kita membuat perisai. Secara alami tata letak pelindung akan bergantung pada mesin/tugas. Misalnya, kita memiliki mesin non-NUMA 4 inti:kita ingin mendedikasikan 3 inti untuk perisai , dan sisakan 1 inti untuk tugas yang tidak penting; karena ini bukan NUMA, kami tidak perlu menentukan parameter node memori apa pun, dan kami membiarkan utas kernel berjalan di root
cpuset (yaitu:di semua cpu)
$ cset shield --cpu 1-3
Beberapa utas kernel (yang tidak terikat pada cpu tertentu) dapat dipindahkan ke system
cpuset. (Secara umum, bukanlah ide yang baik untuk memindahkan utas kernel yang telah terikat ke cpu tertentu)
$ cset shield --kthread on
Sekarang mari kita buat daftar apa yang berjalan di perisai (user
) atau tanpa pelindung (system
) cpuset:(-v
untuk verbose, yang akan mencantumkan nama proses) (tambahkan -v
ke-2 untuk menampilkan lebih dari 80 karakter)
$ cset shield --shield -v
$ cset shield --unshield -v -v
Jika kita ingin menghentikan perisai (teardown)
$ cset shield --reset
Sekarang mari kita jalankan proses di perisai (perintah mengikuti '--'
diteruskan ke perintah yang akan dieksekusi, bukan ke cset
)
$ cset shield --exec mycommand -- -arg1 -arg2
Jika kita sudah memiliki proses yang sedang berjalan yang ingin kita pindahkan ke perisai (perhatikan bahwa kita dapat memindahkan beberapa proses dengan meneruskan daftar yang dipisahkan koma, atau rentang (proses apa pun dalam rentang tersebut akan dipindahkan, bahkan jika ada celah))
$ cset shield --shield --pid 1234
$ cset shield --shield --pid 1234,1236
$ cset shield --shield --pid 1234,1237,1238-1240
Konsep lanjutan
cset set/proc
- ini memberi Anda kontrol cpuset yang lebih baik
Tetapkan
Buat, sesuaikan, ganti nama, pindahkan, dan hancurkan cpuset
Perintah
Buat cpuset, gunakan cpus 1-3, gunakan NUMA node 1 dan beri nama "my_cpuset1"
$ cset set --cpu=1-3 --mem=1 --set=my_cpuset1
Ubah "my_cpuset1" untuk hanya menggunakan cpus 1 dan 3
$ cset set --cpu=1,3 --mem=1 --set=my_cpuset1
Hancurkan cpuset
$ cset set --destroy --set=my_cpuset1
Ganti nama cpuset yang ada
$ cset set --set=my_cpuset1 --newname=your_cpuset1
Buat cpuset hierarkis
$ cset set --cpu=3 --mem=1 --set=my_cpuset1/my_subset1
Buat daftar cpuset yang ada (kedalaman level 1)
$ cset set --list
Cantumkan cpuset yang ada dan turunannya
$ cset set --list --set=my_cpuset1
Buat daftar semua cpuset yang ada
$ cset set --list --recurse
Proses
Kelola utas dan proses
Perintah
Buat daftar tugas yang berjalan di cpuset
$ cset proc --list --set=my_cpuset1 --verbose
Jalankan tugas di cpuset
$ cset proc --set=my_cpuset1 --exec myApp -- --arg1 --arg2
Memindahkan tugas
$ cset proc --toset=my_cpuset1 --move --pid 1234
$ cset proc --toset=my_cpuset1 --move --pid 1234,1236
$ cset proc --toset=my_cpuset1 --move --pid 1238-1340
Memindahkan tugas dan semua saudara kandungnya
$ cset proc --move --toset=my_cpuset1 --pid 1234 --threads
Pindahkan semua tugas dari satu cpuset ke yang lain
$ cset proc --move --fromset=my_cpuset1 --toset=system
Pindahkan utas kernel yang tidak disematkan ke cpuset
$ cset proc --kthread --fromset=root --toset=system
Memindahkan secara paksa utas kernel (termasuk yang disematkan ke cpu tertentu) ke dalam cpuset (catatan:ini mungkin memiliki konsekuensi yang mengerikan bagi sistem - pastikan Anda tahu apa yang Anda lakukan)
$ cset proc --kthread --fromset=root --toset=system --force
Contoh hierarki
Kita dapat menggunakan cpuset hierarkis untuk membuat pengelompokan yang diprioritaskan
- Buat
system
cpuset dengan 1 cpu (0) - Buat
prio_low
cpuset dengan 1 cpu (1) - Buat
prio_met
cpuset dengan 2 cpu (1-2) - Buat
prio_high
cpuset dengan 3 cpu (1-3) - Buat
prio_all
cpuset dengan semua 4 cpus (0-3) (perhatikan ini sama dengan root; ini dianggap praktik yang baik untuk menjaga pemisahan dari root)
Untuk mencapai hal di atas, Anda membuat prio_all, lalu membuat subset prio_high di bawah prio_all, dll
$ cset set --cpu=0 --set=system
$ cset set --cpu=0-3 --set=prio_all
$ cset set --cpu=1-3 --set=/prio_all/prio_high
$ cset set --cpu=1-2 --set=/prio_all/prio_high/prio_med
$ cset set --cpu=1 --set=/prio_all/prio_high/prio_med/prio_low
Ada dua cara lain yang dapat saya pikirkan untuk melakukan ini (walaupun tidak seanggun cset, yang tampaknya tidak memiliki tingkat dukungan yang fantastis dari Redhat):
1) Taskset semuanya termasuk PID 1 - bagus dan mudah (tetapi, diduga - Saya sendiri belum pernah melihat masalah apa pun - dapat menyebabkan ketidakefisienan dalam penjadwalan). Skrip di bawah ini (yang harus dijalankan sebagai root) menjalankan kumpulan tugas pada semua proses yang berjalan, termasuk init (pid 1); ini akan menyematkan semua proses yang berjalan ke satu atau lebih 'inti sampah', dan dengan menyematkan init, ini akan memastikan bahwa setiap proses selanjutnya juga dimulai dalam daftar 'inti sampah':
#!/bin/bash
if [[ -z $1 ]]; then
printf "Usage: %s '<csv list of cores to set as junk in double quotes>'", $0
exit -1;
fi
for i in `ps -eLfad |awk '{ print $4 } '|grep -v PID | xargs echo `; do
taskset -pc $1 $i;
done
2) gunakan parameter kernel isolcpus (berikut dokumentasi dari https://www.kernel.org/doc/Documentation/kernel-parameters.txt):
isolcpus= [KNL,SMP] Isolate CPUs from the general scheduler.
Format:
<cpu number>,...,<cpu number>
or
<cpu number>-<cpu number>
(must be a positive range in ascending order)
or a mixture
<cpu number>,...,<cpu number>-<cpu number>
This option can be used to specify one or more CPUs
to isolate from the general SMP balancing and scheduling
algorithms. You can move a process onto or off an
"isolated" CPU via the CPU affinity syscalls or cpuset.
<cpu number> begins at 0 and the maximum value is
"number of CPUs in system - 1".
This option is the preferred way to isolate CPUs. The
alternative -- manually setting the CPU mask of all
tasks in the system -- can cause problems and
suboptimal load balancer performance.
Saya telah menggunakan keduanya plus mekanisme cset untuk beberapa proyek (kebetulan, mohon maafkan promosi diri yang terang-terangan :-)), saya baru saja mengajukan paten untuk alat yang disebut Pontus Vision ThreadManager yang muncul dengan strategi penyematan yang optimal untuk semua platform x86 yang diberikan untuk setiap beban kerja perangkat lunak yang diberikan; setelah mengujinya di situs pelanggan, saya mendapatkan hasil yang sangat bagus (pengurangan 270% dalam latensi puncak), jadi sebaiknya lakukan penyematan dan isolasi CPU.