Some utility tools and apps for performance measurement.

Tools

  • Libpcap/tcpdump

    “A portable C/C++ library for network traffic capture”

    Using libpcap in C yche TCPDUMP/LIBPCAP public Repository

  • Iperf

    “A tool for active measurements of the maximum achievable bandwidth on IP networks”

     #! /usr/bin/python3
     # -*- coding: UTF-8 -*-
       
     import matplotlib
     matplotlib.use('Agg')
     import matplotlib.pyplot as plt
     from matplotlib.backends.backend_pdf import PdfPages
     from pylab import *
     import matplotlib.gridspec as gridspec
     import re
     import numpy as np
     import math
       
     fsize  = 7
     lwidth = 1
     msize  = 3
     alpha  = 0.4
     linestyles = [
         ("dotted", (0, (1,1))),
         ("densely dashed", (0, (5,1))),
         ("densely dashdotted", (0, (3,1,1,1))),
         ("densely dashdotdotted", (0, (3,1,1,1,1,1))),
         ("dashdotted", (0, (3,5,1,5))),
         ("dotted", (0, (1,1)))]
       
     matplotlib.rcParams.update({'font.size': fsize})
       
     def RGB2Hex(R=255, G=255, B=255):
         color = "#"
         color += str(hex(R)).replace('x','0')[-2:]
         color += str(hex(G)).replace('x','0')[-2:]
         color += str(hex(B)).replace('x','0')[-2:]
         return color
       
     # Return a dictionary {flow_id : [Tput 1, Tput 2 ...]}
     def get_iperf(path):
         data = {}
         with open(path,'r') as iperf:
             for line in iperf.readlines():
                 matchobj = re.search(r'\[.*\]',line,re.M|re.I)
                 if matchobj:
                     if re.search(r'SUM|ID',line,re.M|re.I):
                         continue
       
                     size = len(matchobj.group()) - 1
                     ID  = matchobj.group()[1:size]
                     pid = int(ID)
                       
                     if re.search(r'port .* connected',line,re.M|re.I):
                         data[pid] = []
                         continue
       
                     temp_1 = re.search(r'Bytes .* Mbits/sec',line,re.M|re.I)
                     temp_2 = re.search(r'Bytes .* Gbits/sec',line,re.M|re.I)
                     temp_3 = re.search(r'Bytes .*bits/sec',line,re.M|re.I)
                     if temp_1:
                         aList = re.split(r'\s+',temp_1.group())
                         data[pid].append(float(aList[1]))
                     elif temp_2:
                         aList = re.split(r'\s+',temp_2.group())
                         data[pid].append(float(aList[1]) * 1000)
                     elif temp_3:
                         # print(path + " : " + str(pid) + "appending 0 ")
                         data[pid].append(0)
         return data
       
     def plot(y_data, x_label, x_ticks, x_tick_labels, y_label, y_ticks, y_tick_labels, labels, figName):
         # rainbow
         colors = [RGB2Hex(255, 0, 0), RGB2Hex(255, 165, 0), RGB2Hex(0, 255, 0), RGB2Hex(0, 127, 255), RGB2Hex(0, 0, 255), RGB2Hex(139, 0, 255)]
         # colors = ["", "", ]
         plt.figure(figsize=(4,2.5))
         ax = plt.subplot(111)
       
         x_values = []
         y_values = []
         for loop in range(len(y_data)):
             for key in y_data[loop]:
                 values = y_data[loop][key]
             y_values = values
             x_values = [item+0.5 for item in range(len(y_values))]
             ax.plot(x_values, y_values, ls=linestyles[loop][1], linewidth=lwidth, color=colors[loop], label=labels[loop])
       
         ax.set_xlim(0, len(x_ticks)+1)
         ax.set_ylim(0, 150)
         ax.set_xlabel(x_label)
         ax.set_xticks(x_ticks)
         ax.set_xticklabels(x_tick_labels)
         ax.set_ylabel(y_label)
         ax.set_yticks(y_ticks)
         ax.set_yticklabels(y_tick_labels)
         ax.tick_params(direction="in")
         # ax.tick_params(axis='y', labelcolor=colors[4])
         ax.xaxis.grid(ls=":", alpha=alpha)
         ax.yaxis.grid(ls=":", alpha=alpha)
       
         plt.legend(loc=0, prop={"size":fsize})
         plt.tight_layout()
         pp = PdfPages(figName)
         pp.savefig()
         pp.close()  
       
     def main_plot():
         files   = ["iperf"]
         x_ticks = [0, 20, 40, 60, 80, 100]
         y_ticks = [0, 20, 40, 60, 80, 100, 120]
         x_label = "Time (s)"
         y_label = "Throughput (Mbps)"
         x_tick_labels = ["0", "20", "40", "60", "80", "100"]
         y_tick_labels = ["",  "20", "40", "60", "80", "100", "120"]
         labels = ["iperf"]
         figName = "EBA.pdf"
       
         y_data = []
         for h in files:
             y_data.append(get_iperf(h + ".txt"))
         plot(y_data, x_label, x_ticks, x_tick_labels, y_label, y_ticks, y_tick_labels, labels, figName)
       
     if __name__ == '__main__':
         main_plot()
    

    Network Throughput Testing with Iperf Iperf

  • NTTTCP

    “A multiple-thread based Linux network throughput benchmark tool.”

    Source Code Modified version

  • neper “neper is a Linux networking performance tool.”
    • Support multithreads and multi-flows out of the box.
    • Generate workload with epoll.
    • Collect statistics in a more accurate way.
    • Export statistics to CSV for easier consumption by other tools.

    neper

  • Sockperf

    “A network testing tool oriented to measure network latency and also spikes of network latency”

    1. Installation

      sudo apt-get install g++
      sudo apt-get install autoconf
      git clone https://github.com/Mellanox/sockperf.git
      cd sockperf
      ./autogen.sh 
      ./configure 
      make -j 100
      sudo make install
      
    2. Usage

      server : sockperf server --tcp
      client : sockperf ping-pong -i 192.168.0.11 --tcp -t sperf_time --full-log sperf_path
      
    3. Plot

      #! /usr/bin/python3
      # -*- coding: UTF-8 -*-
            
      import matplotlib
      matplotlib.use('Agg')
      import matplotlib.pyplot as plt
      from matplotlib.backends.backend_pdf import PdfPages
      from pylab import *
      import matplotlib.gridspec as gridspec
      import re
            
      fsize  = 10
      lwidth = 0.8
      msize  = 5
      alpha  = 0.3
            
      def getSockperfData(path):
      	points = []
      	rtt    = []
      	with open(path,'r') as sockperf:
      		for line in sockperf.readlines():
      			matchobj = re.search(r'sockperf: --->',line,re.I|re.M)
      			if matchobj:
      				points.append(float(line.split("=")[1].strip()))
      				continue
      			match = re.match(r"(\d+.\d*), (\d+.\d*), (\d+.\d*), (\d+.\d*)", line)
      			if match!=None:
      				items = line.split(',')
      				latency = float(items[2].strip()) - float(items[1].strip())
      				latency = latency * 1000000
      				#print(latency)
      				rtt.append(float(latency))
      	return sorted(rtt),sorted(points)
            
      def plot(labels, file_names):
      	colors = ["dodgerblue", "limegreen", "m","mediumslateblue", "tomato"]
      	markers= ["o", 'v', '*', "D", '|']
      	percentiles = [0, 0.25, 0.5, 0.75, 0.9, 0.99, 0.999, 0.9999, 0.99999, 1]
            
      	plt.figure(figsize=(4,2.5))
      	ax = plt.subplot(111)
      	index = 0
      	for path in file_names:
      		rtt,points = getSockperfData(path)
      		ys = [(float)(j+1)/len(rtt) for j in range(len(rtt)) ]
      		plt.plot(rtt, ys, color=colors[index], linewidth=lwidth)
      		ps = [2*ii for ii in points]
      		plt.plot(ps, percentiles, markers[index], color=colors[index], markersize=5, linewidth=lwidth)
      		plt.plot([],[],marker=markers[index], color=colors[index],markersize=5, label=labels[index], linewidth=lwidth)
      		index = index + 1
            
      		# ax.set_xscale('log')
      	ax.tick_params(direction="in")
      	ax.set_xlim(0,5000)
      	ax.set_xticks([500, 1000, 1500, 2000,2500, 3000, 3500, 4000, 4500, 5000])
      	ax.set_xticklabels(['', "1", '', '2', '', '3', '', '4', '', '5'], fontsize=fsize)
      	ax.set_ylim(0, 1)
      	ax.set_yticks([0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1])
      	ax.set_yticklabels(['0', '', '0.25', '', '0.50', '', '0.75', '', '1'], fontsize=fsize)
      	ax.set_xlabel("RTT (ms)", fontsize=fsize)
      	ax.set_ylabel("CDF", fontsize=fsize)
      	ax.yaxis.grid(True)
      	ax.yaxis.grid(ls=":", alpha=alpha)
      	ax.xaxis.grid(ls=":", alpha=alpha)
            
      	plt.tight_layout()
      	plt.legend(loc=4,prop={'size':fsize}, ncol=3)
            
      	pp = PdfPages('sperf.pdf')
      	pp.savefig()
      	pp.close()	
            
      if __name__ == '__main__':
      	labels =['E1', 'E2', 'E3', 'E4', 'E5']
      	file_names = ["E1.txt","E2.txt", "E3.txt", "E4.txt", "E5.txt"]
            
      	plot(labels, file_names)
      

    Linux Man Pages github

  • TCPPROBE

    “TCP probe is a module that records the state of a TCP connection in response to incoming packets”

    1. Usage

      sudo modprobe tcp_probe full=1
      sudo chmod 444 /proc/net/tcpprobe
      cat /proc/net/tcpprobe > results.txt
      TCPCAP=$!
      sleep 5
      sudo kill ${TCPCAP}
      sudo modprobe -r tcp_probe
      
    2. Customize TCPprobe

      Modify https://elixir.bootlin.com/linux/v4.15/source/net/ipv4/tcp_probe.c
      
    3. Plot

      #!/usr/bin/python3
      # -*- coding: UTF-8 -*-
           
      import matplotlib
      import numpy as np
      matplotlib.use('Agg')
      import matplotlib.pyplot as plt
      from matplotlib.backends.backend_pdf import PdfPages
      from pylab import *
      import matplotlib.gridspec as gridspec
      import re
           
      lwidth = 0.8
      msize  = 3
      fsize  = 7
      alpha  = 0.3
      linestyles = [
          ("dotted", (0, (1,1))),
          ("densely dashed", (0, (5,1))),
          ("densely dashdotted", (0, (3,1,1,1))),
          ("densely dashdotdotted", (0, (3,1,1,1,1,1))),
          ("dashdotted", (0, (3,5,1,5))),
          ("dotted", (0, (1,1)))]
           
      def RGB2Hex(R=255, G=255, B=255):
          color = "#"
          color += str(hex(R)).replace('x','0')[-2:]
          color += str(hex(G)).replace('x','0')[-2:]
          color += str(hex(B)).replace('x','0')[-2:]
          return color
           
      def read_tcpprobe(path):
          print("entering read_tcpprobe ...")
          time     = []
          cwnd     = []
          ssthres  = []
          ret_time = []
          sndnxt   = []
          snduna   = []
          ret_cwnd = []
          ret_ssth = []
          with open(path,"r") as tcpprobe:
              for line in tcpprobe.readlines():
                  # filter port
                  if line.find("5500") == -1:
                      continue
                  aList = line.strip().split()
                  time.append(float(aList[0]))
                  sndnxt.append(int(aList[4], base=16))
                  snduna.append(int(aList[5], base=16))
                  cwnd.append(int(aList[6]))
                  ssthres.append(int(aList[7]))
          new_time = [round(item-time[0], 6) for item in time]
          new_nxt  = []
          new_una  = []
          extra    = 0
          for item in sndnxt:
              if item < sndnxt[0]:
                  extra = 0xffffffff
              new_nxt.append(item-sndnxt[0]+extra)
          extra    = 0
          for item in snduna:
              if item < snduna[0]:
                  extra = 0xffffffff
              new_una.append(item-snduna[0]+extra)  
           
          # new_nxt  = [(item-sndnxt[0]) for item in sndnxt]
          # new_una  = [(item-snduna[0]) for item in snduna]
          return new_time, new_nxt, new_una
           
      def main(path, figName):
          rtime, sndnxt, snduna = read_tcpprobe(path)
          colors = [RGB2Hex(255, 0, 0), RGB2Hex(255, 165, 0), RGB2Hex(0, 255, 0), RGB2Hex(0, 127, 255), RGB2Hex(0, 0, 255), RGB2Hex(139, 0, 255)]
          plt.figure(figsize=(4,2))
          ax = plt.subplot(111)
          X_max = 100
          X_max_index = len(rtime)
          for time_index in range(len(rtime)):
              if rtime[time_index] > X_max+1:
                  X_max_index = time_index
                  break
          ax.plot(rtime[:X_max_index], sndnxt[:X_max_index], color=colors[0], linewidth=lwidth, label="sndnxt")
          # ax.plot(rtime[:X_max_index], sndnxt[:X_max_index], color=colors[1], linewidth=lwidth, label="snduna")
           
          ax.set_xlim(0, X_max)
          ax.set_xticks([0, 20, 40, 60, 80, 100])
          ax.set_xticklabels(["0", "20", "40", "60", "80", "100"], fontsize=fsize)
          ax.set_xlabel("Time (s)", fontsize=fsize)
          ax.set_ylabel("snd_nxt (GBytes)", fontsize=fsize)
          ax.set_ylim(0, 5000000000)
          ax.set_yticks([0, 1000000000, 2000000000, 3000000000, 4000000000, 5000000000])
          ax.set_yticklabels(['', '1', '2', '3', '4', '5'], fontsize=fsize)
          ax.yaxis.grid(ls=":", alpha=alpha)
          ax.xaxis.grid(ls=":", alpha=alpha)
          ax.tick_params(direction="in")
           
          plt.tight_layout()
          plt.legend(loc=0, prop={'size':fsize})
           
          pp = PdfPages(figName)
          pp.savefig()
          pp.close()  
           
      if __name__ == '__main__':
          path = "tcpprobe.txt"
          figName = "tcpprobe.pdf"
          main(path, figName)
      

    TCP congestion control basics
    wiki definition
    tcp_testing Tcpprobe在网络中的使用

Apps

  • Memcached: A distributed memory object caching system

    Memcached.org runoob memcached tutorials xmemcached

  • Redis: an in-memory data structure project implementing a distributed, in-memory key-value database with optional durability. [runoob] (https://www.runoob.com/redis/redis-tutorial.html)