Differences

This shows you the differences between the selected revision and the current version of the page.

en:scytheman:zeugs:code:bandwidthtool 2010/03/06 14:44 en:scytheman:zeugs:code:bandwidthtool 2010/08/22 18:53 current
Line 1: Line 1:
 +[[en:scytheman|↑ up]]
 +
====== bandwidthTool ====== ====== bandwidthTool ======
===== Description ===== ===== Description =====
-bandwidthTool is a tiny program to measure the end to end capacity (bottleneck bandwidth) of a path with the help of the ''packet train dispersion technique''. The main idea is to send multiple packet pairs/trains from one end to the other consisting of multiple packets of the same size sent back-to-back. Then, the dispersion (distance between the last bit of the first and last packet) is measured, corresponding to the capacity if the links do not carry other traffic. Cross-traffic can increase or decrease the measured dispersion, causing under- or overestimation of the path capacity.+{{scytheman:zeugs:bandwidthtool.tar.gz|bandwidthTool}} is a tiny program to measure the //end to end capacity// (bottleneck bandwidth) of a path with the help of the //packet train dispersion technique//. The main idea is to send multiple packet pairs/trains from one end to the other consisting of multiple packets of the same size sent back-to-back. Then, the dispersion (distance between the last bit of the first and last packet) is measured, corresponding to the capacity if the links do not carry other traffic (see figure). Cross-traffic can increase or decrease the measured dispersion, causing under- or overestimation of the path capacity. 
 + 
 +{{scytheman:zeugs:code:packet_pairs.png|packet pair technique}}
