-
-
Save bnoordhuis/3b7b6a372e643041c79d to your computer and use it in GitHub Desktop.
tcp multi-accept benchmark
This file contains 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
/accept-server | |
/accept-client | |
*.o |
This file contains 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 "sampler.h" | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/un.h> | |
#include <sys/wait.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <unistd.h> | |
#include <time.h> | |
static void child(void) | |
{ | |
struct sampler sampler = SAMPLER_INIT(1000); | |
struct sockaddr_in sa = { | |
.sin_family = AF_INET, | |
.sin_port = htons(42424), | |
.sin_addr = htonl(INADDR_LOOPBACK), | |
}; | |
for (;;) { | |
sampler_start(&sampler); | |
{ | |
int fd = socket(AF_INET, SOCK_STREAM, 0); | |
if (fd == -1) { | |
perror("socket"); | |
exit(1); | |
} | |
if (connect(fd, (const struct sockaddr *) &sa, sizeof(sa))) { | |
perror("connect"); | |
exit(1); | |
} | |
struct linger linger = { .l_onoff = 1, .l_linger = 1 }; | |
setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); | |
close(fd); | |
} | |
sampler_stop(&sampler); | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
int nforks; | |
int i; | |
nforks = argc > 1 ? atoi(argv[1]) : 0; | |
if (nforks == 0) | |
nforks = 2; | |
for (i = 0; i < nforks; i++) { | |
pid_t pid = fork(); | |
if (pid == -1) | |
perror("fork"); | |
if (pid == 0) | |
child(); | |
} | |
for (i = 0; i < nforks; i++) { | |
int status; | |
wait(&status); | |
} | |
return 0; | |
} |
This file contains 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 "sampler.h" | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <sys/un.h> | |
#include <sys/wait.h> | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <unistd.h> | |
#include <time.h> | |
#include <poll.h> | |
static void child(int fd, int backoff) | |
{ | |
struct sampler sampler = SAMPLER_INIT(1000); | |
for (;;) { | |
struct pollfd pfd = { .fd = fd, .events = POLLIN }; | |
if (poll(&pfd, 1, -1) == -1) { | |
perror("poll"); | |
continue; | |
} | |
sampler_start(&sampler); | |
{ | |
int peerfd = accept(fd, NULL, NULL); | |
if (peerfd == -1) | |
perror("accept"); | |
else { | |
struct linger linger = { .l_onoff = 1, .l_linger = 1 }; | |
setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); | |
close(peerfd); | |
} | |
if (backoff) { | |
struct timespec timeout = { 0, 1 }; | |
nanosleep(&timeout, NULL); | |
} | |
} | |
sampler_stop(&sampler); | |
} | |
} | |
int main(int argc, char **argv) | |
{ | |
int i; | |
int nforks = argc > 1 ? atoi(argv[1]) : 0; | |
if (nforks == 0) | |
nforks = 2; | |
int backoff = argc > 2 ? atoi(argv[2]) : 0; | |
int fd = socket(AF_INET, SOCK_STREAM, 0); | |
if (fd == -1) { | |
perror("socket"); | |
exit(1); | |
} | |
int on = 1; | |
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); | |
struct sockaddr_in sa = { | |
.sin_family = AF_INET, | |
.sin_port = htons(42424), | |
.sin_addr = htonl(INADDR_LOOPBACK), | |
}; | |
if (bind(fd, (const struct sockaddr *) &sa, sizeof(sa))) { | |
perror("bind"); | |
exit(1); | |
} | |
if (listen(fd, 1024)) { | |
perror("listen"); | |
exit(1); | |
} | |
for (i = 0; i < nforks; i++) { | |
pid_t pid = fork(); | |
if (pid == -1) | |
perror("fork"); | |
if (pid == 0) | |
child(fd, backoff); | |
} | |
close(fd); | |
for (i = 0; i < nforks; i++) { | |
int status; | |
wait(&status); | |
} | |
return 0; | |
} |
This file contains 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
override CFLAGS += -D_GNU_SOURCE | |
override LDFLAGS += -lrt | |
.PHONY: all clean | |
all: accept-server accept-client | |
clean: | |
$(RM) accept-server accept-client *.o | |
accept-client: accept-client.o | |
$(CC) $^ -o $@ $(LDFLAGS) | |
accept-server: accept-server.o | |
$(CC) $^ -o $@ $(LDFLAGS) | |
accept-client.o: accept-client.c sampler.h | |
accept-server.o: accept-server.c sampler.h |
This file contains 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
#ifndef _SAMPLER_H_ | |
#define _SAMPLER_H_ | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <sched.h> | |
#include <time.h> | |
#define SAMPLER_INIT(size_) { .start = now(), .size = (size_), .min = (u64) -1 } | |
typedef uint64_t u64; | |
struct sampler | |
{ | |
unsigned size; | |
unsigned count; | |
u64 start; | |
u64 avg; | |
u64 min; | |
u64 max; | |
u64 ts; | |
}; | |
static u64 now(void) | |
{ | |
struct timespec ts; | |
clock_gettime(CLOCK_MONOTONIC, &ts); | |
return ts.tv_sec * (u64) 1e9 + ts.tv_nsec; | |
} | |
static void sampler_start(struct sampler *s) | |
{ | |
s->ts = now(); | |
} | |
static void sampler_stop(struct sampler *s) | |
{ | |
u64 ts = now() - s->ts; | |
u64 avg = s->avg * s->count; | |
s->count += 1; | |
s->avg = (avg + ts) / s->count; | |
if (s->count >= s->size) { | |
u64 total = now() - s->start; | |
printf("pid=%d cpu=%d avg=%.1fus min=%.1fus max=%.1fus\ttotal=%.1fms\n", | |
getpid(), | |
sched_getcpu(), | |
s->avg / 1e3, | |
s->min / 1e3, | |
s->max / 1e3, | |
total / 1e6); | |
struct sampler blank = SAMPLER_INIT(s->size); | |
*s = blank; | |
} else { | |
if (s->min > ts) s->min = ts; | |
if (s->max < ts) s->max = ts; | |
} | |
} | |
#endif /* _SAMPLER_H_ */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment