Skip to content

Instantly share code, notes, and snippets.

@amosr
Created November 19, 2015 21:55
Show Gist options
  • Save amosr/8f899bf71fa100261e40 to your computer and use it in GitHub Desktop.
Save amosr/8f899bf71fa100261e40 to your computer and use it in GitHub Desktop.
#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
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