benchmark.c (5720B)
1 /* 2 This file is part of libmicrohttpd 3 Copyright (C) 2007, 2013 Christian Grothoff (and other contributing authors) 4 Copyright (C) 2014-2022 Evgeny Grin (Karlson2k) 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License as published by the Free Software Foundation; either 9 version 2.1 of the License, or (at your option) any later version. 10 11 This library is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 Lesser General Public License for more details. 15 16 You should have received a copy of the GNU Lesser General Public 17 License along with this library; if not, write to the Free Software 18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 /** 21 * @file benchmark.c 22 * @brief minimal code to benchmark MHD GET performance 23 * @author Christian Grothoff 24 * @author Karlson2k (Evgeny Grin) 25 */ 26 27 #include "platform.h" 28 #include <microhttpd.h> 29 30 #ifdef HAVE_INTTYPES_H 31 #include <inttypes.h> 32 #endif /* HAVE_INTTYPES_H */ 33 #ifndef PRIu64 34 #define PRIu64 "llu" 35 #endif /* ! PRIu64 */ 36 37 #if defined(MHD_CPU_COUNT) && (MHD_CPU_COUNT + 0) < 2 38 #undef MHD_CPU_COUNT 39 #endif 40 #if ! defined(MHD_CPU_COUNT) 41 #define MHD_CPU_COUNT 2 42 #endif 43 44 #define PAGE \ 45 "<html><head><title>libmicrohttpd demo</title></head><body>libmicrohttpd demo</body></html>" 46 47 48 #define SMALL (1024 * 128) 49 50 /** 51 * Number of threads to run in the thread pool. Should (roughly) match 52 * the number of cores on your system. 53 */ 54 #define NUMBER_OF_THREADS MHD_CPU_COUNT 55 56 static unsigned int small_deltas[SMALL]; 57 58 static struct MHD_Response *response; 59 60 61 /** 62 * Signature of the callback used by MHD to notify the 63 * application about completed requests. 64 * 65 * @param cls client-defined closure 66 * @param connection connection handle 67 * @param req_cls value as set by the last call to 68 * the MHD_AccessHandlerCallback 69 * @param toe reason for request termination 70 * @see MHD_OPTION_NOTIFY_COMPLETED 71 */ 72 static void 73 completed_callback (void *cls, 74 struct MHD_Connection *connection, 75 void **req_cls, 76 enum MHD_RequestTerminationCode toe) 77 { 78 struct timeval *tv = *req_cls; 79 struct timeval tve; 80 uint64_t delta; 81 (void) cls; /* Unused. Silent compiler warning. */ 82 (void) connection; /* Unused. Silent compiler warning. */ 83 (void) toe; /* Unused. Silent compiler warning. */ 84 85 if (NULL == tv) 86 return; 87 gettimeofday (&tve, NULL); 88 89 delta = ((uint64_t) (tve.tv_sec - tv->tv_sec)) * 1000000LL 90 + (uint64_t) tve.tv_usec - (uint64_t) tv->tv_usec; 91 if (delta < SMALL) 92 small_deltas[delta]++; 93 else 94 fprintf (stdout, "D: %" PRIu64 " 1\n", delta); 95 free (tv); 96 } 97 98 99 static void * 100 uri_logger_cb (void *cls, 101 const char *uri) 102 { 103 struct timeval *tv = malloc (sizeof (struct timeval)); 104 (void) cls; /* Unused. Silent compiler warning. */ 105 (void) uri; /* Unused. Silent compiler warning. */ 106 107 if (NULL != tv) 108 gettimeofday (tv, NULL); 109 return tv; 110 } 111 112 113 static enum MHD_Result 114 ahc_echo (void *cls, 115 struct MHD_Connection *connection, 116 const char *url, 117 const char *method, 118 const char *version, 119 const char *upload_data, size_t *upload_data_size, void **req_cls) 120 { 121 (void) cls; /* Unused. Silent compiler warning. */ 122 (void) url; /* Unused. Silent compiler warning. */ 123 (void) version; /* Unused. Silent compiler warning. */ 124 (void) upload_data; /* Unused. Silent compiler warning. */ 125 (void) upload_data_size; /* Unused. Silent compiler warning. */ 126 (void) req_cls; /* Unused. Silent compiler warning. */ 127 128 if (0 != strcmp (method, "GET")) 129 return MHD_NO; /* unexpected method */ 130 return MHD_queue_response (connection, MHD_HTTP_OK, response); 131 } 132 133 134 int 135 main (int argc, char *const *argv) 136 { 137 struct MHD_Daemon *d; 138 unsigned int i; 139 int port; 140 141 if (argc != 2) 142 { 143 printf ("%s PORT\n", argv[0]); 144 return 1; 145 } 146 port = atoi (argv[1]); 147 if ( (1 > port) || (port > 65535) ) 148 { 149 fprintf (stderr, 150 "Port must be a number between 1 and 65535.\n"); 151 return 1; 152 } 153 response = MHD_create_response_from_buffer_static (strlen (PAGE), 154 (const void *) PAGE); 155 #if 0 156 (void) MHD_add_response_header (response, 157 MHD_HTTP_HEADER_CONNECTION, 158 "close"); 159 #endif 160 d = MHD_start_daemon (MHD_USE_INTERNAL_POLLING_THREAD 161 | MHD_USE_SUPPRESS_DATE_NO_CLOCK 162 #ifdef EPOLL_SUPPORT 163 | MHD_USE_EPOLL | MHD_USE_TURBO 164 #endif 165 , 166 (uint16_t) port, 167 NULL, NULL, &ahc_echo, NULL, 168 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 120, 169 MHD_OPTION_THREAD_POOL_SIZE, (unsigned 170 int) NUMBER_OF_THREADS, 171 MHD_OPTION_URI_LOG_CALLBACK, &uri_logger_cb, NULL, 172 MHD_OPTION_NOTIFY_COMPLETED, &completed_callback, NULL, 173 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 1000, 174 MHD_OPTION_END); 175 if (d == NULL) 176 return 1; 177 (void) getc (stdin); 178 MHD_stop_daemon (d); 179 MHD_destroy_response (response); 180 for (i = 0; i < SMALL; i++) 181 if (0 != small_deltas[i]) 182 fprintf (stdout, "D: %u %u\n", i, small_deltas[i]); 183 return 0; 184 }