mirror of
https://github.com/fluencelabs/redis
synced 2025-04-01 15:21:03 +00:00
BITCOUNT performance improved.
At Redis's default optimization level the command is now much faster, always using a constant-time bit manipualtion technique to count bits instead of GCC builtin popcount, and unrolling the loop. The current implementation performance is 1.5GB/s in a MBA 11" (1.8 Ghz i7) compiled with both GCC and clang. The algorithm used is described here: http://graphics.stanford.edu/~seander/bithacks.html
This commit is contained in:
parent
80f8028e3c
commit
7c34643f15
35
src/bitops.c
35
src/bitops.c
@ -34,19 +34,28 @@ long popcount(void *s, long count) {
|
|||||||
uint32_t *p4 = s;
|
uint32_t *p4 = s;
|
||||||
static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
|
static const unsigned char bitsinbyte[256] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8};
|
||||||
|
|
||||||
/* Count bits four bytes at a time */
|
/* Count bits 16 bytes at a time */
|
||||||
while(count>=4) {
|
while(count>=16) {
|
||||||
uint32_t aux = *p4++;
|
uint32_t aux1, aux2, aux3, aux4;
|
||||||
count -= 4;
|
|
||||||
#ifdef __GNUC__
|
aux1 = *p4++;
|
||||||
/* Unsigned int is always >= 4 bytes if compiler is GCC */
|
aux2 = *p4++;
|
||||||
bits += __builtin_popcount(aux);
|
aux3 = *p4++;
|
||||||
#else
|
aux4 = *p4++;
|
||||||
bits += bitsinbyte[aux&0xff] +
|
count -= 16;
|
||||||
bitsinbyte[(aux>>8)&0xff] +
|
|
||||||
bitsinbyte[(aux>>16)&0xff] +
|
aux1 = aux1 - ((aux1 >> 1) & 0x55555555);
|
||||||
bitsinbyte[(aux>>24)&0xff];
|
aux1 = (aux1 & 0x33333333) + ((aux1 >> 2) & 0x33333333);
|
||||||
#endif
|
aux2 = aux2 - ((aux2 >> 1) & 0x55555555);
|
||||||
|
aux2 = (aux2 & 0x33333333) + ((aux2 >> 2) & 0x33333333);
|
||||||
|
aux3 = aux3 - ((aux3 >> 1) & 0x55555555);
|
||||||
|
aux3 = (aux3 & 0x33333333) + ((aux3 >> 2) & 0x33333333);
|
||||||
|
aux4 = aux4 - ((aux4 >> 1) & 0x55555555);
|
||||||
|
aux4 = (aux4 & 0x33333333) + ((aux4 >> 2) & 0x33333333);
|
||||||
|
bits += ((((aux1 + (aux1 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
|
||||||
|
((((aux2 + (aux2 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
|
||||||
|
((((aux3 + (aux3 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24) +
|
||||||
|
((((aux4 + (aux4 >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24);
|
||||||
}
|
}
|
||||||
/* Count the remaining bytes */
|
/* Count the remaining bytes */
|
||||||
p = (unsigned char*)p4;
|
p = (unsigned char*)p4;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user