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); | |
} | |
} | |
} |
Author
izabera
commented
Feb 4, 2025
$ ./a.out
total i/o: 4294967296 bytes
chunk size: 1048576 bytes
pipe: 0.760s 5648.354mb/s - 65536 reads 65536.000 bytes avg
65536 - 131071 bytes: 65536 reads ████████████████████████████████████████████████████████████████████████████████████████████████████ 100.000%
uds: 0.268s 16045.615mb/s - 70194 reads 61187.100 bytes avg
16384 - 32767 bytes: 45 reads 0.064%
32768 - 65535 bytes: 45450 reads ████████████████████████████████████████████████████████████████▋ 64.749%
65536 - 131071 bytes: 19750 reads ████████████████████████████▏ 28.136%
131072 - 262143 bytes: 4528 reads ██████▍ 6.451%
262144 - 524287 bytes: 383 reads ▌ 0.546%
524288 - 1048575 bytes: 26 reads 0.037%
1048576 - 2097151 bytes: 12 reads 0.017%
inet: 0.639s 6724.734mb/s - 69462 reads 61831.898 bytes avg
512 - 1023 bytes: 4085 reads █████▉ 5.881%
1024 - 2047 bytes: 0 reads 0.000%
2048 - 4095 bytes: 0 reads 0.000%
4096 - 8191 bytes: 0 reads 0.000%
8192 - 16383 bytes: 0 reads 0.000%
16384 - 32767 bytes: 1 reads 0.001%
32768 - 65535 bytes: 65335 reads ██████████████████████████████████████████████████████████████████████████████████████████████ 94.059%
65536 - 131071 bytes: 23 reads 0.033%
131072 - 262143 bytes: 6 reads 0.009%
262144 - 524287 bytes: 3 reads 0.004%
524288 - 1048575 bytes: 5 reads 0.007%
1048576 - 2097151 bytes: 4 reads 0.006%
pty: 7.741s 554.866mb/s - 401039 reads 10709.600 bytes avg
1 - 1 bytes: 383 reads 0.096%
2 - 3 bytes: 13 reads 0.003%
4 - 7 bytes: 2 reads 0.000%
8 - 15 bytes: 1 reads 0.000%
16 - 31 bytes: 1 reads 0.000%
32 - 63 bytes: 0 reads 0.000%
64 - 127 bytes: 341 reads 0.085%
128 - 255 bytes: 521 reads ▏ 0.130%
256 - 511 bytes: 531 reads ▏ 0.132%
512 - 1023 bytes: 10755 reads ██▋ 2.682%
1024 - 2047 bytes: 412 reads 0.103%
2048 - 4095 bytes: 53535 reads █████████████▎ 13.349%
4096 - 8191 bytes: 81905 reads ████████████████████▍ 20.423%
8192 - 16383 bytes: 164507 reads █████████████████████████████████████████ 41.020%
16384 - 32767 bytes: 88132 reads █████████████████████▉ 21.976%
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment