我正在使用inotify并希望有效地检查报告的位掩码事件(请参阅inotify man page)。
现在我可以粗暴地检查每一个事件的每一点,但如果不是愚蠢的话,这将非常粗糙,因为我每次都会有N个条件。或者正在呼叫
( bitmask & mask ) == mask
每个掩码已经超级高效?
由于结果位掩码基本上只是一个定义良好的数字,我应该可以使用基本的算术运算。但在我自己想到一些事情之前,我想问一下是否有一种众所周知的,有效的方法来检查给定的位掩码。那么,有吗?
答案 0 :(得分:8)
如果要检查一个位掩码,那么
if ((value & mask) == mask)
将为您提供完全匹配(“掩码中的所有位”)和
if ((value & mask) != 0)
将提供一个松散的匹配(“掩码中的任何位”)。编译器将进一步优化对零的检查。
如果您有多个位掩码,您希望从时域中的每个检查中提取最大信息(极端情况:如果您获得的所有值肯定奇数,则不需要检查第0位。它总是1)。理想情况下,您需要识别第一轮比特,其概率为50%。
在两组中,您都可以识别出具有相同机会的子组(在两种情况下可能不同)。
if ((value & SPECIAL_MASK_1) == SPECIAL_MASK_1) {
if ((value & SPECIAL_MASK_2) == SPECIAL_MASK_2) {
...
} else {
...
}
} else {
if ((value & SPECIAL_MASK_3) == SPECIAL_MASK_3) {
...
} else {
...
}
}
如果你有32个状态,每个映射到一个位,每次调用只能设置一个位 - 最简单的情况 - “串行”序列将是一个接一个的32个检查之一
if ((mask & 0x00000001) == 0x00000001) {
} else if ((mask & 0x00000002) == 0x00000002) {
}
...
并且第一个简单的优化将首先对最频繁的事件进行检查。假设设置了第三位中的三个中的一个;你先检查第七位。
这样你最终只能在33%的时间内完成一次检查;然后可能有两次检查另外20%的时间,......,最后平均,你可能会运行七次检查。
另一种可能性是
if (mask & 0x0000FFFF) {
// The bit is in the LSW
if (mask & 0x0000FF00) {
// MSB of LSW
if (mask & 0x0000F000) {
...
} else {
}
}
} else {
}
这将每次完成五次检查。然而,在那时,关于CPU架构,分支预测等的考虑可能胜过您可能尝试的任何优化。
除非您有非常复杂的设置或其他约束(例如嵌入式设备),否则我担心分析,构建,调试和维护“优化”与“暴力”的成本检查可能不仅仅是平衡你可以挤出前者的任何优势。
答案 1 :(得分:2)
为了检查掩码的多个位,我使用循环。如果你正在使用一个像样的编译器,它应该相当优化代码。除非您遇到严重的性能问题,否则不值得手动优化,因为我所知道的所有CPU都在单个指令中实现逻辑位测试或逐位AND操作。所以你有两个指令:每个位的逻辑指令和CPU分支条件指令。没有大量的代码可以运行 - 据我所知 - 是不可能的。 (请注意,由于mask
是32位宽,如果您在16位核心CPU上运行,则会有更多指令来测试这两半。)
void processEvents(uint32_t events)
{
uint32_t bitToTest;
// Check each bit in turn
for(bitToTest = 1; bitToTest < events; bitToTest << 1)
{
// Check which bit is set. If none then the default case is used.
switch(bitToTest & events)
{
case IN_ACCESS:
// Handle the IN_ACCESS event flag here.
break;
case IN_ATTRIB:
// Handle the IN_ATTRIB event flag here.
break;
// Et cetera...
default:
// No flag was set, so do nothing.
break;
}
}
}
答案 2 :(得分:2)
如果只设置了一个位,并且您的代码不必是可移植的,则可以使用提供设置位位置的内在函数,然后在switch语句中使用结果。 对于gcc,例如是
__builtin_ffs
答案 3 :(得分:1)
如果需要检查每个位掩码,除了明确检查之外别无他法。但是,如果已知特定的位掩码,则可以进行逐位检查,从而有效地导致在每一步中排除一半可能的位掩码。