Files
strans/bench/main.c
Hojun-Cho bdf05e3c4a str, bench: three checks that guard nothing
sinit sets s->n = 0 as its first statement and no failure path restores
it, so stail's sclear after a failed sinit could never change anything;
say so in sinit's comment instead, where the contract belongs.  bench
compared a uintmax_t against UINT64_MAX and a size_t against UINT64_MAX,
both constant on any host this builds for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 16:14:16 +09:00

184 lines
2.9 KiB
C

#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include "ipc.h"
typedef struct Key Key;
struct Key {
int k;
int mod;
};
static Key *keys;
static size_t nkeys;
static int fd;
static void
die(char *msg)
{
perror(msg);
exit(1);
}
static void
addkey(int k, int mod)
{
static size_t cap;
Key *p;
if(nkeys >= cap){
if(cap > SIZE_MAX / 2 / sizeof(Key)){
fprintf(stderr, "too many keys\n");
exit(1);
}
cap = cap ? cap * 2 : 256;
p = realloc(keys, cap * sizeof(Key));
if(!p)
die("realloc");
keys = p;
}
keys[nkeys].k = k;
keys[nkeys].mod = mod;
nkeys++;
}
static void
loadkeys(char *file)
{
FILE *f;
int c;
f = fopen(file, "r");
if(!f)
die(file);
while((c = fgetc(f)) != EOF){
if(c == '\n' || c == '\r')
continue;
if(c != '^'){
addkey(c, 0);
continue;
}
c = fgetc(f);
if(c == EOF)
break;
switch(c){
case 'B':
addkey(Kback, 0);
break;
case 'R':
addkey(Kret, 0);
break;
case 'E':
addkey(Kesc, 0);
break;
default:
addkey(c, Mctrl);
break;
}
}
fclose(f);
if(nkeys == 0){
fprintf(stderr, "%s: no keys\n", file);
exit(1);
}
}
static uint64_t
iterations(char *s)
{
uintmax_t n;
char *end;
if(*s == '\0' || *s == '-')
goto Bad;
errno = 0;
n = strtoumax(s, &end, 10);
if(errno != 0 || *end != '\0' || n == 0)
goto Bad;
return n;
Bad:
fprintf(stderr, "invalid iteration count: %s\n", s);
exit(1);
}
static void
dial(void)
{
fd = ipcconnect();
if(fd < 0)
die("connect");
}
static void
sendkey(int key, int mod)
{
unsigned char req[Ipcreqsz];
ipcpackreq(req, 0, mod, key);
if(ipcsend(fd, req, sizeof req) < 0)
die("write");
}
static int
readresp(void)
{
char commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
Ipcresp resp;
return ipcreadresp(fd, 0, commit, preedit, &resp);
}
static double
now(void)
{
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec + ts.tv_nsec * 1e-9;
}
int
main(int argc, char **argv)
{
size_t j;
uint64_t i, niter, total;
double t0, t1, dt;
if(argc != 2 && argc != 3){
fprintf(stderr, "usage: bench file [niter]\n");
exit(1);
}
loadkeys(argv[1]);
niter = argc == 3 ? iterations(argv[2]) : 1000;
if(niter > UINT64_MAX / nkeys){
fprintf(stderr, "iteration count overflows key total\n");
exit(1);
}
total = niter * nkeys;
dial();
t0 = now();
for(i = 0; i < niter; i++)
for(j = 0; j < nkeys; j++){
sendkey(keys[j].k, keys[j].mod);
if(readresp() < 0){
fprintf(stderr, "failed at iter %" PRIu64 " key %zu\n", i, j);
exit(1);
}
}
t1 = now();
dt = t1 - t0;
printf("%" PRIu64 " iters x %zu keys = %" PRIu64 " keys\n",
niter, nkeys, total);
printf("%.3f ms total, %.3f us/key, %.3f us/iter\n",
dt * 1000, dt * 1e6 / total, dt * 1e6 / niter);
close(fd);
return 0;
}