1 /* 2 * nghttp2 - HTTP/2 C Library 3 * 4 * Copyright (c) 2014 Tatsuhiro Tsujikawa 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 #ifndef H2LOAD_H 26 #define H2LOAD_H 27 28 #include "nghttp2_config.h" 29 30 #include <sys/types.h> 31 #ifdef HAVE_SYS_SOCKET_H 32 # include <sys/socket.h> 33 #endif // HAVE_SYS_SOCKET_H 34 #ifdef HAVE_NETDB_H 35 # include <netdb.h> 36 #endif // HAVE_NETDB_H 37 #include <sys/un.h> 38 39 #include <vector> 40 #include <string> 41 #include <unordered_map> 42 #include <memory> 43 #include <chrono> 44 #include <array> 45 46 #include <nghttp2/nghttp2.h> 47 48 #include <ev.h> 49 50 #include <openssl/ssl.h> 51 52 #include "http2.h" 53 #include "memchunk.h" 54 #include "template.h" 55 56 using namespace nghttp2; 57 58 namespace h2load { 59 60 constexpr auto BACKOFF_WRITE_BUFFER_THRES = 16_k; 61 62 class Session; 63 struct Worker; 64 65 struct Config { 66 std::vector<std::vector<nghttp2_nv>> nva; 67 std::vector<std::string> h1reqs; 68 std::vector<ev_tstamp> timings; 69 nghttp2::Headers custom_headers; 70 std::string scheme; 71 std::string host; 72 std::string connect_to_host; 73 std::string ifile; 74 std::string ciphers; 75 // length of upload data 76 int64_t data_length; 77 addrinfo *addrs; 78 size_t nreqs; 79 size_t nclients; 80 size_t nthreads; 81 // The maximum number of concurrent streams per session. 82 ssize_t max_concurrent_streams; 83 size_t window_bits; 84 size_t connection_window_bits; 85 // rate at which connections should be made 86 size_t rate; 87 ev_tstamp rate_period; 88 // amount of time for main measurements in timing-based test 89 ev_tstamp duration; 90 // amount of time to wait before starting measurements in timing-based test 91 ev_tstamp warm_up_time; 92 // amount of time to wait for activity on a given connection 93 ev_tstamp conn_active_timeout; 94 // amount of time to wait after the last request is made on a connection 95 ev_tstamp conn_inactivity_timeout; 96 enum { PROTO_HTTP2, PROTO_HTTP1_1 } no_tls_proto; 97 uint32_t header_table_size; 98 uint32_t encoder_header_table_size; 99 // file descriptor for upload data 100 int data_fd; 101 // file descriptor to write per-request stats to. 102 int log_fd; 103 uint16_t port; 104 uint16_t default_port; 105 uint16_t connect_to_port; 106 bool verbose; 107 bool timing_script; 108 std::string base_uri; 109 // true if UNIX domain socket is used. In this case, base_uri is 110 // not used in usual way. 111 bool base_uri_unix; 112 // used when UNIX domain socket is used (base_uri_unix is true). 113 sockaddr_un unix_addr; 114 // list of supported NPN/ALPN protocol strings in the order of 115 // preference. 116 std::vector<std::string> npn_list; 117 118 Config(); 119 ~Config(); 120 121 bool is_rate_mode() const; 122 bool is_timing_based_mode() const; 123 bool has_base_uri() const; 124 }; 125 126 struct RequestStat { 127 // time point when request was sent 128 std::chrono::steady_clock::time_point request_time; 129 // same, but in wall clock reference frame 130 std::chrono::system_clock::time_point request_wall_time; 131 // time point when stream was closed 132 std::chrono::steady_clock::time_point stream_close_time; 133 // upload data length sent so far 134 int64_t data_offset; 135 // HTTP status code 136 int status; 137 // true if stream was successfully closed. This means stream was 138 // not reset, but it does not mean HTTP level error (e.g., 404). 139 bool completed; 140 }; 141 142 struct ClientStat { 143 // time client started (i.e., first connect starts) 144 std::chrono::steady_clock::time_point client_start_time; 145 // time client end (i.e., client somehow processed all requests it 146 // is responsible for, and disconnected) 147 std::chrono::steady_clock::time_point client_end_time; 148 // The number of requests completed successful, but not necessarily 149 // means successful HTTP status code. 150 size_t req_success; 151 152 // The following 3 numbers are overwritten each time when connection 153 // is made. 154 155 // time connect starts 156 std::chrono::steady_clock::time_point connect_start_time; 157 // time to connect 158 std::chrono::steady_clock::time_point connect_time; 159 // time to first byte (TTFB) 160 std::chrono::steady_clock::time_point ttfb; 161 }; 162 163 struct SDStat { 164 // min, max, mean and sd (standard deviation) 165 double min, max, mean, sd; 166 // percentage of samples inside mean -/+ sd 167 double within_sd; 168 }; 169 170 struct SDStats { 171 // time for request 172 SDStat request; 173 // time for connect 174 SDStat connect; 175 // time to first byte (TTFB) 176 SDStat ttfb; 177 // request per second for each client 178 SDStat rps; 179 }; 180 181 struct Stats { 182 Stats(size_t req_todo, size_t nclients); 183 // The total number of requests 184 size_t req_todo; 185 // The number of requests issued so far 186 size_t req_started; 187 // The number of requests finished 188 size_t req_done; 189 // The number of requests completed successful, but not necessarily 190 // means successful HTTP status code. 191 size_t req_success; 192 // The number of requests marked as success. HTTP status code is 193 // also considered as success. This is subset of req_done. 194 size_t req_status_success; 195 // The number of requests failed. This is subset of req_done. 196 size_t req_failed; 197 // The number of requests failed due to network errors. This is 198 // subset of req_failed. 199 size_t req_error; 200 // The number of requests that failed due to timeout. 201 size_t req_timedout; 202 // The number of bytes received on the "wire". If SSL/TLS is used, 203 // this is the number of decrypted bytes the application received. 204 int64_t bytes_total; 205 // The number of bytes received for header fields. This is 206 // compressed version. 207 int64_t bytes_head; 208 // The number of bytes received for header fields after they are 209 // decompressed. 210 int64_t bytes_head_decomp; 211 // The number of bytes received in DATA frame. 212 int64_t bytes_body; 213 // The number of each HTTP status category, status[i] is status code 214 // in the range [i*100, (i+1)*100). 215 std::array<size_t, 6> status; 216 // The statistics per request 217 std::vector<RequestStat> req_stats; 218 // THe statistics per client 219 std::vector<ClientStat> client_stats; 220 }; 221 222 enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED }; 223 224 // This type tells whether the client is in warmup phase or not or is over 225 enum class Phase { 226 INITIAL_IDLE, // Initial idle state before warm-up phase 227 WARM_UP, // Warm up phase when no measurements are done 228 MAIN_DURATION, // Main measurement phase; if timing-based 229 // test is not run, this is the default phase 230 DURATION_OVER // This phase occurs after the measurements are over 231 }; 232 233 struct Client; 234 235 // We use reservoir sampling method 236 struct Sampling { 237 // maximum number of samples 238 size_t max_samples; 239 // number of samples seen, including discarded samples. 240 size_t n; 241 }; 242 243 struct Worker { 244 MemchunkPool mcpool; 245 Stats stats; 246 Sampling request_times_smp; 247 Sampling client_smp; 248 struct ev_loop *loop; 249 SSL_CTX *ssl_ctx; 250 Config *config; 251 size_t progress_interval; 252 uint32_t id; 253 bool tls_info_report_done; 254 bool app_info_report_done; 255 size_t nconns_made; 256 // number of clients this worker handles 257 size_t nclients; 258 // number of requests each client issues 259 size_t nreqs_per_client; 260 // at most nreqs_rem clients get an extra request 261 size_t nreqs_rem; 262 size_t rate; 263 // maximum number of samples in this worker thread 264 size_t max_samples; 265 ev_timer timeout_watcher; 266 // The next client ID this worker assigns 267 uint32_t next_client_id; 268 // Keeps track of the current phase (for timing-based experiment) for the 269 // worker 270 Phase current_phase; 271 // We need to keep track of the clients in order to stop them when needed 272 std::vector<Client *> clients; 273 // This is only active when there is not a bounded number of requests 274 // specified 275 ev_timer duration_watcher; 276 ev_timer warmup_watcher; 277 278 Worker(uint32_t id, SSL_CTX *ssl_ctx, size_t nreq_todo, size_t nclients, 279 size_t rate, size_t max_samples, Config *config); 280 ~Worker(); 281 Worker(Worker &&o) = default; 282 void run(); 283 void sample_req_stat(RequestStat *req_stat); 284 void sample_client_stat(ClientStat *cstat); 285 void report_progress(); 286 void report_rate_progress(); 287 // This function calls the destructors of all the clients. 288 void stop_all_clients(); 289 // This function frees a client from the list of clients for this Worker. 290 void free_client(Client *); 291 }; 292 293 struct Stream { 294 RequestStat req_stat; 295 int status_success; 296 Stream(); 297 }; 298 299 struct Client { 300 DefaultMemchunks wb; 301 std::unordered_map<int32_t, Stream> streams; 302 ClientStat cstat; 303 std::unique_ptr<Session> session; 304 ev_io wev; 305 ev_io rev; 306 std::function<int(Client &)> readfn, writefn; 307 Worker *worker; 308 SSL *ssl; 309 ev_timer request_timeout_watcher; 310 addrinfo *next_addr; 311 // Address for the current address. When try_new_connection() is 312 // used and current_addr is not nullptr, it is used instead of 313 // trying next address though next_addr. To try new address, set 314 // nullptr to current_addr before calling connect(). 315 addrinfo *current_addr; 316 size_t reqidx; 317 ClientState state; 318 // The number of requests this client has to issue. 319 size_t req_todo; 320 // The number of requests left to issue 321 size_t req_left; 322 // The number of requests currently have started, but not abandoned 323 // or finished. 324 size_t req_inflight; 325 // The number of requests this client has issued so far. 326 size_t req_started; 327 // The number of requests this client has done so far. 328 size_t req_done; 329 // The client id per worker 330 uint32_t id; 331 int fd; 332 ev_timer conn_active_watcher; 333 ev_timer conn_inactivity_watcher; 334 std::string selected_proto; 335 bool new_connection_requested; 336 // true if the current connection will be closed, and no more new 337 // request cannot be processed. 338 bool final; 339 340 enum { ERR_CONNECT_FAIL = -100 }; 341 342 Client(uint32_t id, Worker *worker, size_t req_todo); 343 ~Client(); 344 int make_socket(addrinfo *addr); 345 int connect(); 346 void disconnect(); 347 void fail(); 348 // Call this function when do_read() returns -1. This function 349 // tries to connect to the remote host again if it is requested. If 350 // so, this function returns 0, and this object should be retained. 351 // Otherwise, this function returns -1, and this object should be 352 // deleted. 353 int try_again_or_fail(); 354 void timeout(); 355 void restart_timeout(); 356 int submit_request(); 357 void process_request_failure(); 358 void process_timedout_streams(); 359 void process_abandoned_streams(); 360 void report_tls_info(); 361 void report_app_info(); 362 void terminate_session(); 363 // Asks client to create new connection, instead of just fail. 364 void try_new_connection(); 365 366 int do_read(); 367 int do_write(); 368 369 // low-level I/O callback functions called by do_read/do_write 370 int connected(); 371 int read_clear(); 372 int write_clear(); 373 int tls_handshake(); 374 int read_tls(); 375 int write_tls(); 376 377 int on_read(const uint8_t *data, size_t len); 378 int on_write(); 379 380 int connection_made(); 381 382 void on_request(int32_t stream_id); 383 void on_header(int32_t stream_id, const uint8_t *name, size_t namelen, 384 const uint8_t *value, size_t valuelen); 385 void on_status_code(int32_t stream_id, uint16_t status); 386 // |success| == true means that the request/response was exchanged 387 // |successfully, but it does not mean response carried successful 388 // |HTTP status code. 389 void on_stream_close(int32_t stream_id, bool success, bool final = false); 390 // Returns RequestStat for |stream_id|. This function must be 391 // called after on_request(stream_id), and before 392 // on_stream_close(stream_id, ...). Otherwise, this will return 393 // nullptr. 394 RequestStat *get_req_stat(int32_t stream_id); 395 396 void record_request_time(RequestStat *req_stat); 397 void record_connect_start_time(); 398 void record_connect_time(); 399 void record_ttfb(); 400 void clear_connect_times(); 401 void record_client_start_time(); 402 void record_client_end_time(); 403 404 void signal_write(); 405 }; 406 407 } // namespace h2load 408 409 #endif // H2LOAD_H 410