Skip to content

isolcpus và cô lập scheduler domain

Cô lập CPU (CPU isolation) là dành riêng một số core cho một workload, sao cho kernel không chen công việc của nó vào các core đó. Trang này trình bày tham số boot isolcpus= và cách thay thế nó bằng cpuset của cgroup v2, theo thứ tự: khái niệm housekeeping, cú pháp và các cờ của isolcpus=, cách kernel xử lý tham số, cpuset isolated partition, cách kiểm tra và các giới hạn. Phần tắt tick định kỳ được trình bày ở nohz_full và adaptive tick, phần định tuyến ngắt ở IRQ affinity và irqbalance.

Nội dung dựa trên tài liệu và mã nguồn kernel mainline bản 7.4-rc1. Các mốc phiên bản được ghi rõ ở từng chỗ.

Nhiễu kernel và housekeeping

Tài liệu kernel gọi các can thiệp của kernel lên một core là nhiễu (noise). Nhiễu có hai loại: bất đồng bộ, như ngắt, timer, workqueue và kthread chiếm core; và đồng bộ, như system call và page fault do chính workload gây ra. Với đa số workload, nhiễu này không đáng kể. Với xử lý gói tin băng thông cao bằng DPDK, xử lý tín hiệu vRAN hoặc vòng điều khiển real-time, mỗi lần bị chen ngang làm tăng độ trễ tối đa (worst-case latency).

Housekeeping là phần việc nền mà kernel phải làm để duy trì dịch vụ của nó. Core housekeeping là các core không bị cô lập, nơi nhận phần việc đó. Cách đẩy việc ra khỏi core cô lập phụ thuộc vào tính chất của việc:

Loại việc Ví dụ Cách xử lý
Không gắn với core nào (unbound) Unbound workqueue, kthread, timer toàn cục Chuyển sang core housekeeping
Gắn với một core (bound), có bản thay thế RCU callback Chuyển sang cơ chế có khóa, chạy ở kthread riêng (rcu_nocbs)
Gắn với một core, không có bản thay thế Lockup watchdog, clocksource không ổn định Tắt tính năng, coi là không tương thích với core cô lập
Gắn với một core, có cơ chế bù Tick định kỳ Tắt tick khi core chỉ chạy một task (nohz_full), đổi lại chi phí vào/ra kernel cao hơn

Do việc housekeeping luôn tồn tại, hệ thống phải giữ ít nhất một core housekeeping. Tài liệu kernel khuyến nghị nhiều hơn trên máy nhiều core, ví dụ mỗi NUMA node một core.

Phân chia việc giữa core housekeeping và core cô lập

Cú pháp isolcpus

isolcpus=[flag-list,]<cpu-list>

<cpu-list> dùng cú pháp danh sách CPU chung của kernel command line (ví dụ 2-7 hoặc 1,3-5), đánh số từ 0. Xem cách truyền tham số qua bootloader ở Kernel Command Line.

Cờ Tác dụng Tương đương
domain Bỏ core khỏi thuật toán cân bằng tải và lập lịch SMP. Task không tự di chuyển tới hoặc rời khỏi core, trừ khi được gắn affinity tường minh. Core cũng bị loại khỏi unbound workqueue và unbound kthread Cpuset partition isolated
nohz Tắt tick khi core chỉ chạy một task, đồng thời offload RCU callback nohz_full=
managed_irq Tránh gửi managed interrupt (ngắt do kernel tự quản lý affinity) tới core cô lập, theo kiểu best effort Không có

Hình dưới so sánh cân bằng tải trước và sau khi cô lập bằng cờ domain: core cô lập nằm ngoài scheduler domain, scheduler chỉ di chuyển task giữa các core housekeeping.

Scheduler domain trước và sau isolcpus=domain

Khi không ghi cờ nào, kernel dùng mặc định domain. Vì vậy isolcpus=2-7 và isolcpus=domain,2-7 cho cùng kết quả. Có thể kết hợp nhiều cờ, ví dụ isolcpus=domain,managed_irq,2-7.

Cờ managed_irq chỉ có hiệu lực khi mask ngắt mà kernel tự gán cho một hàng đợi thiết bị chứa cả core cô lập lẫn core housekeeping. Khi đó ngắt được hướng sang core housekeeping. Nếu mask của hàng đợi chỉ gồm core cô lập, cờ này không thay đổi việc định tuyến, nhưng ngắt của hàng đợi đó chỉ phát sinh khi chính task trên core cô lập gửi I/O. Chi tiết về managed interrupt nằm ở IRQ affinity và irqbalance.

