lwip memory and full speed throughput test.

Dependencies:   EthernetInterface mbed-rtos mbed

This project represents a throughtput test for the EthernetInterface, based on the lwIP library.

The purpose of this is to be able to make a comparison of full speed (Rx,Tx and Rx+Tx) and memory between the EthernetInterface based on the lwIP and the one based on PicoTCP.

The benchmark consists of three parts:

  • we are sending 1 Megabyte from the board to host
  • we are waiting for the host to send us 1 Megabyte of data
  • on the last part we are using a TCP Echo Server to send and receive back 1 Megabyte of data

we send/receive 1024 packets of 1024 bytes each and we measure how many bits per second we transmit and receive.

The result:
TX+RX Throughput: 4194304 bytes in 41 seconds (0.774) Mbits/s

Memory report
Current free memory : 22644 bytes
Maximum free memory : 24716 bytes
Minimum free memory : 22644 bytes
Average free memory : 22644 bytes

The python script used

#!/usr/bin/python
import sys, socket
import random, string
import select
from time import time
#ECHO_SERVER_ADDRESS = "10.20.30.139"
ECHO_SERVER_ADDRESS = "192.168.100.12"
ECHO_SERVER_PORT = 7
N_PACKETS = 1024
LEN_PACKET = 1024

TOT_BITS = (LEN_PACKET * N_PACKETS * 8) * 4. # TX bits + RX bits
PACKET = ''.join(random.choice(string.ascii_uppercase+string.digits) for _ in range(LEN_PACKET))
MEGA = 1024 * 1024.
UPDATE_STEP = (N_PACKETS/20) # Make the update step such as one step = 5%
UPDATE_R_STEP = (N_PACKETS/20) #Make the update step such as one step = 1%
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ECHO_SERVER_ADDRESS, ECHO_SERVER_PORT))
start = time()
rx_total = 0
tx_total = 0
data = ''
i = 0
lp = []
p = select.poll()
while(True): # keeping this in for robustness testing, when the test will run for days
	#Stage I - sending data from host towards mbed board	
	print "Started sending data...."
	while (i < N_PACKETS):
	  p.register(s, select.POLLOUT)
	  lp = p.poll(1)
	  if (len(lp) > 0):
	    s.sendall(PACKET)
	    i+=1
	    if (i % UPDATE_STEP) == 0: print "sent %d/%d (%.2f%%)" % (i, N_PACKETS, float(i)/ float(N_PACKETS) * 100.)
	    continue

	#Stage II - receving data from the mbed board
	print "Started receiving data...."
	while(len(data) < N_PACKETS * LEN_PACKET):	
		p.register(s, select.POLLIN)
		lp = p.poll(1)
		if(len(lp) > 0):
		    r = s.recv(LEN_PACKET)
		    if (r != ''):
		      data += r
		      if (len(data) / LEN_PACKET) % UPDATE_R_STEP: print "recvd %d/%d (%.2f%%)" % (len(data)/LEN_PACKET, N_PACKETS, float(len(data))/ float(N_PACKETS * LEN_PACKET) * 100.)
		    else:
		      print "Error receiving !"
		      sys.exit(1)

	#Stage III - echo between host and mbed board
	print "Started echoing data...."
	for i in range(N_PACKETS):
		if (i % UPDATE_STEP) == 0: print "%.2f%%" % (float(i)/float(N_PACKETS) * 100.)
		s.sendall(PACKET)
		data = s.recv(LEN_PACKET)
		if (len(data) != LEN_PACKET):
			print "Error echoing !"
			sys.exit(1)

	print "Test was finished!"
	break;	

t = time() - start
s.close()
print "TX+RX Throughput: %d bytes in %d seconds (%.3f)Mbits/s" % (TOT_BITS / 8, t, ((TOT_BITS / t) / MEGA))

This test is based on the following libraries

Import librarymbed-rtos

Official mbed Real Time Operating System based on the RTX implementation of the CMSIS-RTOS API open standard.

Import libraryEthernetInterface

mbed IP library over Ethernet

Click here to see the results for PicoTCP

Files at this revision

API Documentation at this revision

Comitter:
tass
Date:
Mon Jul 08 12:25:13 2013 +0000
Child:
1:fd8283c28901
Commit message:
lwIP memory usage benchmark.

Changed in this revision

