Last active
July 25, 2024 01:20
-
-
Save N-R-K/ebf096448c0a7f3fdd8b93d280747550 to your computer and use it in GitHub Desktop.
benchmark code for https://nrk.neocities.org/articles/cpu-vs-common-sense.html
This file contains 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
/////////// | |
// compile with: | |
// $ gcc -O3 -march=native -fno-builtin -o /tmp/test bench.c glibc.c openbsd.c bespoke.c | |
// | |
// the various *_strlcpy functions are placed into their own | |
// file/translation-unit so that the compiler doesn't do any inlining or | |
// const-propogation, skewing the benchmark. | |
// for this reason LTO is also NOT enabled. | |
// | |
// -fno-builtin is so that bespoke_strlcpy doesn't get "optimized" down to | |
// strlen + memcpy call. | |
#include <time.h> | |
#include <stdio.h> | |
#include <string.h> | |
size_t glibc_strlcpy(char *dst, const char *src, size_t size); | |
size_t openbsd_strlcpy(char *dst, const char *src, size_t size); | |
size_t bespoke_strlcpy(char *dst, const char *src, size_t size); | |
typedef struct timespec T; | |
static T | |
now(void) | |
{ | |
T t; | |
clock_gettime(CLOCK_BOOTTIME, &t); | |
return t; | |
} | |
static void | |
timediff_print(T e, T s) | |
{ | |
long sec = e.tv_sec - s.tv_sec; | |
long ns = e.tv_nsec - s.tv_nsec; | |
if (ns < 0) { | |
--sec; | |
ns += 1000000000L; | |
} | |
long us = sec * 1000000L + ns / 1000L; | |
fprintf(stderr, "%8ldus\n", us); | |
} | |
int main(void) | |
{ | |
enum { N = 1<<9, ITER = 1024 }; | |
char src[N] = {0}; | |
memset(src, 1, N - 1); | |
T beg, end; | |
beg = now(); | |
for (int i = 0; i < ITER; ++i) { | |
char buf[N]; | |
char *p = buf; | |
__asm volatile ("" : "+r"(p)); | |
openbsd_strlcpy(p, src, N); | |
__asm volatile ("" : "+r"(p) :: "memory" ); | |
} | |
end = now(); | |
fprintf(stderr, "openbsd: "); | |
timediff_print(end, beg); | |
beg = now(); | |
for (int i = 0; i < ITER; ++i) { | |
char buf[N]; | |
char *p = buf; | |
__asm volatile ("" : "+r"(p)); | |
glibc_strlcpy(p, src, N); | |
__asm volatile ("" : "+r"(p) :: "memory" ); | |
} | |
end = now(); | |
fprintf(stderr, "glibc: "); | |
timediff_print(end, beg); | |
beg = now(); | |
for (int i = 0; i < ITER; ++i) { | |
char buf[N]; | |
char *p = buf; | |
__asm volatile ("" : "+r"(p)); | |
bespoke_strlcpy(p, src, N); | |
__asm volatile ("" : "+r"(p) :: "memory" ); | |
} | |
end = now(); | |
fprintf(stderr, "bespoke: "); | |
timediff_print(end, beg); | |
} |
This file contains 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 <stddef.h> | |
#include <string.h> | |
size_t | |
bespoke_strlcpy(char *dst, const char *src, size_t size) | |
{ | |
/* size_t len = strlen(src); */ | |
size_t len = 0; | |
for (; src[len] != '\0'; ++len) {} // strlen() | |
if (size > 0) { | |
size_t to_copy = len < size ? len : size - 1; | |
for (size_t i = 0; i < to_copy; ++i) // memcpy() | |
dst[i] = src[i]; | |
dst[to_copy] = '\0'; | |
} | |
return len; | |
} |
This file contains 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 <string.h> | |
size_t | |
glibc_strlcpy(char *__restrict dest, const char *__restrict src, size_t size) | |
{ | |
size_t src_length = strlen (src); | |
if (src_length >= size) | |
{ | |
if (size > 0) | |
{ | |
/* Copy the leading portion of the string. The last | |
character is subsequently overwritten with the NUL | |
terminator, but the destination size is usually a | |
multiple of a small power of two, so writing it twice | |
should be more efficient than copying an odd number of | |
bytes. */ | |
memcpy (dest, src, size); | |
dest[size - 1] = '\0'; | |
} | |
} | |
else | |
/* Copy the string and its terminating NUL character. */ | |
memcpy (dest, src, src_length + 1); | |
return src_length; | |
} |
This file contains 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 <stddef.h> | |
size_t | |
openbsd_strlcpy(char *dst, const char *src, size_t dsize) | |
{ | |
const char *osrc = src; | |
size_t nleft = dsize; | |
/* Copy as many bytes as will fit. */ | |
if (nleft != 0) { | |
while (--nleft != 0) { | |
if ((*dst++ = *src++) == '\0') | |
break; | |
} | |
} | |
/* Not enough room in dst, add NUL and traverse rest of src. */ | |
if (nleft == 0) { | |
if (dsize != 0) | |
*dst = '\0'; /* NUL-terminate dst */ | |
while (*src++) | |
; | |
} | |
return(src - osrc - 1); /* count does not include NUL */ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment