我使用这两种方法从寄存器中获取位域信息。我需要提取的位字段的位置由英特尔手册给出。正如下面的代码。但是我得到的结果与这两种方法不同。
我找不到这两种方法的任何问题。但据我了解,maximum_power filed 不应该像第一种方法那样为'0'(这是英特尔已经在寄存器中定义的值。)
方法一:
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
方法二:
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
您是否知道问题出在哪里?
更新:
抱歉让您感到困惑。我将所有类型更改为 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)
感谢 David,这是 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
最佳答案
C 位域中位的顺序是实现定义的,所以如果您计划使用它们,请小心——您认为获得的顺序可能与您实际的顺序不同。查看编译器的文档以了解它如何处理此问题。
此外,您的第二个函数采用 uint32,而您的第一个示例使用的是 64 位结构,因此您的类型不匹配。你能更正它并更新你的结果吗?
编辑:此外,您在第一个示例中将时间窗定义为 6 位,在第二个示例中定义为 15 位。
C99:6.7.2.1p10 An implementation may allocate any addressable storage unit large enough to hold a bit- field. If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit. If insufficient space remains, whether a bit-field that does not fit is put into the next unit or overlaps adjacent units is implementation-defined. The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined. The alignment of the addressable storage unit is unspecified.
关于c - 在c中用struct提取位域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24089751/