Skip to content

Instantly share code, notes, and snippets.

@bnoordhuis
Created December 8, 2012 15:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bnoordhuis/3b7b6a372e643041c79d to your computer and use it in GitHub Desktop.
Save bnoordhuis/3b7b6a372e643041c79d to your computer and use it in GitHub Desktop.
tcp multi-accept benchmark
/accept-server
/accept-client
*.o
#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;
}
#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;
}
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
#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