Skip to content

Commit 217e723

Browse files
committed
add quic_server_ssl_poll_http to benchmark SSL_poll() for QUIC protocol
The tool spawns server and client thread. Client then starts '-c' connections to server over a loopback interface. The connections then transport bidirectional (-b) or unidirectional (-u) HTTP/1.0 streams to measure performance. Fixes #26 Reviewed-by: Matt Caswell <[email protected]> Reviewed-by: Neil Horman <[email protected]> (Merged from #26)
1 parent e5cd2d4 commit 217e723

File tree

9 files changed

+3532
-7
lines changed

9 files changed

+3532
-7
lines changed

README

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,27 @@ writeread [-t] [-s] [-d] [-b size] <certsdir> <threadcount>
166166
-b - size of buffer to write and read, default is 1024 bytes.
167167
certsdir - directory where the test can locate servercert.pem and serverkey.pem.
168168
threadcount - number of concurrent threads to run in test.
169+
170+
ssl_poll_perf
171+
-------------
172+
173+
Tool to evaluate performance of QUIC client and server which both use
174+
SSL_poll(3ossl). Application creates two threads, one for client the
175+
other for server. Server and client can both accept/create simultanous
176+
connections. Each connection then can carry multiple unidirectional/bidirectional
177+
streams. The streams handle HTTP/1.0 GET request/responses only.
178+
Server always drains the incoming stream initiated by client. It answers to
179+
any GET request. The default reply is 200 OK with 12345 bytes of payload.
180+
Client may request desired payload with URL as follows:
181+
/any/path/to_8192whatever/foo_4096.txt
182+
In which case the server will send response with 8kB http/1.0 body.
183+
The URL parser attempts to find leftmost number, which denotes the number
184+
of bytes client expects in response.
185+
The test program supports options as follows:
186+
-c - number of connections to create (default 10)
187+
-b - number of bidirectional streams each connection creates (default 10)
188+
-u - number of unidirectional streams each connection creates (default 10)
189+
-s - the size of reply body, the maximum size is 100MB. The default size is 64.
190+
-w - the size of request body, the maximum size is 100MB. The default size is 64.
191+
-p - port number to use
192+
-t - terse output

source/CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ add_library(perf perflib/perfhelper.c perflib/perfsslhelper.c perflib/threads.c
114114
perflib/time.c)
115115

116116
if (WIN32)
117-
target_sources(perf PRIVATE perflib/getopt.c perflib/basename.c)
117+
target_sources(perf PRIVATE perflib/getopt.c perflib/basename.c perflib/err.c)
118118
endif()
119119

120120
target_include_directories(perf PUBLIC "${PROJECT_SOURCE_DIR}")
@@ -126,6 +126,9 @@ if( OPENSSL_VERSION VERSION_GREATER_EQUAL 3 )
126126

127127
add_executable(providerdoall providerdoall.c)
128128
target_link_libraries(providerdoall PRIVATE perf)
129+
130+
add_executable(ssl_poll_perf ssl_poll_perf.c)
131+
target_link_libraries(ssl_poll_perf PRIVATE perf)
129132
endif()
130133

131134
add_executable(randbytes randbytes.c)

source/Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
all: randbytes handshake sslnew newrawkey rsasign x509storeissuer providerdoall rwlocks pkeyread evp_fetch evp_setpeer writeread
1+
all: randbytes handshake sslnew newrawkey rsasign x509storeissuer providerdoall rwlocks pkeyread evp_fetch evp_setpeer writeread ssl_poll_perf
22
# Build target for OpenSSL 1.1.1 builds
33
all111: randbytes handshake sslnew newrawkey rsasign x509storeissuer rwlocks pkeyread evp_setpeer writeread
44

@@ -56,3 +56,6 @@ evp_setpeer: evp_setpeer.c libperf.a
5656

5757
writeread: writeread.c libperf.a
5858
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o writeread writeread.c -lperf -lcrypto -lssl
59+
60+
ssl_poll_perf: ssl_poll_perf.c libperf.a
61+
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -o ssl_poll_perf ssl_poll_perf.c -lperf -lcrypto -lssl

source/perflib/err.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2024 The OpenSSL Project Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. You can obtain a copy
6+
* in the file LICENSE in the source distribution or at
7+
* https://www.openssl.org/source/license.html
8+
*/
9+
10+
#include <stdarg.h>
11+
12+
const char *progname;
13+
14+
static void
15+
vwarnx(const char *fmt, va_list ap)
16+
{
17+
if (progname != NULL)
18+
fprintf(stderr, "%s: ", progname);
19+
vfprintf(stderr, fmt, ap);
20+
putc('\n', stderr);
21+
}
22+
23+
static void
24+
errx(int status, const char *fmt, ...)
25+
{
26+
va_list ap;
27+
28+
va_start(ap, fmt);
29+
vwarnx(fmt, ap);
30+
va_end(ap);
31+
exit(status);
32+
}
33+
34+
static void
35+
warnx(const char *fmt, ...)
36+
{
37+
va_list ap;
38+
39+
va_start(ap, fmt);
40+
vwarnx(fmt, ap);
41+
va_end(ap);
42+
}

source/perflib/err.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2025 The OpenSSL Project Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. You can obtain a copy
6+
* in the file LICENSE in the source distribution or at
7+
* https://www.openssl.org/source/license.html
8+
*/
9+
10+
#ifndef OSSL_PERFLIB_GETOPT_H
11+
# define OSSL_PERFLIB_GETOPT_H
12+
# pragma once
13+
14+
#include <stdarg.h>
15+
16+
extern const char *progname;
17+
18+
extern void vwarnx(const char *, va_list);
19+
extern void errx(int, const char *, ...);
20+
extern void warnx(const char *, ...);
21+
22+
#endif
23+

source/perflib/list.h

Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
/*
2+
* Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License 2.0 (the "License"). You may not use
5+
* this file except in compliance with the License. You can obtain a copy
6+
* in the file LICENSE in the source distribution or at
7+
* https://www.openssl.org/source/license.html
8+
*/
9+
10+
#ifndef OSSL_INTERNAL_LIST_H
11+
# define OSSL_INTERNAL_LIST_H
12+
# pragma once
13+
14+
# include <string.h>
15+
# include <assert.h>
16+
17+
# ifdef NDEBUG
18+
# define OSSL_LIST_DBG(x)
19+
# else
20+
# define OSSL_LIST_DBG(x) x;
21+
# endif
22+
23+
# define OSSL_LIST_FOREACH_FROM(p, name, init) \
24+
for ((p) = (init); \
25+
(p) != NULL; \
26+
(p) = ossl_list_##name##_next(p))
27+
# define OSSL_LIST_FOREACH(p, name, l) \
28+
OSSL_LIST_FOREACH_FROM(p, name, ossl_list_##name##_head(l))
29+
30+
# define OSSL_LIST_FOREACH_REV_FROM(p, name, init) \
31+
for ((p) = (init); \
32+
(p) != NULL; \
33+
(p) = ossl_list_##name##_prev(p))
34+
# define OSSL_LIST_FOREACH_REV(p, name, l) \
35+
OSSL_LIST_FOREACH_FROM(p, name, ossl_list_##name##_tail(l))
36+
37+
# define OSSL_LIST_FOREACH_DELSAFE_FROM(p, pn, name, init) \
38+
for ((p) = (init); \
39+
(p) != NULL && (((pn) = ossl_list_##name##_next(p)), 1); \
40+
(p) = (pn))
41+
#define OSSL_LIST_FOREACH_DELSAFE(p, pn, name, l) \
42+
OSSL_LIST_FOREACH_DELSAFE_FROM(p, pn, name, ossl_list_##name##_head(l))
43+
44+
# define OSSL_LIST_FOREACH_REV_DELSAFE_FROM(p, pn, name, init) \
45+
for ((p) = (init); \
46+
(p) != NULL && (((pn) = ossl_list_##name##_prev(p)), 1); \
47+
(p) = (pn))
48+
# define OSSL_LIST_FOREACH_REV_DELSAFE(p, pn, name, l) \
49+
OSSL_LIST_FOREACH_REV_DELSAFE_FROM(p, pn, name, ossl_list_##name##_tail(l))
50+
51+
/* Define a list structure */
52+
# define OSSL_LIST(name) OSSL_LIST_ ## name
53+
54+
/* Define fields to include an element of a list */
55+
# define OSSL_LIST_MEMBER(name, type) \
56+
struct { \
57+
type *next, *prev; \
58+
OSSL_LIST_DBG(struct ossl_list_st_ ## name *list) \
59+
} ossl_list_ ## name
60+
61+
# define DECLARE_LIST_OF(name, type) \
62+
typedef struct ossl_list_st_ ## name OSSL_LIST(name); \
63+
struct ossl_list_st_ ## name { \
64+
type *alpha, *omega; \
65+
size_t num_elems; \
66+
} \
67+
68+
# define DEFINE_LIST_OF_IMPL(name, type) \
69+
static ossl_unused ossl_inline void \
70+
ossl_list_##name##_init(OSSL_LIST(name) *list) \
71+
{ \
72+
memset(list, 0, sizeof(*list)); \
73+
} \
74+
static ossl_unused ossl_inline void \
75+
ossl_list_##name##_init_elem(type *elem) \
76+
{ \
77+
memset(&elem->ossl_list_ ## name, 0, \
78+
sizeof(elem->ossl_list_ ## name)); \
79+
} \
80+
static ossl_unused ossl_inline int \
81+
ossl_list_##name##_is_empty(const OSSL_LIST(name) *list) \
82+
{ \
83+
return list->num_elems == 0; \
84+
} \
85+
static ossl_unused ossl_inline size_t \
86+
ossl_list_##name##_num(const OSSL_LIST(name) *list) \
87+
{ \
88+
return list->num_elems; \
89+
} \
90+
static ossl_unused ossl_inline type * \
91+
ossl_list_##name##_head(const OSSL_LIST(name) *list) \
92+
{ \
93+
assert(list->alpha == NULL \
94+
|| list->alpha->ossl_list_ ## name.list == list); \
95+
return list->alpha; \
96+
} \
97+
static ossl_unused ossl_inline type * \
98+
ossl_list_##name##_tail(const OSSL_LIST(name) *list) \
99+
{ \
100+
assert(list->omega == NULL \
101+
|| list->omega->ossl_list_ ## name.list == list); \
102+
return list->omega; \
103+
} \
104+
static ossl_unused ossl_inline type * \
105+
ossl_list_##name##_next(const type *elem) \
106+
{ \
107+
assert(elem->ossl_list_ ## name.next == NULL \
108+
|| elem->ossl_list_ ## name.next \
109+
->ossl_list_ ## name.prev == elem); \
110+
return elem->ossl_list_ ## name.next; \
111+
} \
112+
static ossl_unused ossl_inline type * \
113+
ossl_list_##name##_prev(const type *elem) \
114+
{ \
115+
assert(elem->ossl_list_ ## name.prev == NULL \
116+
|| elem->ossl_list_ ## name.prev \
117+
->ossl_list_ ## name.next == elem); \
118+
return elem->ossl_list_ ## name.prev; \
119+
} \
120+
static ossl_unused ossl_inline void \
121+
ossl_list_##name##_remove(OSSL_LIST(name) *list, type *elem) \
122+
{ \
123+
assert(elem->ossl_list_ ## name.list == list); \
124+
OSSL_LIST_DBG(elem->ossl_list_ ## name.list = NULL) \
125+
if (list->alpha == elem) \
126+
list->alpha = elem->ossl_list_ ## name.next; \
127+
if (list->omega == elem) \
128+
list->omega = elem->ossl_list_ ## name.prev; \
129+
if (elem->ossl_list_ ## name.prev != NULL) \
130+
elem->ossl_list_ ## name.prev->ossl_list_ ## name.next = \
131+
elem->ossl_list_ ## name.next; \
132+
if (elem->ossl_list_ ## name.next != NULL) \
133+
elem->ossl_list_ ## name.next->ossl_list_ ## name.prev = \
134+
elem->ossl_list_ ## name.prev; \
135+
list->num_elems--; \
136+
memset(&elem->ossl_list_ ## name, 0, \
137+
sizeof(elem->ossl_list_ ## name)); \
138+
} \
139+
static ossl_unused ossl_inline void \
140+
ossl_list_##name##_insert_head(OSSL_LIST(name) *list, type *elem) \
141+
{ \
142+
assert(elem->ossl_list_ ## name.list == NULL); \
143+
OSSL_LIST_DBG(elem->ossl_list_ ## name.list = list) \
144+
if (list->alpha != NULL) \
145+
list->alpha->ossl_list_ ## name.prev = elem; \
146+
elem->ossl_list_ ## name.next = list->alpha; \
147+
elem->ossl_list_ ## name.prev = NULL; \
148+
list->alpha = elem; \
149+
if (list->omega == NULL) \
150+
list->omega = elem; \
151+
list->num_elems++; \
152+
} \
153+
static ossl_unused ossl_inline void \
154+
ossl_list_##name##_insert_tail(OSSL_LIST(name) *list, type *elem) \
155+
{ \
156+
assert(elem->ossl_list_ ## name.list == NULL); \
157+
OSSL_LIST_DBG(elem->ossl_list_ ## name.list = list) \
158+
if (list->omega != NULL) \
159+
list->omega->ossl_list_ ## name.next = elem; \
160+
elem->ossl_list_ ## name.prev = list->omega; \
161+
elem->ossl_list_ ## name.next = NULL; \
162+
list->omega = elem; \
163+
if (list->alpha == NULL) \
164+
list->alpha = elem; \
165+
list->num_elems++; \
166+
} \
167+
static ossl_unused ossl_inline void \
168+
ossl_list_##name##_insert_before(OSSL_LIST(name) *list, type *e, \
169+
type *elem) \
170+
{ \
171+
assert(elem->ossl_list_ ## name.list == NULL); \
172+
OSSL_LIST_DBG(elem->ossl_list_ ## name.list = list) \
173+
elem->ossl_list_ ## name.next = e; \
174+
elem->ossl_list_ ## name.prev = e->ossl_list_ ## name.prev; \
175+
if (e->ossl_list_ ## name.prev != NULL) \
176+
e->ossl_list_ ## name.prev->ossl_list_ ## name.next = elem; \
177+
e->ossl_list_ ## name.prev = elem; \
178+
if (list->alpha == e) \
179+
list->alpha = elem; \
180+
list->num_elems++; \
181+
} \
182+
static ossl_unused ossl_inline void \
183+
ossl_list_##name##_insert_after(OSSL_LIST(name) *list, type *e, \
184+
type *elem) \
185+
{ \
186+
assert(elem->ossl_list_ ## name.list == NULL); \
187+
OSSL_LIST_DBG(elem->ossl_list_ ## name.list = list) \
188+
elem->ossl_list_ ## name.prev = e; \
189+
elem->ossl_list_ ## name.next = e->ossl_list_ ## name.next; \
190+
if (e->ossl_list_ ## name.next != NULL) \
191+
e->ossl_list_ ## name.next->ossl_list_ ## name.prev = elem; \
192+
e->ossl_list_ ## name.next = elem; \
193+
if (list->omega == e) \
194+
list->omega = elem; \
195+
list->num_elems++; \
196+
} \
197+
struct ossl_list_st_ ## name
198+
199+
# define DEFINE_LIST_OF(name, type) \
200+
DECLARE_LIST_OF(name, type); \
201+
DEFINE_LIST_OF_IMPL(name, type)
202+
203+
#endif

source/perflib/perflib.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ typedef pthread_t thread_t;
3232

3333
# endif
3434

35+
struct thread_arg_st {
36+
void (*func)(size_t num);
37+
size_t num;
38+
};
39+
40+
int perflib_run_thread(thread_t *t, struct thread_arg_st *arg);
41+
int perflib_wait_for_thread(thread_t thread);
3542
int perflib_run_multi_thread_test(void (*f)(size_t), size_t threadcount,
3643
OSSL_TIME *duration);
3744
char *perflib_mk_file_path(const char *dir, const char *file);

source/perflib/threads.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,6 @@
99

1010
#include "perflib/perflib.h"
1111

12-
struct thread_arg_st {
13-
void (*func)(size_t num);
14-
size_t num;
15-
};
16-
1712
#if defined(_WIN32)
1813

1914
static DWORD WINAPI thread_run(LPVOID varg)

0 commit comments

Comments
 (0)