diff --git a/mt_echod.c b/mt_echod.c new file mode 100644 index 0000000..4eb2d51 --- /dev/null +++ b/mt_echod.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int num_threads = 10000; +unsigned short port = 11111; +int listen_sock; + +void* start_thread(void* _unused) +{ + int fd, r, r2; + char buf[4096]; + + while (1) { + fd = accept(listen_sock, NULL, NULL); + if (fd == -1) + continue; + r2 = 1; + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &r2, sizeof(r2)); + assert(r == 0); + + while (1) { + r = read(fd, buf, sizeof(buf)); + if (r == 0 || (r == -1 && errno != EINTR)) { + break; + } + r2 = write(fd, buf, r); + assert(r == r2); + } + close(fd); + } + + return NULL; +} + +int main(int argc, char** argv) +{ + int ch, i, r, flag; + struct sockaddr_in listen_addr; + pthread_attr_t tattr; + + while ((ch = getopt(argc, argv, "c:p:")) != -1) { + switch (ch) { + case 'c': + assert(sscanf(optarg, "%d", &num_threads) == 1); + break; + case 'p': + assert(sscanf(optarg, "%hu", &port) == 1); + break; + default: + exit(1); + } + } + + listen_sock = socket(AF_INET, SOCK_STREAM, 0); + assert(listen_sock != -1); + flag = 1; + r = setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + assert(r == 0); + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = htons(port); + listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); + r = bind(listen_sock, (struct sockaddr*)&listen_addr, sizeof(listen_addr)); + assert(r == 0); + r = listen(listen_sock, SOMAXCONN); + assert(r == 0); + + pthread_attr_init(&tattr); + pthread_attr_setstacksize(&tattr, 65536); + for (i = 0; i < num_threads; ++i) { + pthread_t tid; + pthread_create(&tid, &tattr, start_thread, NULL); + } + + while (1) { + sleep(60); + } + + return 0; +} diff --git a/mt_httpd.c b/mt_httpd.c new file mode 100644 index 0000000..79b1781 --- /dev/null +++ b/mt_httpd.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "picohttpparser.h" + +int num_threads = 10000; +unsigned short port = 11111; +int listen_sock; + +void* start_thread(void* _unused) +{ + char buf[16384]; + const char* method, * path; + size_t method_len, path_len, num_headers; + int fd, minor_version, r, r2; + struct phr_header headers[128]; + + while (1) { + fd = accept(listen_sock, NULL, NULL); + if (fd == -1) + continue; + r2 = 1; + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &r2, sizeof(r2)); + assert(r == 0); + + while (1) { + r = read(fd, buf, sizeof(buf)); + if (r == 0 || (r == -1 && errno != EINTR)) { + break; + } + num_headers = sizeof(headers) / sizeof(headers[0]); + r = phr_parse_request(buf, r, &method, &method_len, &path, &path_len, + &minor_version, headers, &num_headers, 0); + assert(r > 0); +#define RES "HTTP\1.0 200 OK\r\n" \ + "Connection: keep-alive\r\n" \ + "Content-Length: 13\r\n" \ + "Content-Type: text/plain\r\n" \ + "\r\n" \ + "hello world!\n" + r = write(fd, RES, sizeof(RES) - 1); + assert(r == sizeof(RES) - 1); +#undef RES + } + close(fd); + } + + return NULL; +} + +int main(int argc, char** argv) +{ + int ch, i, r, flag; + struct sockaddr_in listen_addr; + pthread_attr_t tattr; + + while ((ch = getopt(argc, argv, "c:p:")) != -1) { + switch (ch) { + case 'c': + assert(sscanf(optarg, "%d", &num_threads) == 1); + break; + case 'p': + assert(sscanf(optarg, "%hu", &port) == 1); + break; + default: + exit(1); + } + } + + listen_sock = socket(AF_INET, SOCK_STREAM, 0); + assert(listen_sock != -1); + flag = 1; + r = setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + assert(r == 0); + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = htons(port); + listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); + r = bind(listen_sock, (struct sockaddr*)&listen_addr, sizeof(listen_addr)); + assert(r == 0); + r = listen(listen_sock, SOMAXCONN); + assert(r == 0); + + pthread_attr_init(&tattr); + pthread_attr_setstacksize(&tattr, 65536); + for (i = 0; i < num_threads; ++i) { + pthread_t tid; + pthread_create(&tid, &tattr, start_thread, NULL); + } + + while (1) { + sleep(60); + } + + return 0; +} diff --git a/picoev_echod.c b/picoev_echod.c new file mode 100644 index 0000000..214bddd --- /dev/null +++ b/picoev_echod.c @@ -0,0 +1,125 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "picoev.h" + +unsigned short port = 11111; +int listen_sock; + +static void setup_sock(int fd) +{ + int on = 1, r; + + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); + assert(r == 0); + r = fcntl(fd, F_SETFL, O_NONBLOCK); + assert(r == 0); +} + +static void read_cb(picoev_loop* loop, int fd, int revents, void* cb_arg) +{ + char buf[256]; + int r, r2; + + assert((revents & PICOEV_READ) != 0); + r = read(fd, buf, sizeof(buf)); + if (r == 0) { + goto CLOSE; + } else if (r == -1) { + if (errno == EINTR || errno == EAGAIN) { + return; + } + goto CLOSE; + } + r2 = write(fd, buf, r); + assert(r == r2); + return; + + CLOSE: + picoev_del(loop, fd); + close(fd); +} + +void* start_thread(void* _unused) +{ + int fd, r, r2; + char buf[4096]; + + while (1) { + fd = accept(listen_sock, NULL, NULL); + if (fd == -1) + continue; + r2 = 1; + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &r2, sizeof(r2)); + assert(r == 0); + + while (1) { + r = read(fd, buf, sizeof(buf)); + if (r == 0 || (r == -1 && errno != EINTR)) { + break; + } + r2 = write(fd, buf, r); + assert(r == r2); + } + close(fd); + } + + return NULL; +} + +static void accept_cb(picoev_loop* loop, int fd, int revents, void* cb_arg) +{ + int newfd; + assert((revents & PICOEV_READ) != 0); + if ((newfd = accept(fd, NULL, NULL)) != -1) { + setup_sock(newfd); + picoev_add(loop, newfd, PICOEV_READ, 0, read_cb, NULL); + } +} + +int main(int argc, char** argv) +{ + int ch, r, flag; + struct sockaddr_in listen_addr; + picoev_loop* loop; + + while ((ch = getopt(argc, argv, "p:")) != -1) { + switch (ch) { + case 'p': + assert(sscanf(optarg, "%hu", &port) == 1); + break; + default: + exit(1); + } + } + + listen_sock = socket(AF_INET, SOCK_STREAM, 0); + assert(listen_sock != -1); + flag = 1; + r = setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + assert(r == 0); + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = htons(port); + listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); + r = bind(listen_sock, (struct sockaddr*)&listen_addr, sizeof(listen_addr)); + assert(r == 0); + setup_sock(listen_sock); + r = listen(listen_sock, SOMAXCONN); + assert(r == 0); + + picoev_init(1048576 + 10); + loop = picoev_create_loop(60); + picoev_add(loop, listen_sock, PICOEV_READ, 0, accept_cb, NULL); + while (1) { + picoev_loop_once(loop, 10); + } + + return 0; +} diff --git a/picoev_httpd.c b/picoev_httpd.c new file mode 100644 index 0000000..b39999c --- /dev/null +++ b/picoev_httpd.c @@ -0,0 +1,144 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "picoev.h" +#include "picohttpparser.h" + +unsigned short port = 11111; +int listen_sock; + +static void setup_sock(int fd) +{ + int on = 1, r; + + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); + assert(r == 0); + r = fcntl(fd, F_SETFL, O_NONBLOCK); + assert(r == 0); +} + +static void read_cb(picoev_loop* loop, int fd, int revents, void* cb_arg) +{ + char buf[16384]; + const char* method, * path; + size_t method_len, path_len, num_headers; + int minor_version, r; + struct phr_header headers[128]; + + /* read request */ + assert((revents & PICOEV_READ) != 0); + r = read(fd, buf, sizeof(buf)); + if (r == 0) { + goto CLOSE; + } else if (r == -1) { + if (errno == EINTR || errno == EAGAIN) { + return; + } + goto CLOSE; + } + /* parse request, should arrive in one packat :-p */ + num_headers = sizeof(headers) / sizeof(headers[0]); + r = phr_parse_request(buf, r, &method, &method_len, &path, &path_len, + &minor_version, headers, &num_headers, 0); + assert(r > 0); + +#define RES "HTTP\1.0 200 OK\r\n" \ + "Connection: keep-alive\r\n" \ + "Content-Length: 13\r\n" \ + "Content-Type: text/plain\r\n" \ + "\r\n" \ + "hello world!\n" + r = write(fd, RES, sizeof(RES) - 1); + assert(r == sizeof(RES) - 1); +#undef RES + + return; + + CLOSE: + picoev_del(loop, fd); + close(fd); +} + +void* start_thread(void* _unused) +{ + int fd, r, r2; + char buf[4096]; + + while (1) { + fd = accept(listen_sock, NULL, NULL); + if (fd == -1) + continue; + r2 = 1; + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &r2, sizeof(r2)); + assert(r == 0); + + while (1) { + r = read(fd, buf, sizeof(buf)); + if (r == 0 || (r == -1 && errno != EINTR)) { + break; + } + r2 = write(fd, buf, r); + assert(r == r2); + } + close(fd); + } + + return NULL; +} + +static void accept_cb(picoev_loop* loop, int fd, int revents, void* cb_arg) +{ + int newfd; + assert((revents & PICOEV_READ) != 0); + if ((newfd = accept(fd, NULL, NULL)) != -1) { + setup_sock(newfd); + picoev_add(loop, newfd, PICOEV_READ, 0, read_cb, NULL); + } +} + +int main(int argc, char** argv) +{ + int ch, r, flag; + struct sockaddr_in listen_addr; + picoev_loop* loop; + + while ((ch = getopt(argc, argv, "p:")) != -1) { + switch (ch) { + case 'p': + assert(sscanf(optarg, "%hu", &port) == 1); + break; + default: + exit(1); + } + } + + listen_sock = socket(AF_INET, SOCK_STREAM, 0); + assert(listen_sock != -1); + flag = 1; + r = setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)); + assert(r == 0); + listen_addr.sin_family = AF_INET; + listen_addr.sin_port = htons(port); + listen_addr.sin_addr.s_addr = htonl(INADDR_ANY); + r = bind(listen_sock, (struct sockaddr*)&listen_addr, sizeof(listen_addr)); + assert(r == 0); + setup_sock(listen_sock); + r = listen(listen_sock, SOMAXCONN); + assert(r == 0); + + picoev_init(1048576 + 10); + loop = picoev_create_loop(60); + picoev_add(loop, listen_sock, PICOEV_READ, 0, accept_cb, NULL); + while (1) { + picoev_loop_once(loop, 10); + } + + return 0; +} diff --git a/testechoclient.c b/testechoclient.c new file mode 100644 index 0000000..62df42a --- /dev/null +++ b/testechoclient.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "picoev.h" + +static int active_connections = 1000; +static int num_connections = 10000; +static int num_requests = 1000000; +static int fix_clients = 0; +static struct in_addr host; +static unsigned short port = 11111; + +static int fds[1048576]; +static int next_fd_idx = 0; +static int num_responses; + +static void read_cb(picoev_loop* loop, int fd, int revents, void* cb_arg) +{ + char buf[6]; + int r; + + assert((revents & PICOEV_READ) != 0); + + r = read(fd, buf, sizeof(buf)); + assert(r == 6); + assert(memcmp(buf, "hello\n", 6) == 0); + ++num_responses; + + if (num_responses < num_requests) { + int wfd; + if (fix_clients) { + wfd = fd; + } else { + wfd = fds[next_fd_idx]; + next_fd_idx = (next_fd_idx + 1) % num_connections; + } + r = write(wfd, "hello\n", 6); + assert(r == 6); + } +} + +int main(int argc, char** argv) +{ + int ch, i, r; + picoev_loop* loop; + struct timeval start_at, end_at; + double elapsed; + + host.s_addr = htonl(0x7f000001); + + while ((ch = getopt(argc, argv, "a:c:n:fh:p:")) != -1) { + switch (ch) { + case 'a': + assert(sscanf(optarg, "%d", &active_connections) == 1); + break; + case 'c': + assert(sscanf(optarg, "%d", &num_connections) == 1); + break; + case 'n': + assert(sscanf(optarg, "%d", &num_requests) == 1); + break; + case 'f': + fix_clients = 1; + break; + case 'h': + if (inet_aton(optarg, &host) == 0) { + struct hostent* h = gethostbyname(optarg); + assert(h != NULL && "host not found"); + assert(h->h_addrtype == AF_INET); + assert(h->h_length == sizeof(host)); + memcpy(&host, h->h_addr_list[0], sizeof(host)); + } + break; + case 'p': + assert(sscanf(optarg, "%hu", &port) == 1); + break; + default: + exit(1); + } + } + + picoev_init(num_connections + 10); + loop = picoev_create_loop(60); + + /* setup connections */ + for (i = 0; i < num_connections; ++i) { + int on; + struct sockaddr_in addr; + int fd = socket(AF_INET, SOCK_STREAM, 0); + assert(fd != -1 && "socket(2) failed"); + on = 1; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr, &host, sizeof(host)); + r = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); + if (r == -1) { + perror("could not connect to server"); + exit(2); + } + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); + assert(r == 0); + r = fcntl(fd, F_SETFL, O_NONBLOCK); + assert(r == 0); + picoev_add(loop, fd, PICOEV_READ, 0, read_cb, NULL); + fds[i] = fd; + usleep(1000); + } + + gettimeofday(&start_at, NULL); + + /* fire first active_connections */ + for (i = 0; i < active_connections; ++i) { + r = write(fds[next_fd_idx], "hello\n", 6); + assert(r == 6); + next_fd_idx = (next_fd_idx + 1) % num_connections; + } + /* the main loop */ + while (num_responses < num_requests) { + picoev_loop_once(loop, 10); + } + + gettimeofday(&end_at, NULL); + + elapsed = end_at.tv_sec + end_at.tv_usec / 1000000.0 + - (start_at.tv_sec + start_at.tv_usec / 1000000.0); + printf("%f reqs./sec. (%d in %f seconds)\n", num_responses / elapsed, + num_responses, elapsed); + + return 0; +} diff --git a/testhttpclient.c b/testhttpclient.c new file mode 100644 index 0000000..1a4710d --- /dev/null +++ b/testhttpclient.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "picoev.h" + +static int active_connections = 1000; +static int num_connections = 10000; +static int num_requests = 1000000; +static int fix_clients = 0; +static struct in_addr host; +static unsigned short port = 11111; + +static int fds[1048576]; +static int next_fd_idx = 0; +static int num_responses; + +#define RES_SIZE (sizeof( \ + "HTTP\1.0 200 OK\r\n" \ + "Connection: keep-alive\r\n" \ + "Content-Length: 13\r\n" \ + "Content-Type: text/plain\r\n" \ + "\r\n" \ + "hello world!\n") - 1) + +static void write_req(int fd) +{ + int r; + +#define REQ "GET / HTTP/1.1\r\n" \ + "Host: 127.0.0.1\r\n" \ + "User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; ja-JP-mac; rv:1.9.1.3) Gecko/20090824\r\n" \ + "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\n" \ + "Accept-Language: ja,en-us;q=0.7,en;q=0.3\r\n" \ + "Accept-Encoding: gzip,deflate\r\n" \ + "Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7\r\n" \ + "Keep-Alive: 300\r\n" \ + "Connection: keep-alive\r\n" \ + "\r\n" + r = write(fd, REQ, sizeof(REQ) - 1); + assert(r == sizeof(REQ) - 1); +#undef REQ +} + +static void read_cb(picoev_loop* loop, int fd, int revents, void* cb_arg) +{ + char buf[RES_SIZE]; + int r; + + assert((revents & PICOEV_READ) != 0); + + r = read(fd, buf, sizeof(buf)); + assert(r == sizeof(buf)); + ++num_responses; + + if (num_responses < num_requests) { + int wfd; + if (fix_clients) { + wfd = fd; + } else { + wfd = fds[next_fd_idx]; + next_fd_idx = (next_fd_idx + 1) % num_connections; + } + write_req(wfd); + } +} + +int main(int argc, char** argv) +{ + int ch, i, r; + picoev_loop* loop; + struct timeval start_at, end_at; + double elapsed; + + host.s_addr = htonl(0x7f000001); + + while ((ch = getopt(argc, argv, "a:c:n:fh:p:")) != -1) { + switch (ch) { + case 'a': + assert(sscanf(optarg, "%d", &active_connections) == 1); + break; + case 'c': + assert(sscanf(optarg, "%d", &num_connections) == 1); + break; + case 'n': + assert(sscanf(optarg, "%d", &num_requests) == 1); + break; + case 'f': + fix_clients = 1; + break; + case 'h': + if (inet_aton(optarg, &host) == 0) { + struct hostent* h = gethostbyname(optarg); + assert(h != NULL && "host not found"); + assert(h->h_addrtype == AF_INET); + assert(h->h_length == sizeof(host)); + memcpy(&host, h->h_addr_list[0], sizeof(host)); + } + break; + case 'p': + assert(sscanf(optarg, "%hu", &port) == 1); + break; + default: + exit(1); + } + } + + picoev_init(num_connections + 10); + loop = picoev_create_loop(60); + + /* setup connections */ + for (i = 0; i < num_connections; ++i) { + int on; + struct sockaddr_in addr; + int fd = socket(AF_INET, SOCK_STREAM, 0); + assert(fd != -1 && "socket(2) failed"); + on = 1; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + memcpy(&addr.sin_addr, &host, sizeof(host)); + r = connect(fd, (struct sockaddr*)&addr, sizeof(addr)); + if (r == -1) { + perror("could not connect to server"); + exit(2); + } + r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)); + assert(r == 0); + r = fcntl(fd, F_SETFL, O_NONBLOCK); + assert(r == 0); + picoev_add(loop, fd, PICOEV_READ, 0, read_cb, NULL); + fds[i] = fd; + usleep(1000); + } + + gettimeofday(&start_at, NULL); + + /* fire first active_connections */ + for (i = 0; i < active_connections; ++i) { + write_req(fds[next_fd_idx]); + next_fd_idx = (next_fd_idx + 1) % num_connections; + } + /* the main loop */ + while (num_responses < num_requests) { + picoev_loop_once(loop, 10); + } + + gettimeofday(&end_at, NULL); + + elapsed = end_at.tv_sec + end_at.tv_usec / 1000000.0 + - (start_at.tv_sec + start_at.tv_usec / 1000000.0); + printf("%f reqs./sec. (%d in %f seconds)\n", num_responses / elapsed, + num_responses, elapsed); + + return 0; +}