aboutsummaryrefslogtreecommitdiff
path: root/src/testcurl/perf_get_concurrent.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/testcurl/perf_get_concurrent.c')
-rw-r--r--src/testcurl/perf_get_concurrent.c338
1 files changed, 338 insertions, 0 deletions
diff --git a/src/testcurl/perf_get_concurrent.c b/src/testcurl/perf_get_concurrent.c
new file mode 100644
index 00000000..deb949b2
--- /dev/null
+++ b/src/testcurl/perf_get_concurrent.c
@@ -0,0 +1,338 @@
1/*
2 This file is part of libmicrohttpd
3 (C) 2007, 2009, 2011 Christian Grothoff
4
5 libmicrohttpd is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 2, or (at your
8 option) any later version.
9
10 libmicrohttpd is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with libmicrohttpd; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file perf_get_concurrent.c
23 * @brief benchmark concurrent GET operations
24 * Note that we run libcurl on the machine at the
25 * same time, so the execution time may be influenced
26 * by the concurrent activity; it is quite possible
27 * that more time is spend with libcurl than with MHD,
28 * so the performance scores calculated with this code
29 * should NOT be used to compare with other HTTP servers
30 * (since MHD is actually better); only the relative
31 * scores between MHD versions are meaningful.
32 * @author Christian Grothoff
33 */
34
35#include "MHD_config.h"
36#include "platform.h"
37#include <curl/curl.h>
38#include <microhttpd.h>
39#include <stdlib.h>
40#include <string.h>
41#include <time.h>
42#include "gauger.h"
43
44/**
45 * How many rounds of operations do we do for each
46 * test (total number of requests will be ROUNDS * PAR).
47 */
48#define ROUNDS 500
49
50/**
51 * How many requests do we do in parallel?
52 */
53#define PAR 4
54
55/**
56 * Do we use HTTP 1.1?
57 */
58static int oneone;
59
60/**
61 * Response to return (re-used).
62 */
63static struct MHD_Response *response;
64
65/**
66 * Time this round was started.
67 */
68static unsigned long long start_time;
69
70
71/**
72 * Get the current timestamp
73 *
74 * @return current time in ms
75 */
76static unsigned long long
77now ()
78{
79 struct timeval tv;
80
81 GETTIMEOFDAY (&tv, NULL);
82 return (((unsigned long long) tv.tv_sec * 1000LL) +
83 ((unsigned long long) tv.tv_usec / 1000LL));
84}
85
86
87/**
88 * Start the timer.
89 */
90static void
91start_timer()
92{
93 start_time = now ();
94}
95
96
97/**
98 * Stop the timer and report performance
99 *
100 * @param desc description of the threading mode we used
101 */
102static void
103stop (const char *desc)
104{
105 double rps = ((double) (PAR * ROUNDS * 1000)) / ((double) (now() - start_time));
106
107 fprintf (stderr,
108 "Parallel GETs using %s: %f %s\n",
109 desc,
110 rps,
111 "requests/s");
112 GAUGER (desc,
113 "Parallel GETs",
114 rps,
115 "requests/s");
116}
117
118
119static size_t
120copyBuffer (void *ptr,
121 size_t size, size_t nmemb,
122 void *ctx)
123{
124 return size * nmemb;
125}
126
127static int
128ahc_echo (void *cls,
129 struct MHD_Connection *connection,
130 const char *url,
131 const char *method,
132 const char *version,
133 const char *upload_data, size_t *upload_data_size,
134 void **unused)
135{
136 static int ptr;
137 const char *me = cls;
138 int ret;
139
140 if (0 != strcmp (me, method))
141 return MHD_NO; /* unexpected method */
142 if (&ptr != *unused)
143 {
144 *unused = &ptr;
145 return MHD_YES;
146 }
147 *unused = NULL;
148 ret = MHD_queue_response (connection, MHD_HTTP_OK, response);
149 if (ret == MHD_NO)
150 abort ();
151 return ret;
152}
153
154
155static pid_t
156do_gets ()
157{
158 pid_t ret;
159 CURL *c;
160 CURLcode errornum;
161 unsigned int i;
162 unsigned int j;
163 pid_t par[PAR];
164
165 ret = fork ();
166 if (ret == -1) abort ();
167 if (ret != 0)
168 return ret;
169 for (j=0;j<PAR;j++)
170 {
171 par[j] = fork ();
172 if (par[j] == 0)
173 {
174 for (i=0;i<ROUNDS;i++)
175 {
176 c = curl_easy_init ();
177 curl_easy_setopt (c, CURLOPT_URL, "http://localhost:1081/hello_world");
178 curl_easy_setopt (c, CURLOPT_WRITEFUNCTION, &copyBuffer);
179 curl_easy_setopt (c, CURLOPT_WRITEDATA, NULL);
180 curl_easy_setopt (c, CURLOPT_FAILONERROR, 1);
181 curl_easy_setopt (c, CURLOPT_TIMEOUT, 150L);
182 if (oneone)
183 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
184 else
185 curl_easy_setopt (c, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
186 curl_easy_setopt (c, CURLOPT_CONNECTTIMEOUT, 15L);
187 /* NOTE: use of CONNECTTIMEOUT without also
188 setting NOSIGNAL results in really weird
189 crashes on my system! */
190 curl_easy_setopt (c, CURLOPT_NOSIGNAL, 1);
191 if (CURLE_OK != (errornum = curl_easy_perform (c)))
192 {
193 fprintf (stderr,
194 "curl_easy_perform failed: `%s'\n",
195 curl_easy_strerror (errornum));
196 curl_easy_cleanup (c);
197 _exit (1);
198 }
199 curl_easy_cleanup (c);
200 }
201 _exit (0);
202 }
203 }
204 for (j=0;j<PAR;j++)
205 waitpid (par[j], NULL, 0);
206 _exit (0);
207}
208
209
210static void
211join_gets (pid_t pid)
212{
213 int status;
214
215 status = 1;
216 waitpid (pid, &status, 0);
217 if (0 != status)
218 abort ();
219}
220
221
222static int
223testInternalGet (int poll_flag)
224{
225 struct MHD_Daemon *d;
226
227 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
228 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
229 if (d == NULL)
230 return 1;
231 start_timer ();
232 join_gets (do_gets ());
233 stop (poll_flag ? "internal poll" : "internal select");
234 MHD_stop_daemon (d);
235 return 0;
236}
237
238
239static int
240testMultithreadedGet (int poll_flag)
241{
242 struct MHD_Daemon *d;
243
244 d = MHD_start_daemon (MHD_USE_THREAD_PER_CONNECTION | MHD_USE_DEBUG | poll_flag,
245 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
246 if (d == NULL)
247 return 16;
248 start_timer ();
249 join_gets (do_gets ());
250 stop (poll_flag ? "thread with poll" : "thread with select");
251 MHD_stop_daemon (d);
252 return 0;
253}
254
255static int
256testMultithreadedPoolGet (int poll_flag)
257{
258 struct MHD_Daemon *d;
259
260 d = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG | poll_flag,
261 1081, NULL, NULL, &ahc_echo, "GET",
262 MHD_OPTION_THREAD_POOL_SIZE, 4, MHD_OPTION_END);
263 if (d == NULL)
264 return 16;
265 start_timer ();
266 join_gets (do_gets ());
267 stop (poll_flag ? "thread pool with poll" : "thread pool with select");
268 MHD_stop_daemon (d);
269 return 0;
270}
271
272static int
273testExternalGet ()
274{
275 struct MHD_Daemon *d;
276 pid_t pid;
277 fd_set rs;
278 fd_set ws;
279 fd_set es;
280 int max;
281 struct timeval tv;
282 unsigned MHD_LONG_LONG tt;
283 int tret;
284
285 d = MHD_start_daemon (MHD_USE_DEBUG,
286 1081, NULL, NULL, &ahc_echo, "GET", MHD_OPTION_END);
287 if (d == NULL)
288 return 256;
289 start_timer ();
290 pid = do_gets ();
291 while (0 == waitpid (pid, NULL, WNOHANG))
292 {
293 max = 0;
294 FD_ZERO (&rs);
295 FD_ZERO (&ws);
296 FD_ZERO (&es);
297 if (MHD_YES != MHD_get_fdset (d, &rs, &ws, &es, &max))
298 {
299 MHD_stop_daemon (d);
300 return 4096;
301 }
302 tret = MHD_get_timeout (d, &tt);
303 if (MHD_YES != tret) tt = 1;
304 tv.tv_sec = tt / 1000;
305 tv.tv_usec = 1000 * (tt % 1000);
306 select (max + 1, &rs, &ws, &es, &tv);
307 MHD_run (d);
308 }
309 stop ("external select");
310 MHD_stop_daemon (d);
311 return 0;
312}
313
314
315int
316main (int argc, char *const *argv)
317{
318 unsigned int errorCount = 0;
319
320 oneone = NULL != strstr (argv[0], "11");
321 if (0 != curl_global_init (CURL_GLOBAL_WIN32))
322 return 2;
323 response = MHD_create_response_from_buffer (strlen ("/hello_world"),
324 "/hello_world",
325 MHD_RESPMEM_MUST_COPY);
326 errorCount += testInternalGet (0);
327 errorCount += testMultithreadedGet (0);
328 errorCount += testMultithreadedPoolGet (0);
329 errorCount += testExternalGet ();
330 errorCount += testInternalGet (MHD_USE_POLL);
331 errorCount += testMultithreadedGet (MHD_USE_POLL);
332 errorCount += testMultithreadedPoolGet (MHD_USE_POLL);
333 MHD_destroy_response (response);
334 if (errorCount != 0)
335 fprintf (stderr, "Error (code: %u)\n", errorCount);
336 curl_global_cleanup ();
337 return errorCount != 0; /* 0 == pass */
338}