Measurements can be adapted by either changing the packet size or using different train lengths. Using the default settings below, //800 * 15 bytes (11.7 KiB)// are sufficient for one single measurement. Measurements can be adapted by either changing the packet size or using different train lengths. Using the default settings below, //800 * 15 bytes (11.7 KiB)// are sufficient for one single measurement.
Line 53: Line 57:
// number of packets per train // number of packets per train
#define TRAIN_LEN 15 #define TRAIN_LEN 15
- 
-class SOBandwidthTool 
-{ 
-    private: 
-        /// time difference in micro seconds 
-        int timeDiff(const struct timeval& tv1, const struct timeval& tv2); 
-     
-    public: 
-        int receiver(const std::string& hostAddr); 
-        int sender(); 
-}; 
/// time difference in micro seconds /// time difference in micro seconds
Line 70: Line 63:
} }
-int SOBandwidthTool::receiver(const std::string& hostAddr) { +int SOBandwidthTool::receiver(const std::string& hostAddr) {  
-    // get host address +    // get host address list 
-    struct addrinfo* addr+    struct addrinfo hints; 
-    int err = getaddrinfo(hostAddr.c_str(), 0, 0, &addr);+    memset(&hints, 0, sizeof(struct addrinfo)); 
 +    hints.ai_socktype = SOCK_STREAM; 
 +    std::stringstream cport; 
 +    cport << TCP_PORT; 
 +    struct addrinfo* addrList
 +    int err = getaddrinfo(hostAddr.c_str(), cport.str().c_str(), &hints, &addrList);
    if(err != 0) {     if(err != 0) {
        std::cerr << "Error: Could not resolve host address: " << gai_strerror(err) << std::endl;         std::cerr << "Error: Could not resolve host address: " << gai_strerror(err) << std::endl;
Line 87: Line 85:
       
    int opt = 1;     int opt = 1;
-    if (setsockopt(tcpSock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) == -1) {+    if(setsockopt(tcpSock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) == -1) {
        std::cerr << "Error: Could not set SO_REUSEADDR on TCP socket: " << strerror(errno) << std::endl;         std::cerr << "Error: Could not set SO_REUSEADDR on TCP socket: " << strerror(errno) << std::endl;
 +        close(tcpSock);
        return -1;         return -1;
    }     }
       
-    struct sockaddr_in tcpAddr+    // getaddrinfo() returns a list of addresses, try each until connect() succeeds 
-    memset(&;tcpAddr, 0, sizeof tcpAddr); +    struct addrinfo* addr
-    tcpAddr.sin_family      = AF_INET+    for(addr = addrList; addr != NULL; addr = addr->;ai_next) { 
-   tcpAddr.sin_addr.s_addr = ((struct sockaddr_in*)addr->ai_addr)->sin_addr.s_addr; +       std::cout << "Trying to connect to " << inet_ntoa(((struct sockaddr_in*)addr->ai_addr)->sin_addr) 
-    tcpAddr.sin_port        = htons(TCP_PORT); +                 << ":" << ntohs(((struct sockaddr_in*)addr->ai_addr)->sin_port) << std::endl; 
-    +       if(connect(tcpSock, addr-&gt;ai_addr, addr->ai_addrlen) != -1) { 
-    std::cout << "Trying to connect to TCP socket on " << hostAddr << std::endl; +            // got right address, keep pointer for udp socket later 
-   if(connect(tcpSock, (struct sockaddr*)&amp;tcpAddr, sizeof(tcpAddr)) == -1) { +            break; 
-        std::cerr << "Error: Could not connect TCP socket: " << strerror(errno) << std::endl;+        } 
 +    } 
 + 
 +    if(addr == NULL) { 
 +        std::cerr << "Error: Could not connect to host " << hostAddr << std::endl
 +        close(tcpSock);
        return -1;         return -1;
    }     }
Line 110: Line 114:
    struct timeval now, last;     struct timeval now, last;
    int msg = 42;     int msg = 42;
-    std::cout << "Measuring RTT." << std::endl;+    std::cout << "Measuring RTT: ";
    for(unsigned int i = 0; i < RTT_PROBES; i++) {     for(unsigned int i = 0; i < RTT_PROBES; i++) {
        // transmit message         // transmit message
        if(send(tcpSock, &msg, sizeof(msg), 0) != sizeof(msg)) {         if(send(tcpSock, &msg, sizeof(msg), 0) != sizeof(msg)) {
            std::cerr << "Error: Could not send on TCP socket: " << strerror(errno) << std::endl;             std::cerr << "Error: Could not send on TCP socket: " << strerror(errno) << std::endl;
 +            close(tcpSock);
            return -1;             return -1;
        }         }
Line 123: Line 128:
        if(recv(tcpSock, buf, sizeof(msg), 0) != sizeof(msg)) {         if(recv(tcpSock, buf, sizeof(msg), 0) != sizeof(msg)) {
            std::cerr << "Error: Could not receive on TCP socket: " << strerror(errno) << std::endl;             std::cerr << "Error: Could not receive on TCP socket: " << strerror(errno) << std::endl;
 +            close(tcpSock);
            return -1;             return -1;
        }         }
Line 130: Line 136:
            int duration = timeDiff(last, now);             int duration = timeDiff(last, now);
            totalRtt += duration;             totalRtt += duration;
-            std::cout << duration / 1000.0 << "ms\t" << std::flush;+            std::cout << duration / 1000.0 << " ms " << std::flush;
        }         }
    }     }
Line 137: Line 143:
       
    double rtt = totalRtt / ((RTT_PROBES - 2) * 1000.0);     double rtt = totalRtt / ((RTT_PROBES - 2) * 1000.0);
-    std::cout << "Average RTT is " << rtt << "ms" << std::endl;+    std::cout << "Average RTT is " << rtt << " ms" << std::endl;
       
    //     //
Line 168: Line 174:
        if(sendto(udpSock, packet.c_str(), PACKET_LEN, 0, (struct sockaddr*)&udpAddr, sizeof(udpAddr)) != PACKET_LEN) {         if(sendto(udpSock, packet.c_str(), PACKET_LEN, 0, (struct sockaddr*)&udpAddr, sizeof(udpAddr)) != PACKET_LEN) {
            std::cerr << "Error: Could not send on UDP socket: " << strerror(errno) << std::endl;             std::cerr << "Error: Could not send on UDP socket: " << strerror(errno) << std::endl;
 +            close(udpSock);
            return -1;             return -1;
        }         }
Line 186: Line 193:
       
    int opt = 1;     int opt = 1;
-    if (setsockopt(tcpSock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) == -1) {+    if(setsockopt(tcpSock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) == -1) {
        std::cerr << "Error: Could not set SO_REUSEADDR on TCP socket: " << strerror(errno) << std::endl;         std::cerr << "Error: Could not set SO_REUSEADDR on TCP socket: " << strerror(errno) << std::endl;
 +        close(tcpSock);
        return -1;         return -1;
    }     }
Line 198: Line 206:
    if(bind(tcpSock, (struct sockaddr*)&tcpAddr, sizeof(tcpAddr)) == -1) {     if(bind(tcpSock, (struct sockaddr*)&tcpAddr, sizeof(tcpAddr)) == -1) {
        std::cerr << "Error: Could not bind TCP socket: " << strerror(errno) << std::endl;         std::cerr << "Error: Could not bind TCP socket: " << strerror(errno) << std::endl;
 +        close(tcpSock);
        return -1;         return -1;
    }     }
-    std::cout << "Listening on TCP socket." << std::endl; +    std::cout << "Listening on TCP socket on port " << TCP_PORT << std::endl; 
-    if (listen(tcpSock, 1) == -1) {+    if(listen(tcpSock, 1) == -1) {
        std::cerr << "Error: Could not listen on TCP socket: " << strerror(errno) << std::endl;         std::cerr << "Error: Could not listen on TCP socket: " << strerror(errno) << std::endl;
 +        close(tcpSock);
        return -1;         return -1;
    }     }
       
-    int conSock;;+    int conSock;
    socklen_t tcpAddrLen = sizeof(tcpAddr);     socklen_t tcpAddrLen = sizeof(tcpAddr);
    if((conSock = accept(tcpSock, (struct sockaddr*)&tcpAddr, &tcpAddrLen)) == -1) {     if((conSock = accept(tcpSock, (struct sockaddr*)&tcpAddr, &tcpAddrLen)) == -1) {
        std::cerr << "Error: Could not accept TCP connection: " << strerror(errno) << std::endl;         std::cerr << "Error: Could not accept TCP connection: " << strerror(errno) << std::endl;
 +        close(tcpSock);
        return -1;         return -1;
    }     }
Line 224: Line 235:
        if(recv(conSock, buf, sizeof(msg), 0) != sizeof(msg)) {         if(recv(conSock, buf, sizeof(msg), 0) != sizeof(msg)) {
            std::cerr << "Error: Could not receive on TCP socket: " << strerror(errno) << std::endl;             std::cerr << "Error: Could not receive on TCP socket: " << strerror(errno) << std::endl;
 +            close(tcpSock);
            return -1;             return -1;
        }         }
Line 229: Line 241:
        if(send(conSock, &msg, sizeof(msg), 0) != sizeof(msg)) {         if(send(conSock, &msg, sizeof(msg), 0) != sizeof(msg)) {
            std::cerr << "Error: Could not send on TCP socket: " << strerror(errno) << std::endl;             std::cerr << "Error: Could not send on TCP socket: " << strerror(errno) << std::endl;
 +            close(tcpSock);
            return -1;             return -1;
        }         }
Line 254: Line 267:
    if(bind(udpSock, (struct sockaddr*)&udpAddr, sizeof(udpAddr)) == -1) {     if(bind(udpSock, (struct sockaddr*)&udpAddr, sizeof(udpAddr)) == -1) {
        std::cerr << "Error: Could not bind UDP socket: " << strerror(errno) << std::endl;         std::cerr << "Error: Could not bind UDP socket: " << strerror(errno) << std::endl;
 +        close(udpSock);
        return -1;         return -1;
    }     }
Line 266: Line 280:
        if(recvfrom(udpSock, recvMsg, PACKET_LEN, 0, (struct sockaddr*)&udpAddr, &udpAddrLen) != PACKET_LEN) {         if(recvfrom(udpSock, recvMsg, PACKET_LEN, 0, (struct sockaddr*)&udpAddr, &udpAddrLen) != PACKET_LEN) {
            std::cerr << "Error: Could not receive on UDP socket: " << strerror(errno) << std::endl;             std::cerr << "Error: Could not receive on UDP socket: " << strerror(errno) << std::endl;
 +            close(udpSock);
            return -1;             return -1;
        }         }
Line 279: Line 294:
    int    diff_ns = timeDiff(first, last) * 1000;     int    diff_ns = timeDiff(first, last) * 1000;
    double diff_s  = timeDiff(first, last) / 1000.0 / 1000.0;     double diff_s  = timeDiff(first, last) / 1000.0 / 1000.0;
-    std::cout << "Duration: " << diff_ns << "ns" << " = " << diff_ns / 1000.0 / 1000.0 << "ms" << std::endl;+    std::cout << "Duration: " 
 +              << diff_ns << " ns = " 
 +              << diff_ns / 1000.0 / 1000.0 << " ms" << std::endl;
       
    double disp_s = ((TRAIN_LEN - 1) * PACKET_LEN) / double(diff_s);     double disp_s = ((TRAIN_LEN - 1) * PACKET_LEN) / double(diff_s);
-    std::cout << "Dispersion: " << disp_s / 1000.0 << "ms" << std::endl; +    std::cout << "Dispersion: " << disp_s / 1000.0 << " ms" << std::endl; 
-    std::cout << "Capacity: " << disp_s << "b/s = " << disp_s / 1024.0 / 1024.0 << "MB/s" << std::endl;+    std::cout << "Capacity: " 
 +              << disp_s * 8.0 << " bit/s = " 
 +              << disp_s * 8.0 / 1000.0 << " kbit/s = " 
 +              << disp_s * 8.0 / 1000.0 / 1000.0 << " Mbit/s = " 
 +              << disp_s * 8.0 / 1000.0 / 1000.0 / 1000.0 << " Gbit/s" << std::endl;
       
    return 0;     return 0;
Line 310: Line 331:
            bw.sender();             bw.sender();
        } else if(*it == "-r" || *it == "--receive") {         } else if(*it == "-r" || *it == "--receive") {
-            if (++it < args.end()) {+            if(++it < args.end()) {
                bw.receiver(*it);                 bw.receiver(*it);
            } else {             } else {
Line 332: Line 353:
===== Analysis ===== ===== Analysis =====
 +
 +To analyze the capacity estimation method, different scenarios were tested with 100 measurements for each of them.
  * capacity: the capacity of the bottleneck link (there may be other links with higher capacity on the path)   * capacity: the capacity of the bottleneck link (there may be other links with higher capacity on the path)
Line 341: Line 364:
|  192 kbit |  light  |  177.947 kbit |  178.374 kbit |  177.063 kbit |  216.482 kbit | |  192 kbit |  light  |  177.947 kbit |  178.374 kbit |  177.063 kbit |  216.482 kbit |
|  2 Mbit |  light  |  1.830 Mbit |  1.830 Mbit |  1.396 Mbit |  2.549 Mbit | |  2 Mbit |  light  |  1.830 Mbit |  1.830 Mbit |  1.396 Mbit |  2.549 Mbit |
 +|  2 Mbit |  heavy  |  1.821 Mbit |  1.802 Mbit |  1.359 Mbit |  2.252 Mbit |
|  100 Mbit |  light  |  89.960 Mbit |  90.278 Mbit |  84.929 Mbit |  95.624 Mbit | |  100 Mbit |  light  |  89.960 Mbit |  90.278 Mbit |  84.929 Mbit |  95.624 Mbit |
|  100 Mbit |  heavy  |  90.504 Mbit |  201.605 Mbit |  72.846 Mbit |  1518.648 Mbit | |  100 Mbit |  heavy  |  90.504 Mbit |  201.605 Mbit |  72.846 Mbit |  1518.648 Mbit |
-This table shows, that cross-traffic can influence measurements heavily. Yet, the median is stable enough to rely on it, providing no overestimation of the capacity.+As this table shows, cross-traffic can influence measurements heavily (especially in the 100 Mbit scenario). Yet, the median is stable enough to rely on it, providing no overestimation of the capacity. 
==== WLAN ==== ==== WLAN ====
Line 352: Line 377:
|  24 Mbit |  heavy  |  19.885 Mbit |  17.090 Mbit |  1.839 Mbit |  23.449 Mbit | |  24 Mbit |  heavy  |  19.885 Mbit |  17.090 Mbit |  1.839 Mbit |  23.449 Mbit |
-Here, cross-traffic also leads to significant measurement errors. But also light cross-traffic leads to a higher variance compared to LAN.+Here, (even light) cross-traffic leads to significant measurement errors. Nevertheless the median is quite stable and provides an adequate capacity estimation.
Note: As there is no constant medium using wireless networks, the capacity was measured using ''iperf''. Note: As there is no constant medium using wireless networks, the capacity was measured using ''iperf''.
==== Figures ==== ==== Figures ====
 +
 +The following figures illustrate the measured capacities (100 tests each). Also note the y-axis when comparing two similar looking plots.
=== LAN === === LAN ===
Line 362: Line 389:
192kbit: 192kbit:
[[http://choerbaert.org/wiki/_media/scytheman:zeugs:code:bw_lan_ct_192kbit.png|{{scytheman:zeugs:code:bw_lan_ct_192kbit_thb.png}}]] [[http://choerbaert.org/wiki/_media/scytheman:zeugs:code:bw_lan_ct_192kbit.png|{{scytheman:zeugs:code:bw_lan_ct_192kbit_thb.png}}]]
 +
2Mbit: 2Mbit:
 +[[http://choerbaert.org/wiki/_media/scytheman:zeugs:code:bw_lan_2mbit.png|{{scytheman:zeugs:code:bw_lan_2mbit_thb.png}}]]
 +2Mbit (cross-traffic):
[[http://choerbaert.org/wiki/_media/scytheman:zeugs:code:bw_lan_ct_2mbit.png|{{scytheman:zeugs:code:bw_lan_ct_2mbit_thb.png}}]] [[http://choerbaert.org/wiki/_media/scytheman:zeugs:code:bw_lan_ct_2mbit.png|{{scytheman:zeugs:code:bw_lan_ct_2mbit_thb.png}}]]
 +
100Mbit: 100Mbit:
[[http://choerbaert.org/wiki/_media/scytheman:zeugs:code:bw_lan_100mbit.png|{{scytheman:zeugs:code:bw_lan_100mbit_thb.png}}]] [[http://choerbaert.org/wiki/_media/scytheman:zeugs:code:bw_lan_100mbit.png|{{scytheman:zeugs:code:bw_lan_100mbit_thb.png}}]]
 
en/scytheman/zeugs/code/bandwidthtool.1267883096.txt.gz · Last modified: 2010/03/06 14:44 by scytheman
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki