CPU MASK
CPU MASK
CPU MASKとはCPUの状態を表すビットマップ配列です。
以下の4種類あり、それぞれが0または1の値を取る。
cpu_possible_mask : NR_CPUSの値と同じになる。
cpu_present_mask : 現在、どのCPUが接続されているかを示す。
cpu_online_mask : cpu_present のサブセットで、スケジューラからアクセス可能なCPUを示す。
cpu_active_mask : このマスクのいくつかのビットは、タスクが特定のプロセッサに移動した可能性があることをLinuxカーネルに伝えます。
#以下グローバル変数としてアクセスできます。
extern struct cpumask __cpu_possible_mask;
extern struct cpumask __cpu_online_mask;
extern struct cpumask __cpu_present_mask;
extern struct cpumask __cpu_active_mask;
cpu_online_maskで説明します。
CPUを管理する配列です。ここでいうCPUとは物理CPUではなく、論理CPUです。
CPU数が8個の場合、1が2進数で8個並びます。
cpu_mask_online->bits[0] = 2進数で11111111の値になります。
72個の場合、1が2進数で72個並びます。
cpu_online_mask->bits[0]はunsigned long型(64bit)なので、
cpu_online_mask->bits[0]は1が64個並びます。
cpu_online_mask->bits[1]にあふれた1が8個並びます。
CPUの最大数はNR_CPUS = CONFIG_NR_CPUS = 8192なので1が8192個並ぶ可能性があります。
定義の計算式が以下です。
unsigend long cpu_online_mask->bits[NR_CPU * / sizeof(long)]
unsigned long cpu_online_mask->bits[8192 * /8]
unsigned long cpu_online_mask->bits[182]となります。
実際に設定するところを見ていきます。
2段階で設定しています。
boot_cpu_initで初期化されます。
//Activate the first processor.
void __init boot_cpu_init(void)
{
int cpu = smp_processor_id();
/* Mark the boot cpu "present", "online" etc for SMP and UP case */
set_cpu_online(cpu, true);
set_cpu_active(cpu, true);
set_cpu_present(cpu, true);
set_cpu_possible(cpu, true);
#ifdef CONFIG_SMP
__boot_cpu_id = cpu;
#endif
}
4つのCPU MAPですが、先にpossibleとpresentが決まります。
presentの値を受けてonlineが設定されます。
setup_arch
acpi_boot_init
acpi_process_madt
acpi_parse_madt_lapic_entries
acpi_table_parse_entries_array
acpi_parse_entries_array
acpi_parse_lapic
acpi_register_lapic
generic_processor_info
generic_processor_info {
set_cpu_possible(cpu, true);
physid_set(apicid, phys_cpu_present_map);
set_cpu_present(cpu, true);
num_processors++;
}
/online
Active the first processerとあるように最初の設定です。
smp_processor_id()は起動時0を返すので、cpu = 0です。
set_cpu_online(0, true)を実行します。
この結果, cpu_online_mask->bits[0]は1になります。
1番目以降はstart_secondaryが呼び出している。
smp_init()
bringup_nonboot_cpus()
cpu_up()
_cpu_up()
cpuhp_up_callbacks()
cpuhp_invoke_callback_range()
cpuhp_invoke_callback()
cpuhp_hp_states[CPUHP_BRINGUP_CPU]
bringup_cpu()
__cpu_up()
native_cpu_up()
do_boot_cpu()
start_secondary()
set_cpu_online()
set_cpu_online(1, true)
set_cpu_online(2, true)
set_cpu_online(3, true)
...
set_cpu_online(71, true)
以降、論理CPUの数だけset_cpu_onlineを設定しています。
CPUMASKを使ったモジュール
cpumask_set_cpu
cpumask_setall
#include <linux/cpumask.h>
#include <linux/init.h>
#include <linux/module.h>
// モジュールの初期化関数
static int __init cpumask_example_init(void)
{
// cpumask の宣言
cpumask_t my_cpumask;
// cpumask を初期化
cpumask_clear(&my_cpumask);
// CPU 0 と CPU 1 をセット
cpumask_set_cpu(0, &my_cpumask);
cpumask_set_cpu(1, &my_cpumask);
// 現在の CPU マスクの表示
printk(KERN_INFO "CPU mask: %*pbl\n", NR_CPUS, &my_cpumask);
// CPU 1 をクリア
cpumask_clear_cpu(1, &my_cpumask);
// CPU マスクを再表示
printk(KERN_INFO "CPU mask: %*pbl\n", NR_CPUS, &my_cpumask);
cpumask_setall(&my_cpumask);
printk(KERN_INFO "CPU mask: %*pbl\n", NR_CPUS, &my_cpumask);
return 0;
}
// モジュールの終了関数
static void __exit cpumask_example_exit(void)
{
printk(KERN_INFO "CPU mask example module exited.\n");
}
printk のフォーマット指定子 %*pbl は、Linux カーネル内でビットマスクを表示するために使用される特別なフォーマット指定子です。以下にそれぞれの部分について説明します。
フォーマット指定子の解説
%: フォーマット指定子の開始を示します。
: この指定子は、表示する幅を動的に指定することを意味します。具体的には、 の前に渡される引数(ここでは NR_CPUS)が、表示するビットマスクの幅を決定します。
p: この指定子は、ポインタを表示するために使用されます。この場合、ビットマスクのポインタを表示することを意味します。
b: この指定子は、ビットの値を二進数で表示します。つまり、ビットマスク内の各ビットの状態(0 または 1)を表示します。
l: この指定子は、cpumask 構造体を表示する際に、長さを考慮した表示を行うために使用されます。l がついていることで、ビットマスクのビット数(CPU 数)に合わせて表示されることになります。
Discussion