Xử lý tham số trong kernel

Hai tham số isolcpus= và nohz_full= cùng được xử lý trong kernel/sched/isolation.c. Mỗi tham số được chuyển thành một cpumask housekeeping (tập core không bị cô lập) cho từng loại việc:

Kiểu housekeeping Bật bởi Ý nghĩa
HK_TYPE_DOMAIN isolcpus=domain (hoặc không cờ), cpuset isolated Core tham gia scheduler domain và unbound workqueue
HK_TYPE_MANAGED_IRQ isolcpus=managed_irq Core được ưu tiên nhận managed interrupt
HK_TYPE_KERNEL_NOISE nohz_full= hoặc isolcpus=nohz Core nhận tick, timer, RCU callback và các nhiễu khác thay cho core nohz_full

Các subsystem khác gọi housekeeping_cpumask() để biết nên đặt công việc ở đâu. Khi kết hợp tham số, kernel kiểm tra một số ràng buộc và in cảnh báo vào log boot nếu vi phạm:

  • Nếu cả nohz_full= và isolcpus=nohz cùng được dùng, hai danh sách phải giống nhau. Nếu khác, kernel in Housekeeping: nohz_full= must match isolcpus= và bỏ tham số thứ hai.
  • Phải còn ít nhất một core có mặt (present) không thuộc nohz_full= lẫn isolcpus=domain. Nếu không, kernel bỏ qua tham số và in cảnh báo.
  • Cờ không hợp lệ (chứa ký tự không phải chữ cái hoặc _) làm cả tham số bị bỏ. Cờ chỉ gồm chữ cái nhưng không biết thì bị bỏ qua với thông báo isolcpus: Skipped unknown flag.

Vì vậy, sau khi đổi tham số, cần đọc dmesg | grep -i -E "housekeeping|isolcpus" để chắc chắn tham số được nhận.

Cpuset isolated partition

Cpuset trong cgroup v2 cung cấp cùng hiệu ứng với isolcpus=domain nhưng thay đổi được lúc chạy. Một cgroup có thể được đặt thành partition root qua file cpuset.cpus.partition:

Giá trị Ý nghĩa
member Thành viên bình thường của partition cha (mặc định)
root Partition root, tạo một scheduler domain riêng gồm các core độc quyền của nó
isolated Partition root không có cân bằng tải, các core bị loại khỏi unbound workqueue

Partition giữ quyền dùng độc quyền tập core của nó: cgroup bên ngoài partition không dùng được các core đó. Khi đọc lại, file có thể hiện root invalid (<lý do>) hoặc isolated invalid (<lý do>) nếu điều kiện hợp lệ bị phá, ví dụ do hotplug CPU hoặc do sửa cpuset.cpus. File này hỗ trợ poll và inotify để một agent ở user space theo dõi thay đổi trạng thái.

File cpuset.cpus.isolated ở cgroup gốc (chỉ đọc) liệt kê mọi core đang bị cô lập, gồm core của các isolated partition và core cô lập lúc boot bằng isolcpus=domain. Core cô lập lúc boot vẫn được liệt kê kể cả khi partition dùng chúng đã bị hủy.

Hình dưới là cây cgroup sau khi chạy ví dụ bên dưới: partition rt/ giữ riêng CPU 7, các cgroup khác chỉ còn CPU 0-6.

Cây cpuset với isolated partition

Ví dụ cô lập CPU 7 trên máy 8 core, giả sử cgroup v2 được mount ở /sys/fs/cgroup (theo ví dụ trong tài liệu CPU isolation của kernel):

cd /sys/fs/cgroup
echo +cpuset > cgroup.subtree_control
mkdir rt
echo 7 > rt/cpuset.cpus
echo isolated > rt/cpuset.cpus.partition
cat rt/cpuset.cpus.partition            # kỳ vọng: isolated
echo $$ > rt/cgroup.procs               # đưa shell hiện tại vào partition

Những điểm cần lưu ý khi dùng cpuset:

  • Nếu partition có nhiều core, task trong đó cần được gắn affinity tới từng core cụ thể. Không có cân bằng tải nên scheduler không tự phân bố task.
  • Core đã cô lập bằng isolcpus= lúc boot chỉ được đưa vào partition kiểu isolated, không đưa vào partition root.
  • Không thể tạo partition con kiểu root bên dưới partition cha kiểu isolated.

Todo

Chưa kiểm chứng cách cpuset partition tương tác với cây cgroup do systemd quản lý (thuộc tính AllowedCPUs= của unit). Cần thử trên hệ thống thực trước khi dùng cách ghi trực tiếp vào /sys/fs/cgroup ở môi trường production.

Giá trị isolated của cpuset.cpus.partition có trong tài liệu cgroup v2 từ kernel 6.1. File cpuset.cpus.isolated có từ kernel 6.8.

Trạng thái deprecated

Trong kernel-parameters.txt, isolcpus= mang nhãn [Deprecated - use cpusets instead] tới hết kernel 7.1. Từ kernel 7.2, nhãn này bị bỏ. Tài liệu mới Documentation/admin-guide/cpu-isolation.rst (có từ kernel 7.1) xếp hai cách như sau:

  • Cpuset isolated partition là cách được khuyến nghị, do điều chỉnh được lúc chạy.
  • isolcpus=domain là phương án kém linh hoạt hơn: cô lập lúc boot là không đảo ngược được, không thể đưa core trở lại scheduler domain mà không reboot.

Cờ managed_irq và nohz không có bản tương đương trong cpuset, nên vẫn phải dùng tham số boot cho hai phần này.

So sánh các cách gắn task vào core

Cách Phạm vi Thay đổi lúc chạy Ngăn task khác chạy trên core Bỏ cân bằng tải
taskset, sched_setaffinity() Một task Có Không Không
Cpuset member Một nhóm task Có Không Không
Cpuset partition root Một nhóm task, core độc quyền Có Có, với cgroup ngoài partition Không, có domain riêng
Cpuset partition isolated Một nhóm task, core độc quyền Có Có, với cgroup ngoài partition Có
isolcpus=domain Toàn hệ thống Không Chỉ ngăn scheduler tự đưa task tới. Task gắn affinity tường minh vẫn chạy được Có

taskset chỉ giới hạn nơi một task được chạy, không ngăn task khác chạy trên cùng core. Do đó taskset thường dùng kết hợp với một trong hai cơ chế cô lập ở cuối bảng.

Kiểm tra cấu hình

cat /proc/cmdline                                  # tham số boot đang dùng
cat /sys/devices/system/cpu/isolated               # core cô lập bằng isolcpus= (domain)
cat /sys/devices/system/cpu/housekeeping           # core housekeeping (kernel 6.19 trở lên)
cat /sys/fs/cgroup/cpuset.cpus.isolated            # core cô lập lúc boot và trong partition
cat /sys/devices/virtual/workqueue/cpumask         # core được chạy unbound workqueue
ps -eLo psr,pid,comm | awk '$1>=2'                 # thread đang chạy trên core 2 trở lên

File /sys/devices/system/cpu/housekeeping chỉ có giá trị khi dùng isolcpus=nohz hoặc nohz_full=. Kernel thread per-CPU (ví dụ ksoftirqd/N, kworker/N:M, migration/N, cpuhp/N) vẫn tồn tại trên core cô lập. Đây là bình thường: chúng gắn với core theo thiết kế và chỉ gây nhiễu khi có việc. Tài liệu kernel-per-CPU-kthreads.rst liệt kê từng loại và cách giảm nhiễu của chúng.

Để đo nhiễu thực tế, dùng rtla osnoise hoặc ftrace với event sched_switch và irq_vectors trên core cô lập. Quy trình đo được trình bày ở nohz_full và adaptive tick.

Giới hạn và lưu ý

  • isolcpus=domain không ngăn ngắt thiết bị tới core cô lập. Cần thêm irqaffinity=, chỉnh smp_affinity và cờ managed_irq.
  • isolcpus=domain không tắt tick. Tick định kỳ vẫn chạy trên core cô lập cho tới khi dùng nohz_full=.
  • Core cô lập không có cân bằng tải. Nếu gắn hai task vào cùng một core cô lập trong khi core cô lập khác rảnh, scheduler không chuyển task sang core rảnh.
  • Kernel thread unbound được đưa ra khỏi core cô lập, nhưng phần mềm user space vẫn có thể tự gắn affinity vào core cô lập. Cần kiểm tra lại affinity của các daemon sau khi cấu hình.
  • Cô lập core không thay thế cho các cấu hình khác: khóa bộ nhớ bằng mlock(), tắt SMT, giới hạn C-state sâu, cố định tần số và kiểm tra System Management Interrupt (SMI) của firmware. Tài liệu CPU isolation của kernel liệt kê các mục này trong phần checklist.

Liên quan

Tài liệu tham khảo