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