tcpperf.cc revision 14ca1249
114ca1249SShuo Chen#include "datetime/Timestamp.h"
214ca1249SShuo Chen#include "Acceptor.h"
314ca1249SShuo Chen#include "InetAddress.h"
414ca1249SShuo Chen#include "TcpStream.h"
514ca1249SShuo Chen
614ca1249SShuo Chen#ifdef __linux
714ca1249SShuo Chen#include <linux/tcp.h>
814ca1249SShuo Chen#else
914ca1249SShuo Chen#include <netinet/tcp.h>
1014ca1249SShuo Chen#endif
1114ca1249SShuo Chen#include <stdio.h>
1214ca1249SShuo Chen#include <stdlib.h>
1314ca1249SShuo Chen#include <unistd.h>
1414ca1249SShuo Chen
1514ca1249SShuo Chenusing muduo::Timestamp;
1614ca1249SShuo Chen
1714ca1249SShuo Chenclass BandwidthReporter
1814ca1249SShuo Chen{
1914ca1249SShuo Chen public:
2014ca1249SShuo Chen  BandwidthReporter(int fd, bool sender)
2114ca1249SShuo Chen      : fd_(fd), sender_(sender)
2214ca1249SShuo Chen  {
2314ca1249SShuo Chen  }
2414ca1249SShuo Chen
2514ca1249SShuo Chen  void reportDelta(double now, int64_t total_bytes)
2614ca1249SShuo Chen  {
2714ca1249SShuo Chen    report(now, total_bytes, total_bytes - last_bytes_, now - last_time_);
2814ca1249SShuo Chen    last_time_ = now;
2914ca1249SShuo Chen    last_bytes_ = total_bytes;
3014ca1249SShuo Chen  }
3114ca1249SShuo Chen
3214ca1249SShuo Chen  void reportAll(double now, int64_t total_bytes) const
3314ca1249SShuo Chen  {
3414ca1249SShuo Chen    report(now, total_bytes, total_bytes, now);
3514ca1249SShuo Chen  }
3614ca1249SShuo Chen
3714ca1249SShuo Chen private:
3814ca1249SShuo Chen  void report(double now, int64_t total_bytes, int64_t bytes, double elapsed) const
3914ca1249SShuo Chen  {
4014ca1249SShuo Chen    printf("%6.3f  %.3fM  %.3fM/s ", now, total_bytes / 1e6,
4114ca1249SShuo Chen           elapsed > 0 ? bytes / 1e6 / elapsed : 0.0);
4214ca1249SShuo Chen    if (sender_)
4314ca1249SShuo Chen      printSender();
4414ca1249SShuo Chen    else
4514ca1249SShuo Chen      printReceiver();
4614ca1249SShuo Chen  }
4714ca1249SShuo Chen
4814ca1249SShuo Chen  void printSender() const
4914ca1249SShuo Chen  {
5014ca1249SShuo Chen    int sndbuf = 0;
5114ca1249SShuo Chen    socklen_t optlen = sizeof sndbuf;
5214ca1249SShuo Chen    if (::getsockopt(fd_, SOL_SOCKET, SO_SNDBUF, &sndbuf, &optlen) < 0)
5314ca1249SShuo Chen      perror("getsockopt(SNDBUF)");
5414ca1249SShuo Chen
5514ca1249SShuo Chen    struct tcp_info tcpi = {0};
5614ca1249SShuo Chen    socklen_t len = sizeof(tcpi);
5714ca1249SShuo Chen    if (getsockopt(fd_, IPPROTO_TCP, TCP_INFO, &tcpi, &len) < 0)
5814ca1249SShuo Chen      perror("getsockopt(TCP_INFO)");
5914ca1249SShuo Chen
6014ca1249SShuo Chen    // bytes_in_flight = tcpi.tcpi_bytes_sent - tcpi.tcpi_bytes_acked;
6114ca1249SShuo Chen    // tcpi.tcpi_notsent_bytes;
6214ca1249SShuo Chen
6314ca1249SShuo Chen    printf(" sndbuf=%.1fK snd_wnd=%.1fK rtt=%d/%d\n",
6414ca1249SShuo Chen           sndbuf / 1024.0, tcpi.tcpi_snd_wnd / 1024.0,
6514ca1249SShuo Chen           tcpi.tcpi_rtt, tcpi.tcpi_rttvar);
6614ca1249SShuo Chen  }
6714ca1249SShuo Chen
6814ca1249SShuo Chen  void printReceiver() const
6914ca1249SShuo Chen  {
7014ca1249SShuo Chen    int rcvbuf = 0;
7114ca1249SShuo Chen    socklen_t optlen = sizeof rcvbuf;
7214ca1249SShuo Chen    if (::getsockopt(fd_, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
7314ca1249SShuo Chen      perror("getsockopt(RCVBUF)");
7414ca1249SShuo Chen
7514ca1249SShuo Chen    printf(" rcvbuf=%.1fK\n", rcvbuf / 1024.0);
7614ca1249SShuo Chen  }
7714ca1249SShuo Chen
7814ca1249SShuo Chen  const int fd_ = 0;
7914ca1249SShuo Chen  const bool sender_ = false;
8014ca1249SShuo Chen  double last_time_ = 0;
8114ca1249SShuo Chen  int64_t last_bytes_ = 0;
8214ca1249SShuo Chen};
8314ca1249SShuo Chen
8414ca1249SShuo Chenvoid runClient(const InetAddress& serverAddr, int64_t bytes_limit, double duration)
8514ca1249SShuo Chen{
8614ca1249SShuo Chen  TcpStreamPtr stream(TcpStream::connect(serverAddr));
8714ca1249SShuo Chen  if (!stream) {
8814ca1249SShuo Chen    printf("Unable to connect %s\n", serverAddr.toIpPort().c_str());
8914ca1249SShuo Chen    perror("");
9014ca1249SShuo Chen    return;
9114ca1249SShuo Chen  }
9214ca1249SShuo Chen
9314ca1249SShuo Chen  const Timestamp start = Timestamp::now();
9414ca1249SShuo Chen  const int block_size = 64 * 1024;
9514ca1249SShuo Chen  std::string message(block_size, 'S');
9614ca1249SShuo Chen  int seconds = 1;
9714ca1249SShuo Chen  int64_t total_bytes = 0;
9814ca1249SShuo Chen  double elapsed = 0;
9914ca1249SShuo Chen  BandwidthReporter rpt(stream->fd(), true);
10014ca1249SShuo Chen  rpt.reportAll(0, 0);
10114ca1249SShuo Chen
10214ca1249SShuo Chen  while (total_bytes < bytes_limit) {
10314ca1249SShuo Chen    int nw = stream->sendAll(message.data(), message.size());
10414ca1249SShuo Chen    if (nw <= 0)
10514ca1249SShuo Chen      break;
10614ca1249SShuo Chen    total_bytes += nw;
10714ca1249SShuo Chen    elapsed = timeDifference(Timestamp::now(), start);
10814ca1249SShuo Chen
10914ca1249SShuo Chen    if (elapsed >= duration)
11014ca1249SShuo Chen      break;
11114ca1249SShuo Chen
11214ca1249SShuo Chen    if (elapsed >= seconds) {
11314ca1249SShuo Chen      rpt.reportDelta(elapsed, total_bytes);
11414ca1249SShuo Chen      while (elapsed >= seconds)
11514ca1249SShuo Chen        ++seconds;
11614ca1249SShuo Chen    }
11714ca1249SShuo Chen  }
11814ca1249SShuo Chen
11914ca1249SShuo Chen  stream->shutdownWrite();
12014ca1249SShuo Chen  Timestamp shutdown = Timestamp::now();
12114ca1249SShuo Chen  elapsed = timeDifference(shutdown, start);
12214ca1249SShuo Chen  rpt.reportDelta(elapsed, total_bytes);
12314ca1249SShuo Chen
12414ca1249SShuo Chen  char buf[1024];
12514ca1249SShuo Chen  int nr = stream->receiveSome(buf, sizeof buf);
12614ca1249SShuo Chen  if (nr != 0)
12714ca1249SShuo Chen    printf("nr = %d\n", nr);
12814ca1249SShuo Chen  Timestamp end = Timestamp::now();
12914ca1249SShuo Chen  elapsed = timeDifference(end, start);
13014ca1249SShuo Chen  rpt.reportAll(elapsed, total_bytes);
13114ca1249SShuo Chen}
13214ca1249SShuo Chen
13314ca1249SShuo Chenvoid runServer(int port)
13414ca1249SShuo Chen{
13514ca1249SShuo Chen  InetAddress listenAddr(port);
13614ca1249SShuo Chen  Acceptor acceptor(listenAddr);
13714ca1249SShuo Chen  int count = 0;
13814ca1249SShuo Chen  while (true) {
13914ca1249SShuo Chen    printf("Accepting on port %d ... Ctrl-C to exit\n", port);
14014ca1249SShuo Chen    TcpStreamPtr stream = acceptor.accept();
14114ca1249SShuo Chen    printf("accepted no. %d client\n", ++count);
14214ca1249SShuo Chen
14314ca1249SShuo Chen    const Timestamp start = Timestamp::now();
14414ca1249SShuo Chen    int seconds = 1;
14514ca1249SShuo Chen    int64_t bytes = 0;
14614ca1249SShuo Chen    double elapsed = 0;
14714ca1249SShuo Chen    BandwidthReporter rpt(stream->fd(), false);
14814ca1249SShuo Chen    rpt.reportAll(elapsed, bytes);
14914ca1249SShuo Chen
15014ca1249SShuo Chen    char buf[65536];
15114ca1249SShuo Chen    while (true) {
15214ca1249SShuo Chen      int nr = stream->receiveSome(buf, sizeof buf);
15314ca1249SShuo Chen      if (nr <= 0)
15414ca1249SShuo Chen        break;
15514ca1249SShuo Chen      bytes += nr;
15614ca1249SShuo Chen
15714ca1249SShuo Chen      elapsed = timeDifference(Timestamp::now(), start);
15814ca1249SShuo Chen      if (elapsed >= seconds) {
15914ca1249SShuo Chen        rpt.reportDelta(elapsed, bytes);
16014ca1249SShuo Chen        while (elapsed >= seconds)
16114ca1249SShuo Chen          ++seconds;
16214ca1249SShuo Chen      }
16314ca1249SShuo Chen    }
16414ca1249SShuo Chen    elapsed = timeDifference(Timestamp::now(), start);
16514ca1249SShuo Chen    rpt.reportAll(elapsed, bytes);
16614ca1249SShuo Chen    printf("Client no. %d done\n", count);
16714ca1249SShuo Chen  }
16814ca1249SShuo Chen}
16914ca1249SShuo Chen
17014ca1249SShuo Chenint main(int argc, char* argv[])
17114ca1249SShuo Chen{
17214ca1249SShuo Chen  int opt;
17314ca1249SShuo Chen  bool client = false, server = false;
17414ca1249SShuo Chen  InetAddress serverAddr;
17514ca1249SShuo Chen  const int port = 2009;
17614ca1249SShuo Chen  const int64_t kGigaBytes = 1024 * 1024 * 1024;
17714ca1249SShuo Chen  int64_t bytes_limit = 10 * kGigaBytes;
17814ca1249SShuo Chen  double duration = 10;
17914ca1249SShuo Chen
18014ca1249SShuo Chen  while ((opt = getopt(argc, argv, "sc:")) != -1) {
18114ca1249SShuo Chen    switch (opt) {
18214ca1249SShuo Chen      case 's':
18314ca1249SShuo Chen        server = true;
18414ca1249SShuo Chen        break;
18514ca1249SShuo Chen      case 'c':
18614ca1249SShuo Chen        client = true;
18714ca1249SShuo Chen        serverAddr = InetAddress(optarg, port);
18814ca1249SShuo Chen        break;
18914ca1249SShuo Chen      default:
19014ca1249SShuo Chen        fprintf(stderr, "Usage: %s FIXME\n", argv[0]);
19114ca1249SShuo Chen        break;
19214ca1249SShuo Chen    }
19314ca1249SShuo Chen  }
19414ca1249SShuo Chen
19514ca1249SShuo Chen  if (client)
19614ca1249SShuo Chen    runClient(serverAddr, bytes_limit, duration);
19714ca1249SShuo Chen  else if (server)
19814ca1249SShuo Chen    runServer(port);
19914ca1249SShuo Chen}
200