哈嘍,大家好,我是LittleG。
前言
在Linux內(nèi)核中,CPU掩碼(cpumask
)用于表示一組CPU編號(hào),常用于描述進(jìn)程或任務(wù)的親和性、中斷或定時(shí)器的分配范圍等場(chǎng)景。
如下類(lèi)似打印:
Task scheduled on CPUs: 0-3,7
下面就記錄一些常用的打印cpumask
的方法。
正文
1、printk
?與?cpumask_printk
?宏:
Linux內(nèi)核中最常用的打印接口是printk
函數(shù),可以接收格式化字符串和參數(shù),類(lèi)似用戶(hù)空間的printf
。同時(shí)為了便于打印cpumask
,內(nèi)核還提供了一些輔助宏,如cpumask_printk
,可以接受一個(gè)cpumask_t
類(lèi)型的變量和一個(gè)格式化字符串作為參數(shù)。
例如:
#include <linux/cpumask.h>
#include <linux/kernel.h>
void print_cpu_mask(cpumask_t *mask)
{
printk(KERN_INFO "CPU mask: %*pbn", cpumask_bits(mask)[0]);
// 或者使用 cpumask_printk 宏
cpumask_printk("CPU mask: ", mask);
}
說(shuō)明: 上述代碼中,%*pb
是一種特殊的格式化符,用于打印位掩碼(cpumask_t
本質(zhì)上是一個(gè)位掩碼)。cpumask_bits(mask)[0]
獲取掩碼的第一個(gè)長(zhǎng)整型元素,用于指定要打印的位數(shù)。cpumask_printk
宏則提供了一種更直接的方式,它內(nèi)部會(huì)處理掩碼的格式化輸出。
2、dump_stack
?和?dump_cpu_mask
:
當(dāng)需要在內(nèi)核崩潰報(bào)告或調(diào)試信息中包含當(dāng)前CPU掩碼時(shí),可以調(diào)用dump_stack()
函數(shù),它會(huì)自動(dòng)打印當(dāng)前CPU的標(biāo)識(shí)。如果需要更詳細(xì)地打印某個(gè)cpumask_t
,可以結(jié)合dump_cpu_mask()
函數(shù),通常與dump_stack()
一起使用,用于在內(nèi)核oops堆棧跟蹤中輸出CPU掩碼。
例如:
#include <linux/dump_stack.h>
#include <linux/kernel.h>
void dump_cpu_mask_example(cpumask_t *mask)
{
dump_stack();
dump_cpu_mask(mask);
}
調(diào)用dump_cpu_mask_example()
時(shí),會(huì)在內(nèi)核日志中看到堆棧跟蹤信息以及跟隨其后的CPU掩碼打印。
3、直接訪問(wèn)cpumask_t
的位:
對(duì)于更精細(xì)的控制或特殊情況,可以直接遍歷cpumask_t
的位數(shù)組,并使用printk
打印其中的每一位。雖然cpumask_printk
通常已能滿足需求,但cpumask_t
提供了更大的靈活性。
例如:
#include <linux/bitops.h>
#include <linux/cpumask.h>
#include <linux/kernel.h>
void print_cpu_mask_manual(cpumask_t *mask)
{
int cpu;
for_each_cpu(cpu, mask) {
printk(KERN_INFO "CPU %d is set in the mask.n", cpu);
}
}
上述代碼使用for_each_cpu
宏遍歷cpumask_t
中的每個(gè)已置位CPU,并使用printk
打印其編號(hào)。
4、cpumask_pr_args
?宏
cpumask_pr_args
?可以直觀可讀的形式輸出?cpumask_t
?中包含的 CPU 核心編號(hào)列表,并將其作為函數(shù)參數(shù)傳遞給其他內(nèi)核日志打印函數(shù)。這樣做的好處是能夠方便地將?cpumask_t
?的內(nèi)容嵌入到其他日志消息中,而不必單獨(dú)調(diào)用cpumask_printk
或者手動(dòng)構(gòu)建包含 CPU 列表的字符串。
例如:
// https://elixir.bootlin.com/linux/latest/source/include/linux/cpumask.h#L36
/**
* cpumask_pr_args - printf args to output a cpumask
* @maskp: cpumask to be printed
*
* Can be used to provide arguments for '%*pb[l]' when printing a cpumask.
*/
#define cpumask_pr_args(maskp) nr_cpu_ids, cpumask_bits(maskp)
// https://elixir.bootlin.com/linux/latest/source/arch/arm64/kernel/cpufeature.c#L1521
static ssize_t aarch32_el0_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
const struct cpumask *mask = system_32bit_el0_cpumask();
return sysfs_emit(buf, "%*pbln", cpumask_pr_args(mask));
}
static const DEVICE_ATTR_RO(aarch32_el0);
說(shuō)明:
%*pbl
?是格式占位符,用于接收?cpumask_pr_args
?生成的 CPU 核心列表字符串。
%*pbl
?是內(nèi)核日志特有的格式說(shuō)明符,其中?*
?表示寬度由參數(shù)決定,pbl
?表示以空格分隔的 CPU 核心列表。
cpumask_pr_args
?提供了一種便捷的方式來(lái)將?cpumask_t
?的內(nèi)容以方便肉眼可讀的形式嵌入到日志消息中,通過(guò)使用?%*pbl
?格式說(shuō)明符與內(nèi)核日志打印函數(shù)(如?pr_info()
,?pr_debug()
,?pr_err()
?等)配合使用,可以清晰地記錄與 CPU 核心關(guān)聯(lián)的操作情況。
總結(jié),具體開(kāi)發(fā)過(guò)程中選擇哪種打印方法取決于具體的需求和調(diào)試環(huán)境。在大多數(shù)情況下,直接使用cpumask_printk
宏就可以滿足打印CPU掩碼的需求了。
下期見(jiàn)~