Last active
February 4, 2025 23:49
-
-
Save izabera/579ca3ec9e3e00365d0d25584c67bcb7 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 <arpa/inet.h> | |
#include <errno.h> | |
#include <netinet/in.h> | |
#include <pty.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/mman.h> | |
#include <sys/socket.h> | |
#include <sys/wait.h> | |
#include <time.h> | |
#include <unistd.h> | |
int errfd; | |
#define err(x) do { dprintf(errfd, x " error: %m\n"); return -1; } while (0) | |
// basically what forkpty does after openpty+loginpty | |
int dosetup(int *fd, int fds[2]) { | |
*fd = fds[0]; | |
int pid = fork(); | |
if (pid == -1) | |
err("fork"); | |
if (pid == 0) { | |
dup2(fds[1], 1); | |
close(fds[0]); | |
close(fds[1]); | |
} | |
else | |
close(fds[1]); | |
return pid; | |
} | |
int with_uds(int *fd) { | |
printf("uds: "); | |
fflush(stdout); | |
int fds[2]; | |
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) | |
err("socketpair"); | |
return dosetup(fd, fds); | |
} | |
int with_inet(int *fd) { | |
printf("inet: "); | |
fflush(stdout); | |
int sock = socket(AF_INET, SOCK_STREAM, 0); | |
if (sock < 0) | |
err("socket"); | |
struct sockaddr_in addr = { }; | |
addr.sin_family = AF_INET; | |
unsigned len = sizeof(addr); | |
void *addrp = &addr; | |
if (bind(sock, addrp, len) == -1) | |
err("bind"); | |
getsockname(sock, addrp, &len); | |
listen(sock, 1); | |
int pid = fork(); | |
if (pid == -1) | |
err("fork"); | |
if (pid == 0) { | |
close(sock); | |
sock = socket(AF_INET, SOCK_STREAM, 0); | |
if (connect(sock, addrp, len) == -1) | |
err("connect"); | |
shutdown(sock, SHUT_RD); | |
dup2(sock, 1); | |
close(sock); | |
return pid; | |
} | |
int newfd = accept(sock, NULL, NULL); | |
if (newfd == -1) | |
err("accept"); | |
shutdown(newfd, SHUT_WR); | |
close(sock); | |
*fd = newfd; | |
return pid; | |
} | |
int with_pipe(int *fd) { | |
printf("pipe: "); | |
fflush(stdout); | |
int fds[2]; | |
if (pipe(fds) < 0) | |
err("pipe"); | |
return dosetup(fd, fds); | |
} | |
int with_pty(int *fd) { | |
printf("pty: "); | |
fflush(stdout); | |
struct termios os = {}; | |
cfmakeraw(&os); // doesn't make much of a difference | |
// cfsetspeed(&os, B4000000); // do ptys support this at all...? | |
struct winsize win = { 123, 456, 123, 456 }; | |
int pid = forkpty(fd, NULL, &os, &win); | |
if (pid == -1) | |
err("forkpty"); | |
return pid; | |
} | |
#define limit (4l << 30) | |
#define bufsiz (1l << 20) | |
static _Alignas(4096) char wbuf[2][bufsiz]; | |
static _Alignas(4096) char rbuf[bufsiz]; | |
static _Alignas(4096) unsigned histogram[64]; | |
int main() { | |
errfd = dup(2); | |
printf("total i/o: %zu bytes\n", limit); | |
printf("chunk size: %zu bytes\n", bufsiz); | |
memset(wbuf[0], 'x', bufsiz); | |
memset(wbuf[1], 'y', bufsiz); | |
mlock(wbuf, sizeof wbuf); | |
mlock(rbuf, sizeof rbuf); | |
mlock(histogram, sizeof histogram); | |
// functions return a pid, and a readable fd in the out param | |
int (*funcs[])(int*) = { | |
with_pipe, | |
with_uds, | |
with_inet, | |
with_pty, | |
}; | |
for (size_t f = 0; f < sizeof funcs/sizeof*funcs; f++) { | |
memset(histogram, 0, sizeof histogram); | |
struct timespec t0, t1; | |
clock_gettime(CLOCK_MONOTONIC, &t0); | |
int fd; | |
int pid = funcs[f](&fd); | |
if (pid == -1) | |
continue; | |
if (pid == 0) { | |
for (int i = 0; i < limit/bufsiz; i++) { | |
if (write(1, wbuf[i%2], bufsiz) < bufsiz) | |
err("write"); | |
} | |
return 0; | |
} | |
long l, total = 0, count = 0; | |
for (; (l = read(fd, rbuf, bufsiz)) > 0; count++) { | |
total += l; | |
// basic log scale histogram | |
histogram[63-__builtin_clzl(l)]++; | |
} | |
clock_gettime(CLOCK_MONOTONIC, &t1); | |
if (total < limit || (l < 0 && errno != EIO)) | |
err("read"); | |
close(fd); | |
if (waitpid(pid, NULL, 0) == -1) | |
err("read"); | |
#define tofloat(t) (t.tv_sec + t.tv_nsec/1000000000.) | |
float tdiff = tofloat(t1) - tofloat(t0); | |
printf("%6.3fs %10.3fmb/s - %6ld reads %10.3f bytes avg\n", | |
tdiff, limit/tdiff/1000000., | |
count, total*1./count); | |
int lo = 0, hi = 63; | |
while (!histogram[lo]) lo++; | |
while (!histogram[hi]) hi--; | |
char *hist[] = { | |
" ", | |
"▏", | |
"▎", | |
"▍", | |
"▌", | |
"▋", | |
"▊", | |
"▉", | |
"█", | |
}; | |
float width = 100.; | |
for (int i = lo; i <= hi; i++) { | |
printf(" %7ld - %7ld bytes: %10u reads ", 1L << i, (1L << (i+1)) - 1, histogram[i]); | |
int full = histogram[i]*width*8/count; | |
int rest = full%8; | |
full = full/8; | |
for (int j = 0; j < full; j++) | |
printf("%s", hist[8]); | |
printf("%s %.3f%%\n", hist[rest], histogram[i]*width/count); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.