summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorantirez <antirez@gmail.com>2012-05-20 00:49:35 +0200
committerantirez <antirez@gmail.com>2012-05-24 15:24:31 +0200
commitd12a68d4158ba308b3e153158a0affa80c5fa9eb (patch)
treefa886fe0bb65f30df96d7b555f48aaced8c5bd83 /src
parent7ffa248c7cc53d1b84dfbad2149965efcd6a72f5 (diff)
downloadredis-d12a68d4158ba308b3e153158a0affa80c5fa9eb.tar.gz
popcount() optimization for speed.
We run the array by 32 bit words instead of processing it byte per byte. If the code is compiled using GCC __builtin_popcount() builtin function is used instead.
Diffstat (limited to 'src')
-rw-r--r--src/bitop.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/src/bitop.c b/src/bitop.c
index 2b26265d7..053db02b5 100644
--- a/src/bitop.c
+++ b/src/bitop.c
@@ -30,10 +30,26 @@ static int getBitOffsetFromArgument(redisClient *c, robj *o, size_t *offset) {
* work with a input string length up to 512 MB. */
long popcount(void *s, long count) {
long bits = 0;
- unsigned char *p = s;
+ unsigned char *p;
+ 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};
- /* We can finally count bits. */
+ /* Count bits four bytes at a time */
+ while(count>=4) {
+ uint32_t aux = *p4++;
+ count -= 4;
+#ifdef __GNUC__
+ /* Unsigned int is always >= 4 bytes if compiler is GCC */
+ bits += __builtin_popcount(aux);
+#else
+ bits += bitsinbyte[aux&0xff] +
+ bitsinbyte[(aux>>8)&0xff] +
+ bitsinbyte[(aux>>16)&0xff] +
+ bitsinbyte[(aux>>24)&0xff];
+#endif
+ }
+ /* Count the remaining bytes */
+ p = (unsigned char*)p4;
while(count--) bits += bitsinbyte[*p++];
return bits;
}