Created
November 19, 2015 21:55
-
-
Save amosr/8f899bf71fa100261e40 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <string.h> | |
#include <time.h> | |
typedef long long int uint64_t; | |
int cmp8_mask (const char *as, const char* bs, uint64_t len) | |
{ | |
uint64_t rem = len; | |
while (rem > 8) { | |
uint64_t a = *(uint64_t*)as; | |
uint64_t b = *(uint64_t*)bs; | |
if (a != b) { | |
return 1; | |
} | |
rem -= 8; | |
as += 8; | |
bs += 8; | |
} | |
uint64_t mask = 0xFF00000000000000; | |
mask = ~(mask >> ((7-rem)*8)); | |
uint64_t a = *(uint64_t*)as; | |
uint64_t b = *(uint64_t*)bs; | |
if ((a & mask) != (b & mask)) { | |
return 1; | |
} | |
return 0; | |
} | |
#define BENCH 1 | |
#if BENCH | |
int cmp_both (const char *as, const char* bs, uint64_t len) | |
{ | |
int c8 = cmp8_mask (as,bs,len); | |
int mm = memcmp (as,bs,len); | |
if ((c8 == 0) != (mm == 0)) { | |
printf ("NOT OK:\n"); | |
for (uint64_t i = 0; i != len; ++i) { | |
printf("%c", as[i]); | |
} | |
printf("\n"); | |
for (uint64_t i = 0; i != len; ++i) { | |
printf("%c", bs[i]); | |
} | |
printf("\n"); | |
printf("Len: %lld\n", len); | |
} | |
return mm; | |
} | |
const char* | |
test_str = | |
"big bobby went down to the cemetery he was feeling pretty cool but do you want to know what" | |
" big bobby did when he got there? he had a party and invited all his friends!" | |
" << I do declare, boy, that this is the greatest party you have ever thrown >> " | |
" and so the mayor did declare." | |
" when big bobby heard the mayor declare this, he swooned and palpitated in embarrassment." | |
" nobody had ever won the mayor's affection so quickly!" | |
" << have you been drinking, mister mayor? >> " | |
" asked a well-meaning busy-body with nothing better to do. " | |
" << why yes, I have - it helps with my rheumatism. >> " | |
/* stuff at the end to read past */ | |
"**************************************************" | |
"**************************************************"; | |
const uint64_t TEST_STR_SZ = sizeof(test_str) - 100; | |
#define NUM_ITERATIONS 100000000 | |
#define TEST_WITH(fun) \ | |
int test_##fun() \ | |
{ \ | |
uint64_t off1 = 0; \ | |
uint64_t off2 = 13; \ | |
uint64_t len = 1; \ | |
uint64_t ret = 0; \ | |
\ | |
for (uint64_t num = 0; num != NUM_ITERATIONS; ++num) { \ | |
if (fun (test_str+off1, test_str+off2, len) == 0) ++ret; \ | |
\ | |
off1 = (off1 + 31) % TEST_STR_SZ; \ | |
off2 = (off2 + 21) % TEST_STR_SZ; \ | |
len = (len + 12) % TEST_STR_SZ; \ | |
} \ | |
\ | |
return ret; \ | |
} | |
TEST_WITH(memcmp) | |
TEST_WITH(cmp8_mask) | |
TEST_WITH(cmp_both) | |
int main() | |
{ | |
clock_t start, end; | |
int ret; | |
printf("Memcmp start\n"); | |
start = clock(); | |
ret = test_memcmp(); | |
end = clock(); | |
printf("Memcmp end: %f\n", (double)(end - start) / CLOCKS_PER_SEC); | |
printf("Num eq: %d\n", ret); | |
printf("Cmp8 start\n"); | |
start = clock(); | |
ret = test_cmp8_mask(); | |
end = clock(); | |
printf("Cmp8 end: %f\n", (double)(end - start) / CLOCKS_PER_SEC); | |
printf("Num eq: %d\n", ret); | |
printf("Both start\n"); | |
start = clock(); | |
ret = test_cmp_both(); | |
end = clock(); | |
printf("Both end: %f\n", (double)(end - start) / CLOCKS_PER_SEC); | |
printf("Num eq: %d\n", ret); | |
} | |
#endif | |
#define RUN 0 | |
#if RUN | |
int cmp8_simple (char *as, char* bs, uint64_t len) | |
{ | |
uint64_t rem = len; | |
while (rem > 8) { | |
uint64_t a = *(uint64_t*)as; | |
uint64_t b = *(uint64_t*)bs; | |
uint64_t diff = a - b; | |
if (diff != 0) { | |
return 1; | |
} | |
rem -= 8; | |
as += 8; | |
bs += 8; | |
} | |
while (rem > 0) { | |
char a = *as; | |
char b = *bs; | |
char diff = a - b; | |
if (diff != 0) { | |
return 1; | |
} | |
rem -= 1; | |
as += 1; | |
bs += 1; | |
} | |
return 0; | |
} | |
void test(char* as, char* bs, int len) | |
{ | |
uint64_t ret = cmp8_mask(as, bs, len); | |
uint64_t cmp = memcmp(as,bs,len); | |
if ((ret == 0) == (cmp == 0)) | |
printf("%s, %s: good\n", as, bs); | |
else | |
printf("%s /= %s is no good %lld %lld\n", as, bs, ret, cmp); | |
} | |
int main() | |
{ | |
test("true|", "true|", 5); | |
test("trueBANG|", "trueBANG|", 9); | |
test("trueBANG|", "trueCANG|", 9); | |
test("trueBANG|", "trueBANG)", 9); | |
test("trueBANG|", "trueBANG)", 9); | |
test("true|", "trueBANG)", 9); | |
test("trueBANG????|", "trueBANGBONGBING)", 17); | |
test("trueBANGBONGBING)", "trueBANGBONGBING)", 17); | |
printf("OK\n"); | |
} | |
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
It's a bit faster than memcmp: | |
amos@amosr sea-tests $ gcc cmp8.c -O3 -march=native && ./a.out | |
Memcmp start | |
Memcmp end: 0.557312 | |
... | |
Cmp8 start | |
Cmp8 end: 0.433077 | |
... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment