From ebf57dfc03c9f3bda5ee065d45c28feb6ebb1c97 Mon Sep 17 00:00:00 2001 From: Dirk Engling Date: Fri, 30 Oct 2026 03:25:35 +0100 Subject: Reduce syscalls and add helper to count them --- tests/syscount.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 tests/syscount.c (limited to 'tests/syscount.c') diff --git a/tests/syscount.c b/tests/syscount.c new file mode 100644 index 0000000..ec45c15 --- /dev/null +++ b/tests/syscount.c @@ -0,0 +1,144 @@ +/* Counts the system calls a run makes, by standing in front of libc. + + cc -O2 -shared -fPIC -o syscount.so tests/syscount.c -ldl + LD_PRELOAD=./syscount.so ./opentracker -f conf (DYLD_INSERT_LIBRARIES on macOS) + + The tally goes to stderr when the process exits. Reading the source tells + you which calls a path should make; this tells you which it does make, + which is not always the same thing. */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#endif + +#define COUNTER(name) static _Atomic long g_##name +#define BUMP(name) atomic_fetch_add_explicit(&g_##name, 1, memory_order_relaxed) +#define REPORT(name) fprintf(stderr, " %-14s %10ld\n", #name, atomic_load(&g_##name)) + +COUNTER(accept); +COUNTER(accept4); +COUNTER(read); +COUNTER(write); +COUNTER(close); +COUNTER(fcntl); +COUNTER(recvfrom); +COUNTER(sendto); +COUNTER(epoll_ctl); +COUNTER(epoll_wait); + +typedef int (*fn_accept)(int, struct sockaddr *, socklen_t *); +typedef int (*fn_accept4)(int, struct sockaddr *, socklen_t *, int); +typedef ssize_t (*fn_read)(int, void *, size_t); +typedef ssize_t (*fn_write)(int, const void *, size_t); +typedef int (*fn_close)(int); +typedef int (*fn_fcntl)(int, int, ...); +typedef ssize_t (*fn_recvfrom)(int, void *, size_t, int, struct sockaddr *, socklen_t *); +typedef ssize_t (*fn_sendto)(int, const void *, size_t, int, const struct sockaddr *, socklen_t); + +static fn_accept real_accept; +static fn_accept4 real_accept4; +static fn_read real_read; +static fn_write real_write; +static fn_close real_close; +static fn_fcntl real_fcntl; +static fn_recvfrom real_recvfrom; +static fn_sendto real_sendto; + +/* Resolving lazily keeps the library out of the way until something is + actually called, which matters because dlsym itself allocates */ +#define WRAP(name) \ + if (!real_##name) \ + real_##name = (fn_##name)dlsym(RTLD_NEXT, #name); \ + BUMP(name) + +int accept(int s, struct sockaddr *addr, socklen_t *len) { + WRAP(accept); + return real_accept(s, addr, len); +} + +#ifdef SOCK_NONBLOCK +int accept4(int s, struct sockaddr *addr, socklen_t *len, int flags) { + WRAP(accept4); + return real_accept4(s, addr, len, flags); +} +#endif + +ssize_t read(int fd, void *buf, size_t count) { + WRAP(read); + return real_read(fd, buf, count); +} + +ssize_t write(int fd, const void *buf, size_t count) { + WRAP(write); + return real_write(fd, buf, count); +} + +int close(int fd) { + WRAP(close); + return real_close(fd); +} + +int fcntl(int fd, int cmd, ...) { + va_list args; + long arg; + + va_start(args, cmd); + arg = va_arg(args, long); + va_end(args); + WRAP(fcntl); + return real_fcntl(fd, cmd, arg); +} + +ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { + WRAP(recvfrom); + return real_recvfrom(s, buf, len, flags, from, fromlen); +} + +ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen) { + WRAP(sendto); + return real_sendto(s, buf, len, flags, to, tolen); +} + +#ifdef __linux__ +typedef int (*fn_epoll_ctl)(int, int, int, struct epoll_event *); +typedef int (*fn_epoll_wait)(int, struct epoll_event *, int, int); +static fn_epoll_ctl real_epoll_ctl; +static fn_epoll_wait real_epoll_wait; + +int epoll_ctl(int ep, int op, int fd, struct epoll_event *ev) { + WRAP(epoll_ctl); + return real_epoll_ctl(ep, op, fd, ev); +} + +int epoll_wait(int ep, struct epoll_event *events, int max, int timeout) { + WRAP(epoll_wait); + return real_epoll_wait(ep, events, max, timeout); +} +#endif + +__attribute__((destructor)) static void report(void) { + fprintf(stderr, "\n system calls this run\n"); + REPORT(accept); +#ifdef SOCK_NONBLOCK + REPORT(accept4); +#endif + REPORT(read); + REPORT(write); + REPORT(close); + REPORT(fcntl); + REPORT(recvfrom); + REPORT(sendto); +#ifdef __linux__ + REPORT(epoll_ctl); + REPORT(epoll_wait); +#endif +} -- cgit v1.3