EthernetInterface.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetInterface.lib	Mon Jul 08 12:25:13 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/emilmont/code/EthernetInterface/#dd9794ce1d64
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Jul 08 12:25:13 2013 +0000
@@ -0,0 +1,166 @@
+#include <mbed.h>
+#include <stdarg.h>
+#include "EthernetInterface.h"
+
+#define ECHO_SERVER_PORT  7
+#define BUFFER_QUANTITY   (1024*1024)
+
+struct MemoryUsage
+{
+    uint32_t minFreeRam;
+    uint32_t maxFreeRam;
+    uint32_t avgFreeRam;
+    uint32_t stackPointer;
+    uint32_t cntSamples;
+};
+
+struct MemoryUsage memoryStats = {0xFFFFFFFF,0,0,0};
+
+int fakePrintf(void* pvHeapInfo, char const* pFormatString, ...)
+{
+    struct MemoryUsage * memStat = (struct MemoryUsage *)pvHeapInfo;
+    static const char* freeRamFormat = "%d bytes in";
+    va_list valist;
+    
+    if(memcmp(pFormatString,freeRamFormat,strlen(freeRamFormat)) == 0)
+    {
+        va_start(valist, pFormatString);
+        unsigned long freeSize = va_arg(valist, unsigned long);
+        
+        if(memStat->minFreeRam > freeSize)
+            memStat->minFreeRam = freeSize;
+        
+        if(memStat->maxFreeRam < freeSize)
+            memStat->maxFreeRam = freeSize;
+            
+        memStat->avgFreeRam = ((memStat->avgFreeRam * memStat->cntSamples) + freeSize)/(++memStat->cntSamples);
+    }
+    else
+    {
+        // ignore format
+    }
+    return 0;
+}
+
+void inline memoryStamp(void)
+{
+    __heapstats((__heapprt)fakePrintf, &memoryStats);
+}
+
+void inline stackPtrSnapshot(void)
+{
+    memoryStats.stackPointer = __current_sp();
+}
+
+int main() {
+    
+    printf("Ethernet Interface memory test....\n");
+    stackPtrSnapshot(); // snapshot of the stack pointer before starting benchmark to see the SP.
+    EthernetInterface eth;
+    int connections = 0;
+    eth.init(); //Use DHCP
+    eth.connect();
+    printf("IP Address %s\n", eth.getIPAddress());
+    
+    TCPSocketServer server;
+    server.bind(ECHO_SERVER_PORT);
+    server.listen();
+    
+    while (true) {
+    printf("\nWait for new connection...\n");
+    printf("Client number %d\n",++connections);
+    TCPSocketConnection client;
+    server.accept(client);
+    client.set_blocking(false, 1500); // Timeout after (1.5)s
+    printf("Connection from: %s\n", client.get_address());
+    char buffer[1024];
+    while (true) {
+        
+        int dataReceived = 0;
+        int dataSent = 0;
+        
+        printf("\n\n\nStarting the receiving part...\n");
+        while(dataReceived < BUFFER_QUANTITY)
+        {
+            int n = client.receive(buffer, sizeof(buffer));
+            if (n <= 0) {
+                printf("Receive error\n");
+                break;
+            }
+            dataReceived += n;
+            memoryStamp();
+        }
+        
+       
+        printf("Received : %d bytes\nExpected : %d bytes\n",dataReceived,BUFFER_QUANTITY);
+        if(dataReceived < BUFFER_QUANTITY)
+        {
+            printf("Receiving part of the test has failed. Exiting connection.\n");
+            break;
+        }
+        else{
+            printf("Receiving has passed...\n");
+        }
+        
+        printf("\n\n\nStarting the sending part...\n");
+        while(dataSent < BUFFER_QUANTITY)
+        {
+            int n = client.send_all(buffer, sizeof(buffer));
+            if (n <= 0) {
+                printf("Send error\n");
+                break;
+            }
+            dataSent += n;
+            memoryStamp();
+        }
+        
+        printf("Sent : %d bytes\nExpected : %d bytes\n",dataSent,BUFFER_QUANTITY);
+        if(dataSent < BUFFER_QUANTITY)
+        {
+            printf("Sending part of the test has failed. Exiting connection.\n");
+            break;
+        }
+        else
+        {
+            printf("Sending test has passed...\n");
+        }
+        
+        
+        printf("\n\n\nStarting echo part...\n");
+        dataReceived = dataSent = 0;
+        while((dataReceived+dataSent) < 2*BUFFER_QUANTITY)
+        {
+            int n = client.receive(buffer, sizeof(buffer));
+            if (n <= 0) {
+                printf("Receive error\n");
+                break;
+            }
+            dataReceived += n;
+            
+            n = client.send_all(buffer, n);
+            if (n <= 0) {
+                printf("Send error\n");
+                break;
+            }
+            dataSent += n;
+            memoryStamp();
+        }
+        
+        printf("Echo size : %d bytes\nExpected : %d bytes\n",(dataReceived+dataSent),2*BUFFER_QUANTITY);
+        if((dataReceived+dataSent) < 2*BUFFER_QUANTITY)
+        {
+            printf("Echo test has failed.Exiting connection...\n");
+            break;
+        }
+        else
+        {
+            printf("Echo test has passed...\n");
+        }
+     }
+    client.close();
+    printf("Memory report after connection....\n");
+    printf("Max memory : %d bytes\nMin memory : %d bytes\nAverage memory : %d\n",memoryStats.maxFreeRam,memoryStats.minFreeRam,memoryStats.avgFreeRam);
+  }
+  
+  return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Mon Jul 08 12:25:13 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#58b30ac3f00e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Jul 08 12:25:13 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/b3110cd2dd17
\ No newline at end of file