summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2005-10-06 08:41:08 +0000
committerrwatson <rwatson@FreeBSD.org>2005-10-06 08:41:08 +0000
commit15415175d51bf3e6d0c471fa8d4d120b27f32608 (patch)
treee6bdde6202345f60bbaba1c19a8d5c8479c09f8f /tools
parentbb545b1c608bff9b791fcb393e0b19c3ee99feac (diff)
downloadFreeBSD-src-15415175d51bf3e6d0c471fa8d4d120b27f32608.zip
FreeBSD-src-15415175d51bf3e6d0c471fa8d4d120b27f32608.tar.gz
Add basic simplified HTTP benchmark tools to the netrate suite:
- http is a lightweight, multithreaded HTTP query tool, which performs a timed measurement of the rate at which it can download files using single-fetch HTTP/1.0. Other than specifying the IP and a URL path, it requires zero configuration. - httpd is a lightweight, multithreaded HTTP server tool, which exports a single file of choice to the HTTP client, and responds with it no matter what the request. Other than specifying the file to export, it requires zero configuration. The goal of these tools is to measure the network costs associated with HTTP serving, rather than file system, HTTP protocol parsing, error handling, etc, and as such, parts relating to less interesting components of HTTP testing are intentionally omitted. Both are linked against libpthread by default.
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/netrate/http/Makefile9
-rw-r--r--tools/tools/netrate/http/http.c196
-rw-r--r--tools/tools/netrate/httpd/Makefile9
-rw-r--r--tools/tools/netrate/httpd/httpd.c142
4 files changed, 356 insertions, 0 deletions
diff --git a/tools/tools/netrate/http/Makefile b/tools/tools/netrate/http/Makefile
new file mode 100644
index 0000000..789e7d0
--- /dev/null
+++ b/tools/tools/netrate/http/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+PROG= http
+WARNS= 3
+NO_MAN=
+DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
+
+.include <bsd.prog.mk>
diff --git a/tools/tools/netrate/http/http.c b/tools/tools/netrate/http/http.c
new file mode 100644
index 0000000..cd133e0
--- /dev/null
+++ b/tools/tools/netrate/http/http.c
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * Simple, multi-threaded HTTP benchmark. Fetches a single URL using the
+ * specified parameters, and after a period of execution, reports on how it
+ * worked out.
+ */
+#define THREADS 128
+#define SECONDS 20
+#define BUFFER (48*1024)
+#define HTTP 8000
+#define QUIET 1
+
+struct http_worker_description {
+ pthread_t hwd_thread;
+ u_int64_t hwd_count;
+ u_int64_t hwd_errorcount;
+};
+
+static struct sockaddr_in sin;
+static char *path;
+static struct http_worker_description hwd[THREADS];
+static int run_done;
+static pthread_barrier_t start_barrier;
+
+/*
+ * Given a partially processed URL, fetch it from the specified host.
+ */
+static int
+http_fetch(struct sockaddr_in *sin, char *path, int quiet)
+{
+ u_char buffer[BUFFER];
+ ssize_t len;
+ size_t sofar;
+ int sock;
+
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ if (!quiet)
+ warn("socket(PF_INET, SOCK_STREAM)");
+ return (-1);
+ }
+
+ if (connect(sock, (struct sockaddr *)sin, sizeof(*sin)) < 0) {
+ if (!quiet)
+ warn("connect");
+ close(sock);
+ return (-1);
+ }
+
+ /* Send a request. */
+ snprintf(buffer, BUFFER, "GET %s HTTP/1.0\n\n", path);
+ sofar = 0;
+ while (sofar < strlen(buffer)) {
+ len = send(sock, buffer, strlen(buffer), 0);
+ if (len < 0) {
+ if (!quiet)
+ warn("send");
+ close(sock);
+ return (-1);
+ }
+ if (len == 0) {
+ if (!quiet)
+ warnx("send: len == 0");
+ }
+ sofar += len;
+ }
+
+ /* Read until done. Not very smart. */
+ while (1) {
+ len = recv(sock, buffer, BUFFER, 0);
+ if (len < 0) {
+ if (!quiet)
+ warn("recv");
+ close(sock);
+ return (-1);
+ }
+ if (len == 0)
+ break;
+ }
+
+ close(sock);
+ return (0);
+}
+
+static void *
+http_worker(void *arg)
+{
+ struct http_worker_description *hwdp;
+ int ret;
+
+ ret = pthread_barrier_wait(&start_barrier);
+ if (ret != 0 && ret != PTHREAD_BARRIER_SERIAL_THREAD)
+ err(-1, "pthread_barrier_wait");
+
+ hwdp = arg;
+ while (!run_done) {
+ if (http_fetch(&sin, path, QUIET) < 0) {
+ hwdp->hwd_errorcount++;
+ continue;
+ }
+ /* Don't count transfers that didn't finish in time. */
+ if (!run_done)
+ hwdp->hwd_count++;
+ }
+
+ return (NULL);
+}
+
+int
+main(int argc, char *argv[])
+{
+ u_int64_t total;
+ int i;
+
+ if (argc != 3)
+ errx(-1, "usage: http [IP] [PATH]");
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(HTTP);
+ sin.sin_addr.s_addr = inet_addr(argv[1]);
+ path = argv[2];
+
+ /*
+ * Do one test retrieve so we can report the error from it, if any.
+ */
+ if (http_fetch(&sin, path, 0) < 0)
+ exit(-1);
+
+ if (pthread_barrier_init(&start_barrier, NULL, THREADS) < 0)
+ err(-1, "pthread_mutex_init");
+
+ for (i = 0; i < THREADS; i++) {
+ hwd[i].hwd_count = 0;
+ if (pthread_create(&hwd[i].hwd_thread, NULL, http_worker,
+ &hwd[i]) < 0)
+ err(-1, "pthread_create");
+ }
+ sleep(SECONDS);
+ run_done = 1;
+ for (i = 0; i < THREADS; i++) {
+ if (pthread_join(hwd[i].hwd_thread, NULL) < 0)
+ err(-1, "pthread_join");
+ }
+ total = 0;
+ for (i = 0; i < THREADS; i++)
+ total += hwd[i].hwd_count;
+ printf("%llu transfers/second\n", total / SECONDS);
+ total = 0;
+ for (i = 0; i < THREADS; i++)
+ total += hwd[i].hwd_errorcount;
+ printf("%llu errors/second\n", total / SECONDS);
+ return (0);
+}
diff --git a/tools/tools/netrate/httpd/Makefile b/tools/tools/netrate/httpd/Makefile
new file mode 100644
index 0000000..74067f2
--- /dev/null
+++ b/tools/tools/netrate/httpd/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+PROG= httpd
+WARNS= 3
+NO_MAN=
+DPADD= ${LIBPTHREAD}
+LDADD= -lpthread
+
+.include <bsd.prog.mk>
diff --git a/tools/tools/netrate/httpd/httpd.c b/tools/tools/netrate/httpd/httpd.c
new file mode 100644
index 0000000..d8907ff
--- /dev/null
+++ b/tools/tools/netrate/httpd/httpd.c
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 2005 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <arpa/inet.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * Simple, multi-threaded HTTP server. Very dumb.
+ */
+#define THREADS 128
+#define BUFFER (48*1024)
+#define HTTP 8000
+
+static const char *path;
+static int listen_sock;
+static int data_file;
+
+/*
+ * Given an open client socket, process its request. No notion of timeout.
+ */
+static int
+http_serve(int sock)
+{
+ ssize_t len;
+ int ncount;
+ char ch;
+
+ /* Read until \n\n. Not very smart. */
+ ncount = 0;
+ while (1) {
+ len = recv(sock, &ch, sizeof(ch), 0);
+ if (len < 0) {
+ warn("recv");
+ return (-1);
+ }
+ if (len == 0)
+ return (-1);
+ if (ch == '\n')
+ ncount++;
+ if (ncount == 2)
+ break;
+ }
+
+ if (sendfile(data_file, sock, 0, 0, NULL, NULL, 0) < 0)
+ warn("sendfile");
+
+ return (0);
+}
+
+static void *
+httpd_worker(void *arg)
+{
+ int sock;
+
+ while (1) {
+ sock = accept(listen_sock, NULL, NULL);
+ if (sock < 0)
+ continue;
+ (void)http_serve(sock);
+ close(sock);
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ pthread_t thread_array[THREADS];
+ struct sockaddr_in sin;
+ int i;
+
+ if (argc != 2)
+ errx(-1, "usage: http [PATH]");
+
+ listen_sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (listen_sock < 0)
+ err(-1, "socket(PF_INET, SOCK_STREAM)");
+
+ bzero(&sin, sizeof(sin));
+ sin.sin_len = sizeof(sin);
+ sin.sin_family = AF_INET;
+ sin.sin_port = htons(HTTP);
+
+ path = argv[1];
+ data_file = open(path, O_RDONLY);
+ if (data_file < 0)
+ err(-1, "open: %s", path);
+
+ if (bind(listen_sock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
+ err(-1, "bind");
+
+ if (listen(listen_sock, -1) < 0)
+ err(-1, "listen");
+
+ for (i = 0; i < THREADS; i++) {
+ if (pthread_create(&thread_array[i], NULL, httpd_worker,
+ NULL) < 0)
+ err(-1, "pthread_create");
+ }
+
+ for (i = 0; i < THREADS; i++) {
+ if (pthread_join(thread_array[i], NULL) < 0)
+ err(-1, "pthread_join");
+ }
+ return (0);
+}
OpenPOWER on IntegriCloud