DF-2977 / bench.c
/* * DF-2977 - accf_http httpready filter re-parses the ENTIRE accumulated * request from byte 0 on every data arrival (sys/net/accf_http/accf_http.c * soparsehttpvers lines 237-278: on each upcall the loop restarts at * so->so_rcv.ssb_mb). A client that dribbles the request one byte per * segment (TCP_NODELAY) with exactly one space and no newline keeps the * filter in "readmore" state, so b buffered bytes cost O(b^2) byte-visits * plus b upcalls -- ALL on the netisr protocol thread, unauthenticated. * * bench <mode> <bytes> <conns> * mode 1: one-byte sends (quadratic) mode 0: single bulk send (linear) * Prints kern.cp_time deltas (user nice sys intr idle) + wall time. */ #include <sys/types.h> #include <sys/socket.h> #include <sys/sysctl.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <time.h> static void cp_time(long out[5]) { size_t len = sizeof(long) * 5; if (sysctlbyname("kern.cp_time", out, &len, NULL, 0) < 0) { perror("sysctl kern.cp_time"); exit(1); } } int main(int argc, char **argv) { int mode = argc > 1 ? atoi(argv[1]) : 1; int nbytes = argc > 2 ? atoi(argv[2]) : 8192; int conns = argc > 3 ? atoi(argv[3]) : 8; int port = argc > 4 ? atoi(argv[4]) : 19000; long a[5], b[5]; struct timespec t0, t1; char *req; int c, i, fd, one = 1; req = malloc(nbytes + 16); /* one space total, no newline: filter scans whole buffer, re-arms */ memcpy(req, "GET /", 5); for (i = 5; i < nbytes; i++) req[i] = 'a'; cp_time(a); clock_gettime(CLOCK_MONOTONIC, &t0); for (c = 0; c < conns; c++) { struct sockaddr_in sa; int off = 0; fd = socket(AF_INET, SOCK_STREAM, 0); memset(&sa, 0, sizeof(sa)); sa.sin_family = AF_INET; sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); sa.sin_port = htons(port); if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("connect"); return 1; } setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); if (mode) { for (off = 0; off < nbytes; off++) if (write(fd, req + off, 1) != 1) { perror("write"); return 1; } } else { if (write(fd, req, nbytes) != nbytes) { perror("write"); return 1; } } /* small delay so the last segments get processed before close */ usleep(5000); close(fd); } clock_gettime(CLOCK_MONOTONIC, &t1); cp_time(b); double wall = (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1e9; printf("mode=%s bytes=%d conns=%d wall=%.3fs\n", mode ? "byte-at-a-time" : "bulk", nbytes, conns, wall); printf("cp_time delta: user=%ld nice=%ld sys=%ld intr=%ld idle=%ld\n", b[0] - a[0], b[1] - a[1], b[2] - a[2], b[3] - a[3], b[4] - a[4]); printf("kernel-ticks (sys+intr) = %ld (100/sec)\n", (b[2] - a[2]) + (b[3] - a[3])); return 0; } |