1 //
2 // tcp_client.cpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10 
11 #include <asio/ip/tcp.hpp>
12 #include <asio/read.hpp>
13 #include <asio/write.hpp>
14 #include <boost/date_time/posix_time/posix_time_types.hpp>
15 #include <boost/shared_ptr.hpp>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <cstring>
19 #include <vector>
20 #include "high_res_clock.hpp"
21 
22 using asio::ip::tcp;
23 using boost::posix_time::ptime;
24 using boost::posix_time::microsec_clock;
25 
26 const int num_samples = 100000;
27 
28 struct transfer_all
29 {
30   typedef std::size_t result_type;
operator ()transfer_all31   std::size_t operator()(const asio::error_code& ec, std::size_t)
32   {
33     return (ec && ec != asio::error::would_block) ? 0 : ~0;
34   }
35 };
36 
main(int argc,char * argv[])37 int main(int argc, char* argv[])
38 {
39   if (argc != 6)
40   {
41     std::fprintf(stderr,
42         "Usage: tcp_client <ip> <port> "
43         "<nconns> <bufsize> {spin|block}\n");
44     return 1;
45   }
46 
47   const char* ip = argv[1];
48   unsigned short port = static_cast<unsigned short>(std::atoi(argv[2]));
49   int num_connections = std::atoi(argv[3]);
50   std::size_t buf_size = static_cast<std::size_t>(std::atoi(argv[4]));
51   bool spin = (std::strcmp(argv[5], "spin") == 0);
52 
53   asio::io_context io_context;
54   std::vector<boost::shared_ptr<tcp::socket> > sockets;
55 
56   for (int i = 0; i < num_connections; ++i)
57   {
58     boost::shared_ptr<tcp::socket> s(new tcp::socket(io_context));
59 
60     tcp::endpoint target(asio::ip::make_address(ip), port);
61     s->connect(target);
62 
63     s->set_option(tcp::no_delay(true));
64 
65     if (spin)
66     {
67       s->non_blocking(true);
68     }
69 
70     sockets.push_back(s);
71   }
72 
73   std::vector<unsigned char> write_buf(buf_size);
74   std::vector<unsigned char> read_buf(buf_size);
75 
76   ptime start = microsec_clock::universal_time();
77   boost::uint64_t start_hr = high_res_clock();
78 
79   boost::uint64_t samples[num_samples];
80   for (int i = 0; i < num_samples; ++i)
81   {
82     tcp::socket& socket = *sockets[i % num_connections];
83 
84     boost::uint64_t t = high_res_clock();
85 
86     asio::error_code ec;
87     asio::write(socket,
88         asio::buffer(write_buf),
89         transfer_all(), ec);
90 
91     asio::read(socket,
92         asio::buffer(read_buf),
93         transfer_all(), ec);
94 
95     samples[i] = high_res_clock() - t;
96   }
97 
98   ptime stop = microsec_clock::universal_time();
99   boost::uint64_t stop_hr = high_res_clock();
100   boost::uint64_t elapsed_usec = (stop - start).total_microseconds();
101   boost::uint64_t elapsed_hr = stop_hr - start_hr;
102   double scale = 1.0 * elapsed_usec / elapsed_hr;
103 
104   std::sort(samples, samples + num_samples);
105   std::printf("  0.0%%\t%f\n", samples[0] * scale);
106   std::printf("  0.1%%\t%f\n", samples[num_samples / 1000 - 1] * scale);
107   std::printf("  1.0%%\t%f\n", samples[num_samples / 100 - 1] * scale);
108   std::printf(" 10.0%%\t%f\n", samples[num_samples / 10 - 1] * scale);
109   std::printf(" 20.0%%\t%f\n", samples[num_samples * 2 / 10 - 1] * scale);
110   std::printf(" 30.0%%\t%f\n", samples[num_samples * 3 / 10 - 1] * scale);
111   std::printf(" 40.0%%\t%f\n", samples[num_samples * 4 / 10 - 1] * scale);
112   std::printf(" 50.0%%\t%f\n", samples[num_samples * 5 / 10 - 1] * scale);
113   std::printf(" 60.0%%\t%f\n", samples[num_samples * 6 / 10 - 1] * scale);
114   std::printf(" 70.0%%\t%f\n", samples[num_samples * 7 / 10 - 1] * scale);
115   std::printf(" 80.0%%\t%f\n", samples[num_samples * 8 / 10 - 1] * scale);
116   std::printf(" 90.0%%\t%f\n", samples[num_samples * 9 / 10 - 1] * scale);
117   std::printf(" 99.0%%\t%f\n", samples[num_samples * 99 / 100 - 1] * scale);
118   std::printf(" 99.9%%\t%f\n", samples[num_samples * 999 / 1000 - 1] * scale);
119   std::printf("100.0%%\t%f\n", samples[num_samples - 1] * scale);
120 
121   double total = 0.0;
122   for (int i = 0; i < num_samples; ++i) total += samples[i] * scale;
123   std::printf("  mean\t%f\n", total / num_samples);
124 }
125