1 //
2 // udp_client.cpp
3 // ~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2015 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 <boost/asio/ip/udp.hpp>
12 #include <boost/date_time/posix_time/posix_time_types.hpp>
13 #include <algorithm>
14 #include <cstdio>
15 #include <cstdlib>
16 #include <cstring>
17 #include <vector>
18 #include "high_res_clock.hpp"
19 
20 using boost::asio::ip::udp;
21 using boost::posix_time::ptime;
22 using boost::posix_time::microsec_clock;
23 
24 const int num_samples = 100000;
25 
main(int argc,char * argv[])26 int main(int argc, char* argv[])
27 {
28   if (argc != 6)
29   {
30     std::fprintf(stderr,
31         "Usage: udp_client <ip> <port1> "
32         "<nports> <bufsize> {spin|block}\n");
33     return 1;
34   }
35 
36   const char* ip = argv[1];
37   unsigned short first_port = static_cast<unsigned short>(std::atoi(argv[2]));
38   unsigned short num_ports = static_cast<unsigned short>(std::atoi(argv[3]));
39   std::size_t buf_size = static_cast<std::size_t>(std::atoi(argv[4]));
40   bool spin = (std::strcmp(argv[5], "spin") == 0);
41 
42   boost::asio::io_service io_service;
43 
44   udp::socket socket(io_service, udp::endpoint(udp::v4(), 0));
45 
46   if (spin)
47   {
48     udp::socket::non_blocking_io nbio(true);
49     socket.io_control(nbio);
50   }
51 
52   udp::endpoint target(boost::asio::ip::address::from_string(ip), first_port);
53   unsigned short last_port = first_port + num_ports - 1;
54   std::vector<unsigned char> write_buf(buf_size);
55   std::vector<unsigned char> read_buf(buf_size);
56 
57   ptime start = microsec_clock::universal_time();
58   boost::uint64_t start_hr = high_res_clock();
59 
60   boost::uint64_t samples[num_samples];
61   for (int i = 0; i < num_samples; ++i)
62   {
63     boost::uint64_t t = high_res_clock();
64 
65     boost::system::error_code ec;
66     socket.send_to(boost::asio::buffer(write_buf), target, 0, ec);
67 
68     do socket.receive(boost::asio::buffer(read_buf), 0, ec);
69     while (ec == boost::asio::error::would_block);
70 
71     samples[i] = high_res_clock() - t;
72 
73     if (target.port() == last_port)
74       target.port(first_port);
75     else
76       target.port(target.port() + 1);
77   }
78 
79   ptime stop = microsec_clock::universal_time();
80   boost::uint64_t stop_hr = high_res_clock();
81   boost::uint64_t elapsed_usec = (stop - start).total_microseconds();
82   boost::uint64_t elapsed_hr = stop_hr - start_hr;
83   double scale = 1.0 * elapsed_usec / elapsed_hr;
84 
85   std::sort(samples, samples + num_samples);
86   std::printf("  0.0%%\t%f\n", samples[0] * scale);
87   std::printf("  0.1%%\t%f\n", samples[num_samples / 1000 - 1] * scale);
88   std::printf("  1.0%%\t%f\n", samples[num_samples / 100 - 1] * scale);
89   std::printf(" 10.0%%\t%f\n", samples[num_samples / 10 - 1] * scale);
90   std::printf(" 20.0%%\t%f\n", samples[num_samples * 2 / 10 - 1] * scale);
91   std::printf(" 30.0%%\t%f\n", samples[num_samples * 3 / 10 - 1] * scale);
92   std::printf(" 40.0%%\t%f\n", samples[num_samples * 4 / 10 - 1] * scale);
93   std::printf(" 50.0%%\t%f\n", samples[num_samples * 5 / 10 - 1] * scale);
94   std::printf(" 60.0%%\t%f\n", samples[num_samples * 6 / 10 - 1] * scale);
95   std::printf(" 70.0%%\t%f\n", samples[num_samples * 7 / 10 - 1] * scale);
96   std::printf(" 80.0%%\t%f\n", samples[num_samples * 8 / 10 - 1] * scale);
97   std::printf(" 90.0%%\t%f\n", samples[num_samples * 9 / 10 - 1] * scale);
98   std::printf(" 99.0%%\t%f\n", samples[num_samples * 99 / 100 - 1] * scale);
99   std::printf(" 99.9%%\t%f\n", samples[num_samples * 999 / 1000 - 1] * scale);
100   std::printf("100.0%%\t%f\n", samples[num_samples - 1] * scale);
101 
102   double total = 0.0;
103   for (int i = 0; i < num_samples; ++i) total += samples[i] * scale;
104   std::printf("  mean\t%f\n", total / num_samples);
105 }
106