mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-13 10:02:38 +00:00
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.
This commit is contained in:
parent
57432591c1
commit
6383f6aae0
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=150990
9
tools/tools/netrate/http/Makefile
Normal file
9
tools/tools/netrate/http/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= http
|
||||
WARNS= 3
|
||||
NO_MAN=
|
||||
DPADD= ${LIBPTHREAD}
|
||||
LDADD= -lpthread
|
||||
|
||||
.include <bsd.prog.mk>
|
196
tools/tools/netrate/http/http.c
Normal file
196
tools/tools/netrate/http/http.c
Normal file
@ -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);
|
||||
}
|
9
tools/tools/netrate/httpd/Makefile
Normal file
9
tools/tools/netrate/httpd/Makefile
Normal file
@ -0,0 +1,9 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= httpd
|
||||
WARNS= 3
|
||||
NO_MAN=
|
||||
DPADD= ${LIBPTHREAD}
|
||||
LDADD= -lpthread
|
||||
|
||||
.include <bsd.prog.mk>
|
142
tools/tools/netrate/httpd/httpd.c
Normal file
142
tools/tools/netrate/httpd/httpd.c
Normal file
@ -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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user