Skip to content

Instantly share code, notes, and snippets.

@izabera
Last active February 4, 2025 23:49
Show Gist options
  • Save izabera/579ca3ec9e3e00365d0d25584c67bcb7 to your computer and use it in GitHub Desktop.
Save izabera/579ca3ec9e3e00365d0d25584c67bcb7 to your computer and use it in GitHub Desktop.
#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);
}
}
}
@izabera
Copy link
Author

izabera commented Feb 4, 2025

$ ./a.out 
total i/o:  4294967296 bytes
chunk size: 1048576 bytes
pipe:  0.886s   4849.980mb/s -  65536 reads  65536.000 bytes avg
uds:   0.285s  15091.187mb/s -  58376 reads  73574.197 bytes avg
inet:  0.634s   6775.562mb/s -  69274 reads  61999.701 bytes avg
pty:   7.141s    601.470mb/s - 433259 reads   9913.163 bytes avg

@izabera
Copy link
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