Sponge
CS144's user-space TCP library
tcp_benchmark.cc
Go to the documentation of this file.
1 #include "tcp_connection.hh"
2 
3 #include <chrono>
4 #include <cstdlib>
5 #include <iomanip>
6 #include <iostream>
7 #include <string>
8 
9 using namespace std;
10 using namespace std::chrono;
11 
12 constexpr size_t len = 100 * 1024 * 1024;
13 
14 void move_segments(TCPConnection &x, TCPConnection &y, vector<TCPSegment> &segments, const bool reorder) {
15  while (not x.segments_out().empty()) {
16  segments.emplace_back(move(x.segments_out().front()));
17  x.segments_out().pop();
18  }
19  if (reorder) {
20  for (auto it = segments.rbegin(); it != segments.rend(); ++it) {
21  y.segment_received(move(*it));
22  }
23  } else {
24  for (auto it = segments.begin(); it != segments.end(); ++it) {
25  y.segment_received(move(*it));
26  }
27  }
28  segments.clear();
29 }
30 
31 void main_loop(const bool reorder) {
32  TCPConfig config;
33  TCPConnection x{config}, y{config};
34 
35  string string_to_send(len, 'x');
36  for (auto &ch : string_to_send) {
37  ch = rand();
38  }
39 
40  Buffer bytes_to_send{string(string_to_send)};
41  x.connect();
42  y.end_input_stream();
43 
44  bool x_closed = false;
45 
46  string string_received;
47  string_received.reserve(len);
48 
49  const auto first_time = high_resolution_clock::now();
50 
51  auto loop = [&] {
52  // write input into x
53  while (bytes_to_send.size() and x.remaining_outbound_capacity()) {
54  const auto want = min(x.remaining_outbound_capacity(), bytes_to_send.size());
55  const auto written = x.write(string(bytes_to_send.str().substr(0, want)));
56  if (want != written) {
57  throw runtime_error("want = " + to_string(want) + ", written = " + to_string(written));
58  }
59  bytes_to_send.remove_prefix(written);
60  }
61 
62  if (bytes_to_send.size() == 0 and not x_closed) {
63  x.end_input_stream();
64  x_closed = true;
65  }
66 
67  // exchange segments between x and y but in reverse order
68  vector<TCPSegment> segments;
69  move_segments(x, y, segments, reorder);
70  move_segments(y, x, segments, false);
71 
72  // read output from y
73  const auto available_output = y.inbound_stream().buffer_size();
74  if (available_output > 0) {
75  string_received.append(y.inbound_stream().read(available_output));
76  }
77 
78  // time passes
79  x.tick(1000);
80  y.tick(1000);
81  };
82 
83  while (not y.inbound_stream().eof()) {
84  loop();
85  }
86 
87  if (string_received != string_to_send) {
88  throw runtime_error("strings sent vs. received don't match");
89  }
90 
91  const auto final_time = high_resolution_clock::now();
92 
93  const auto duration = duration_cast<nanoseconds>(final_time - first_time).count();
94 
95  const auto gigabits_per_second = len * 8.0 / double(duration);
96 
97  cout << fixed << setprecision(2);
98  cout << "CPU-limited throughput" << (reorder ? " with reordering: " : " : ") << gigabits_per_second
99  << " Gbit/s\n";
100 
101  while (x.active() or y.active()) {
102  loop();
103  }
104 }
105 
106 int main() {
107  try {
108  main_loop(false);
109  main_loop(true);
110  } catch (const exception &e) {
111  cerr << e.what() << "\n";
112  return EXIT_FAILURE;
113  }
114 
115  return EXIT_SUCCESS;
116 }
std::setprecision
T setprecision(T... args)
std::string
std::exception
len
constexpr size_t len
Definition: tcp_benchmark.cc:12
std::move
T move(T... args)
TCPConnection::segments_out
std::queue< TCPSegment > & segments_out()
TCPSegments that the TCPConnection has enqueued for transmission.
Definition: tcp_connection.hh:75
std::string::reserve
T reserve(T... args)
TCPConnection
A complete endpoint of a TCP connection.
Definition: tcp_connection.hh:10
std::vector
std::chrono::duration
main_loop
void main_loop(const bool reorder)
Definition: tcp_benchmark.cc:31
main
int main()
Definition: tcp_benchmark.cc:106
std::queue::front
T front(T... args)
std::vector::clear
T clear(T... args)
tcp_connection.hh
TCPConnection::segment_received
void segment_received(const TCPSegment &seg)
Called when a new segment has been received from the network.
Definition: tcp_connection.cc:23
std::cout
Buffer
A reference-counted read-only string that can discard bytes from the front.
Definition: buffer.hh:14
std::queue::pop
T pop(T... args)
std::to_string
T to_string(T... args)
std::runtime_error
TCPConfig
Config for TCP sender and receiver.
Definition: tcp_config.hh:12
std::string::append
T append(T... args)
std::rand
T rand(T... args)
std::vector::rend
T rend(T... args)
std::min
T min(T... args)
std::vector::emplace_back
T emplace_back(T... args)
move_segments
void move_segments(TCPConnection &x, TCPConnection &y, vector< TCPSegment > &segments, const bool reorder)
Definition: tcp_benchmark.cc:14
std::vector::begin
T begin(T... args)
std
std::chrono::duration::count
T count(T... args)
std::fixed
T fixed(T... args)
std::queue::empty
T empty(T... args)
std::vector::end
T end(T... args)
std::exception::what
T what(T... args)
std::vector::rbegin
T rbegin(T... args)
std::chrono
std::chrono::high_resolution_clock::now
T now(T... args)