👻

CPU MASK

2022/10/16に公開

CPU MASK

CPU MASKとはCPUの状態を表すビットマップ配列です。
以下の4種類あり、それぞれが0または1の値を取る。

/include/linux/cpumask.h
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で初期化されます。

/kernel/cpu.c
//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 数)に合わせて表示されることになります。

https://zhuanlan.zhihu.com/p/163850501

https://www.dingmos.com/index.php/archives/35/

https://vh21.github.io/linux/2015/04/28/linux-cpu-mask.html

https://linux-note.hatenablog.com/search?q=cpumask

https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html

https://satoru739.hatenadiary.com/entry/20100820/1282274743

https://0xax.gitbooks.io/linux-insides/content/Concepts/linux-cpu-2.html

https://postd.cc/cpumask/

https://www.cnblogs.com/zhangzhiwei122/p/16093602.html

https://zhuanlan.zhihu.com/p/536776611

https://zhuanlan.zhihu.com/p/545550388

https://zhuanlan.zhihu.com/p/536776611

https://zhuanlan.zhihu.com/p/545550388

https://www.cnblogs.com/zhangzhiwei122/p/16093602.html

https://www.cnblogs.com/zhangzhiwei122/p/16093412.html

https://stackoverflow.com/questions/24437724/diff-between-various-cpu-masks-linux-kernel

https://vh21.github.io/linux/2015/04/28/linux-cpu-mask.html

https://image.slidesharecdn.com/cpuhotplugrcuandbig-140320112138-phpapp02/95/lce12-cpu-hotplug-rcu-and-biglittle-22-638.jpg?cb=1395333911

Discussion