Ken*_*Liu 3 c struct bit-manipulation intel cpu-registers
我使用这两种方法从寄存器中获取位字段信息.我需要提取的位字段的位置由Intel Manual提供.就像下面的代码一样.但是我得到的结果与这两种方法不同.
我找不到这两种方法的任何问题.但根据我的理解,maximum_power字段不应该是'0'作为第一种方法(这是英特尔已经在寄存器中定义的值.)
方法1:
typedef struct rapl_parameters_msr_t {
uint64_t thermal_spec_power : 15;
uint64_t : 1;
uint64_t minimum_power : 15;
uint64_t : 1;
uint64_t maximum_power : 15;
uint64_t : 1;
uint64_t maximum_limit_time_window : 6;
uint64_t : 10;
} rapl_parameters_msr_t;
uint64_t msr;
read_msr(cpu, 0x614, &msr);
rapl_parameters_msr_t domain_msr = *(rapl_parameters_msr_t *)&msr;
printf("%ld\n", domain_msr.thermal_spec_power); //print: 280
printf("%ld\n", domain_msr.minimum_power); //print: 192
printf("%ld\n", domain_msr.maximum_power); //print: 0
printf("%ld\n", domain_msr.maximum_limit_time_window); //print: 16
Run Code Online (Sandbox Code Playgroud)
方法2:
uint64_t
extractBitField(uint64_t inField, uint64_t width, uint64_t offset)
{
uint64_t bitMask;
uint64_t outField;
if ((offset+width) == 32)
{
bitMask = (0xFFFFFFFF<<offset);
}
else
{ /*Just keep the filed needs to be extrated*/
bitMask = (0xFFFFFFFF<<offset) ^ (0xFFFFFFFF<<(offset+width));
}
/*Move to the right most field to be calculated*/
outField = (inField & bitMask) >> offset;
return outField;
}
uint64_t flags;
read_msr(cpu, 0x614, &flags);
printf("thermal power: %d\n", extractBitField(flags,15,0)); //print: 280
printf("minimum power: %d\n", extractBitField(flags,15,16));//print: 192
printf("maximum power: %d\n", extractBitField(flags,15,32));//print: 0
printf("time window: %d\n", extractBitField(flags,6,48)); //print: 0
Run Code Online (Sandbox Code Playgroud)
你有什么见解可以解决问题吗?
更新:
对不起困惑的部分.我将所有类型更改为uint64_t,方法2的最大功率和时间窗口都为0.
如果编译器会使方法1产生错误的结果,我仍然怀疑我对方法2的结果有多信任.
以下是英特尔手册中的位代表文档:
Thermal Spec Power (bits 14:0)
Minimum Power (bits 30:16)
Maximum Power (bits 46:32)
Maximum Time Window (bits 53:48)
Run Code Online (Sandbox Code Playgroud)
感谢大卫,这是64位提取的正确版本.
uint64_t
extractBitField(uint64_t inField, uint64_t width, uint64_t offset)
{
uint64_t bitMask;
uint64_t outField;
if ((offset+width) == 64)
{
bitMask = (0xFFFFFFFFFFFFFFFF<<offset);
}
else
{ /*Just keep the filed needs to be extrated*/
bitMask = (0xFFFFFFFFFFFFFFFF<<offset) ^ (0xFFFFFFFFFFFFFFFF<<(offset+width));
}
/*Move to the right most field to be calculated*/
outField = (inField & bitMask) >> offset;
return outField;
}
uint64_t flags;
read_msr(cpu, 0x614, &flags);
printf("thermal power: %d\n", extractBitField(flags,15,0)); //print: 280
printf("minimum power: %d\n", extractBitField(flags,15,16));//print: 192
printf("maximum power: %d\n", extractBitField(flags,15,32));//print: 0
printf("time window: %d\n", extractBitField(flags,6,48)); //print: 16
Run Code Online (Sandbox Code Playgroud)
小智 5
C位域中位的排序是实现定义的,所以如果你打算使用它们要小心 - 你认为你得到的顺序可能不是你实际的.检查编译器的文档,看看它是如何处理的.
此外,您的第二个函数接受uint32,而您的第一个示例使用64位结构,因此您的类型不匹配.你能纠正这个并更新你的结果吗?
编辑:此外,您在第一个示例中将时间窗口定义为六位,在第二个示例中定义为15.
C99:6.7.2.1p10实现可以分配足够大的任何可寻址存储单元来保存位字段.如果剩余足够的空间,则紧跟在结构中的另一个位字段之后的位字段将被打包到相同单元的相邻位中.如果剩余的空间不足,则是否将不适合的位域放入下一个单元或重叠相邻单元是实现定义的.单元内的位域分配顺序(高阶到低阶或低阶到高阶)是实现定义的.未指定可寻址存储单元的对齐.