我在我的代码中使用了某种具有read_bit()
函数的BitStream。非常频繁地调用此函数(在单个流中超过十亿次)。这就是结构BitStream的样子:
typedef struct BitStream {
unsigned char* data;
unsigned int size;
unsigned int currentByte;
unsigned char buffer;
unsigned char bitsInBuffer;
} BitStream;
read_bit()
- 函数定义如下:
unsigned char bitstream_read_bit(BitStream* stream, unsigned long long bitPos) {
unsigned int byte = bitPos / 8;
unsigned char byteVal = stream->data[byte];
unsigned char mask = 128 >> (bitPos & 7);
if (mask & byteVal) {
return 1;
} else {
return 0;
}
}
现在,我通过反复试验发现行unsigned char mask = 128 >> (bitPos & 7);
非常慢。有什么方法可以加快检查一下吗?我已经尝试使用一个索引8种不同掩码的数组,但这并不快(我认为是由于内存访问)。
128 >> (bitPos & 7)
,而是使用了函数:
unsigned char bitstream_read_bit_2(BitStream* stream, const unsigned long long bitPos) {
unsigned int byte = (unsigned int) (bitPos / 8);
unsigned char byteVal = stream->data[byte];
unsigned char mod = bitPos & 7;
return (byteVal & (1 << mod)) >> mod;
}
我显然也改变了相应的写功能。
答案 0 :(得分:2)
明显的第一个改进是移动加载的值而不是掩码:
unsigned char bitstream_read_bit(BitStream* stream, unsigned long long bitPos) {
unsigned int byte = bitPos / 8;
unsigned char byteVal = stream->data[byte];
unsigned char maskVal = byteVal >> (bitPos & 7);
return maskVal & 1;
}
这消除了对条件(if
或!
或?:
)的需要。
如果您可以修改struct
,我建议您使用比字节更大的单位进行访问:
#include <stddef.h>
#include <limits.h>
#include <stdbool.h>
typedef struct WBitStream
{
size_t *data;
size_t size;
} WBitStream;
bool Wbitstream_read_bit(WBitStream* stream, size_t bitPos)
{
size_t location = bitPos / (sizeof(size_t)*CHAR_BIT);
size_t locval = stream->data[location];
size_t maskval = locval >> (bitPos & (sizeof(size_t)*CHAR_BIT-1));
return maskval & 1;
}
在某些处理器(特别是常见的x86)上,移位量的掩码是NOP,因为处理器的本机移位指令仅考虑移位量的低位。至少gcc知道这一点。
答案 1 :(得分:1)
我已经测试了与初始源代码相比的优化宏:
static unsigned char tMask[8] = { 128, 64, 32, 16, 8, 4, 2, 1 };
#define BITSTREAM_READ_BIT1(stream, bitPos) (((128 >> (bitPos & 7)) & stream->data[bitPos >> 3])!=0)
#define BITSTREAM_READ_BIT2(stream, bitPos) (((tMask[(bitPos & 7)]) & stream->data[bitPos >> 3])!=0)
通过数组中的掩码替换掩码计算并不会提高性能。 主要差距在功能和宏之间(在我的计算机上运行速度提高了6倍,通话时间为80.000.000)。
静态内联使用距离宏不远。
答案 2 :(得分:0)
以下是我最初优化代码的方式:
unsigned char bitstream_read_bit(BitStream* stream, unsigned long long bitPos)
{
return !!(stream->data[(bitPos / 8)] & (128 >> (bitPos % 8)));
}
但是函数调用开销本身可能比其中的位调整代码更多的指令。因此,如果你真的想进一步优化它,那么让我们利用内联并将其转换为宏:
#define bitstream_read_bit(stream, bitPos) (!!((stream)->data[((bitPos) / 8)] & (128 >> ((bitPos) % 8))))