Project

General

Profile

Feature #22463 » crt_funcs_bench.c

watson1978 (Shizuo Fujita), 10/22/2026 04:24 AM

 
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#ifdef _WIN32
#include <windows.h>
#else
#include <time.h>
#endif

typedef void *(*cpy_t)(void *, const void *, size_t);
typedef void *(*set_t)(void *, int, size_t);
typedef int (*cmp_t)(const void *, const void *, size_t);
typedef void *(*chr_t)(const void *, int, size_t);
typedef size_t (*len_t)(const char *);
typedef size_t (*nlen_t)(const char *, size_t);
typedef char *(*schr_t)(const char *, int);
typedef char *(*sstr_t)(const char *, const char *);
typedef int (*scmp_t)(const char *, const char *);
typedef int (*sncmp_t)(const char *, const char *, size_t);
typedef size_t (*wlen_t)(const wchar_t *);

enum kind { CPY, SET, CMP, CHR, LEN, NLEN, SCHR, SRCHR, SSTR, SCMP, SNCMP, WLEN };
struct fn { const char *name; enum kind kind; };
static const struct fn fns[] = {
{"memcpy", CPY}, {"memmove", CPY}, {"memset", SET}, {"memcmp", CMP}, {"memchr", CHR},
{"strlen", LEN}, {"strnlen", NLEN}, {"strchr", SCHR}, {"strrchr", SRCHR}, {"strstr", SSTR},
{"strcmp", SCMP}, {"strncmp", SNCMP}, {"wcslen", WLEN},
};
#define NFNS (sizeof(fns) / sizeof(fns[0]))

static double now(void) {
#ifdef _WIN32
LARGE_INTEGER f, t;
QueryPerformanceFrequency(&f);
QueryPerformanceCounter(&t);
return (double)t.QuadPart / f.QuadPart;
#else
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec + ts.tv_nsec / 1e9;
#endif
}

#define BARRIER(p) __asm__ volatile("" : : "r"(p) : "memory")

static unsigned char *A, *B;
static wchar_t *W;

/* returns GB/s, or -1 on a wrong result */
static double bench(enum kind k, void *f, size_t n) {
long iters = (long)((256ULL << 20) / n);
size_t bad = 0;
/* setup: n bytes of content; strings end with NUL at n-1 */
memset(A, 'a', n);
memset(B, 'a', n);
A[n - 2] = '\n';
A[n - 1] = 0;
B[n - 2] = '\n';
B[n - 1] = 0;
if (k == SRCHR) A[0] = 'z';
if (k == SSTR) { A[n - 4] = 'x'; A[n - 3] = 'y'; A[n - 2] = 'z'; }
if (k == CHR) { A[n - 1] = '\n'; A[n - 2] = 'a'; }
for (size_t i = 0; i < n / sizeof(wchar_t); i++) W[i] = L'a';
W[n / sizeof(wchar_t) - 1] = 0;
double t0 = now();
for (long i = 0; i < iters; i++) {
BARRIER(A);
BARRIER(B);
switch (k) {
case CPY: bad += ((cpy_t)f)(B, A, n) != B; break;
case SET: bad += ((set_t)f)(B, 'x', n) != B; break;
case CMP: bad += ((cmp_t)f)(A, B, n) != 0; break;
case CHR: bad += (unsigned char *)((chr_t)f)(A, '\n', n) != A + n - 1; break;
case LEN: bad += ((len_t)f)((char *)A) != n - 1; break;
case NLEN: bad += ((nlen_t)f)((char *)A, n) != n - 1; break;
case SCHR: bad += ((schr_t)f)((char *)A, '\n') != (char *)A + n - 2; break;
case SRCHR: bad += ((schr_t)f)((char *)A, 'z') != (char *)A; break;
case SSTR: bad += ((sstr_t)f)((char *)A, "xyz") != (char *)A + n - 4; break;
case SCMP: bad += ((scmp_t)f)((char *)A, (char *)B) != 0; break;
case SNCMP: bad += ((sncmp_t)f)((char *)A, (char *)B, n) != 0; break;
case WLEN: bad += ((wlen_t)f)(W) != n / sizeof(wchar_t) - 1; break;
}
}
double t = now() - t0;
if (bad) return -1;
return (double)n * iters / t / 1e9;
}

int main(void) {
size_t sizes[] = {64, 1040, 65536, 1 << 20};
A = malloc(1 << 20);
B = malloc(1 << 20);
W = malloc(1 << 20);
#ifdef _WIN32
const char *libs[] = {"ucrtbase.dll", "msvcrt.dll", "ntdll.dll", "vcruntime140.dll"};
int nlibs = 4;
#else
const char *libs[] = {"glibc"};
int nlibs = 1;
void *glibc[] = {(void *)memcpy, (void *)memmove, (void *)memset, (void *)memcmp, (void *)memchr,
(void *)strlen, (void *)strnlen, (void *)strchr, (void *)strrchr, (void *)strstr,
(void *)strcmp, (void *)strncmp, (void *)wcslen};
#endif
printf("%-9s %-17s %10s %10s %10s %10s (GB/s)\n", "func", "library", "64 B", "1040 B", "64 KB", "1 MB");
for (size_t i = 0; i < NFNS; i++) {
for (int l = 0; l < nlibs; l++) {
#ifdef _WIN32
HMODULE h = LoadLibraryA(libs[l]);
void *f = h ? (void *)GetProcAddress(h, fns[i].name) : NULL;
#else
void *f = glibc[i];
#endif
printf("%-9s %-17s", fns[i].name, libs[l]);
if (!f) { printf(" (not exported)\n"); continue; }
for (int s = 0; s < 4; s++) {
double g = bench(fns[i].kind, f, sizes[s]);
if (g < 0) printf(" %10s", "WRONG");
else printf(" %10.1f", g);
}
printf("\n");
}
}
return 0;
}
(5-5/5)