Browse Source

wrk show latency

ithewei 10 months ago
parent
commit
4f05ec3310
1 changed files with 59 additions and 6 deletions
  1. 59 6
      examples/wrk.cpp

+ 59 - 6
examples/wrk.cpp

@@ -6,6 +6,9 @@
  *
  */
 
+#include <vector>
+#include <algorithm>
+
 #include "hv.h"
 #include "hmain.h"  // import parse_opt
 #include "hloop.h"
@@ -15,7 +18,7 @@
 #include "HttpParser.h"
 using namespace hv;
 
-static const char options[] = "hvc:d:t:";
+static const char options[] = "hvc:d:t:b:i:";
 
 static const char detail_options[] = R"(
   -h                Print help infomation
@@ -23,11 +26,15 @@ static const char detail_options[] = R"(
   -c <connections>  Number of connections, default: 1000
   -d <duration>     Duration of test, default: 10s
   -t <threads>      Number of threads, default: 4
+  -b <bytes>        Content-Length, default: 0
+  -i <interval>     Interval of timer, default: 0ms
 )";
 
 static int connections = 1000;
-static int duration = 10;
+static int duration = 10;   // s
 static int threads = 4;
+static int bytes = 0;       // byte
+static int interval = 0;    // ms
 
 static bool verbose = false;
 static const char* url = NULL;
@@ -48,6 +55,8 @@ typedef struct connection_s {
     uint64_t response_cnt;
     uint64_t ok_cnt;
     uint64_t readbytes;
+    uint64_t start_time;
+    std::vector<int> delays;
 
     connection_s()
         : parser(HttpParser::New(HTTP_CLIENT, HTTP_V1))
@@ -63,6 +72,7 @@ typedef struct connection_s {
     }
 
     void SendRequest() {
+        start_time = hloop_now_ms(hevent_loop(io));
         hio_write(io, request_msg.data(), request_msg.size());
         ++request_cnt;
         parser->InitResponse(response.get());
@@ -77,6 +87,8 @@ typedef struct connection_s {
             return false;
         }
         if (parser->IsComplete()) {
+            int delay = hloop_now_ms(hevent_loop(io)) - start_time;
+            delays.push_back(delay);
             ++response_cnt;
             if (response->status_code == HTTP_STATUS_OK) {
                 ++ok_cnt;
@@ -90,6 +102,7 @@ static connection_t** conns = NULL;
 
 static std::atomic<int> connected_num(0);
 static std::atomic<int> disconnected_num(0);
+static unsigned int connect_start_time = 0;
 
 static void print_help() {
     printf("Usage: wrk [%s] <url>\n", options);
@@ -106,6 +119,8 @@ static void print_result() {
     uint64_t total_response_cnt = 0;
     uint64_t total_ok_cnt = 0;
     uint64_t total_readbytes = 0;
+    uint64_t total_delay = 0;
+    std::vector<int> delays;
     connection_t* conn = NULL;
     for (int i = 0; i < connections; ++i) {
         conn = conns[i];
@@ -113,6 +128,11 @@ static void print_result() {
         total_response_cnt += conn->response_cnt;
         total_ok_cnt += conn->ok_cnt;
         total_readbytes += conn->readbytes;
+        delays.insert(delays.end(), conn->delays.begin(), conn->delays.end());
+    }
+    std::sort(delays.begin(), delays.end());
+    for (int i = 0; i < delays.size(); ++i) {
+        total_delay += delays[i];
     }
     printf("%llu requests, %llu OK, %lluMB read in %ds\n",
             LLU(total_request_cnt),
@@ -121,6 +141,19 @@ static void print_result() {
             duration);
     printf("Requests/sec: %8llu\n", LLU(total_response_cnt / duration));
     printf("Transfer/sec: %8lluMB\n", LLU((total_readbytes / duration) >> 20));
+    printf("Latency  avg: %8llums\n", LLU(total_delay / delays.size()));
+    printf("Percentage of the requests served within a certain time (ms)\n");
+    printf("    50%%    %d\n", delays[delays.size() * 0.5]);
+    printf("    60%%    %d\n", delays[delays.size() * 0.6]);
+    printf("    70%%    %d\n", delays[delays.size() * 0.7]);
+    printf("    80%%    %d\n", delays[delays.size() * 0.8]);
+    printf("    90%%    %d\n", delays[delays.size() * 0.9]);
+    printf("    95%%    %d\n", delays[delays.size() * 0.95]);
+    printf("    96%%    %d\n", delays[delays.size() * 0.96]);
+    printf("    97%%    %d\n", delays[delays.size() * 0.97]);
+    printf("    98%%    %d\n", delays[delays.size() * 0.98]);
+    printf("    99%%    %d\n", delays[delays.size() * 0.99]);
+    printf("   100%%    %d (longest delay)\n", delays.back());
 }
 
 static void start_reconnect(hio_t* io);
@@ -140,19 +173,30 @@ static void on_close(hio_t* io) {
 static void on_recv(hio_t* io, void* buf, int readbytes) {
     connection_t* conn = (connection_t*)hevent_userdata(io);
     if (conn->RecvResponse((const char*)buf, readbytes)) {
-        conn->SendRequest();
+        if (interval == 0) {
+            conn->SendRequest();
+        }
     }
 }
 
+static void send_heartbeat(hio_t* io) {
+    connection_t* conn = (connection_t*)hevent_userdata(io);
+    conn->SendRequest();
+}
+
 static void on_connect(hio_t* io) {
     if (++connected_num == connections) {
         if (verbose) {
-            printf("all connected\n");
+            printf("all connected in %ums\n", gettick_ms() - connect_start_time);
         }
     }
 
     connection_t* conn = (connection_t*)hevent_userdata(io);
-    conn->SendRequest();
+    if (interval == 0) {
+        conn->SendRequest();
+    } else {
+        hio_set_heartbeat(io, interval, send_heartbeat);
+    }
 
     hio_setcb_read(io, on_recv);
     hio_read(io);
@@ -203,10 +247,14 @@ int main(int argc, char** argv) {
     const char* strConnections = get_arg("c");
     const char* strDuration = get_arg("d");
     const char* strThreads = get_arg("t");
+    const char* strBytes = get_arg("b");
+    const char* strInterval = get_arg("i");
 
     if (strConnections) connections = atoi(strConnections);
     if (strDuration)    duration = atoi(strDuration);
     if (strThreads)     threads = atoi(strThreads);
+    if (strBytes)       bytes = atoi(strBytes);
+    if (strInterval)    interval = atoi(strInterval);
 
     print_cmd();
 
@@ -243,14 +291,19 @@ int main(int argc, char** argv) {
     // Dump request
     request->headers["User-Agent"] = std::string("libhv/") + hv_version();
     request->headers["Connection"] = "keep-alive";
+    if (bytes > 0) {
+        request->method = HTTP_POST;
+        request->body = std::string(bytes, 'a');
+    }
     request_msg = request->Dump(true, true);
-    printf("%s", request_msg.c_str());
+    printf("%.*s", int(request_msg.size() - request->body.size()), request_msg.c_str());
 
     // EventLoopThreadPool
     EventLoopThreadPool loop_threads(threads);
     loop_threads.start(true);
 
     // connections
+    connect_start_time = gettick_ms();
     conns = (connection_t**)malloc(sizeof(connection_t*) * connections);
     for (int i = 0; i < connections; ++i) {
         conns[i] = new connection_t;