I have a setup where I am sending data (1 byte at a time) to a Raspberry Pi from a Windows laptop via serial or Ethernet connection. The Pi then sends the data back to the laptop via serial or Ethernet, and I log the transmission for the round trip time. The Raspberry Pi server is coded in C++.
Right now I am trying to measure the execution time of receiving and sending on the Raspberry Pi side. However, I am noticing that the same function (receiving on the serial port) has different execution times depending on whether UDP or TCP is used to send back the data. This doesn't make sense to me, I would think that receiving on the serial port will be the same regardless.
I can post the actual code if necessary. Can anyone help explain what's going on here? Is it the inaccuracy of the timer? I am using the chrono library for millisecond timing.
Here is the code:
void send_client_udp( char *s, int mysock, int myport){
int i;
for(i=0;i<BACKLOG;i++){
if(htons(udparray[i].sin_port) == myport){
sendto(mysock,s,1,0,(struct sockaddr*)&udparray[i], sizeof udparray[i]);
}
}
}
void send_message_all_udp(char *s, int mysock){
int k;
for(k=0;k<BACKLOG;k++){
sendto(mysock,s,1,0,(struct sockaddr*)&udparray[k], sizeof udparray[k]);
}
}
void send_client_tcp( char *s, int mysock){
int i;
for(i=0;i<BACKLOG;i++){
if(tcparray[i]){
if(tcparray[i] == mysock){
send(tcparray[i], s, 1,0);
}
}
}
}
/* Send message to all clients */
void send_message_all_tcp(char *s){
int k;
for(k=0;k<BACKLOG;k++){
if(tcparray[k]){
send(tcparray[k], s, 1,0);
}
}
}
void *sr_es_udp(void *thissock)
{
int mysock = *(int*)thissock;
int counter = 1;
int ardint;
char ardchar;
char *mesg;
while (ardrun)
{
if (serialDataAvail (serfd) == -1)
{
fprintf(stdout, "(Serial) No data able to be received: %s\n", strerror (errno));
exit(EXIT_FAILURE);
}
auto recv1 = chrono::high_resolution_clock::now();
ardint = serialGetchar(serfd) ;
auto recv2 = chrono::high_resolution_clock::now();
if (ardint > 0)
{
ardchar = char(ardint);
mesg = &ardchar;
send_message_all_udp(mesg, mysock);
auto sendcli = chrono::high_resolution_clock::now();
std::chrono::duration<double,std::milli> elapscli = (sendcli - recv2);
std::chrono::duration<double,std::milli> elapsrecv = (recv2 - recv1);
outfile << counter << "\t" << elapsrecv.count() << "\t"<< elapscli.count() << "\t" << ardint << "\n";
counter++;
}
}
cout << "exit" << endl;
exitard= true;
}
void *er_es_udp(void *pnewsock)
{
int mysock = *(int*)pnewsock;
char client_msg[MAXLEN];
int read_size;
int clientint;
int myport;
int counter = 1;
while(looprun){
auto recv1 = chrono::high_resolution_clock::now();
read_size = recvfrom(mysock, client_msg, 1, 0, (struct sockaddr*)&their_addr, &size);
auto recv2 = chrono::high_resolution_clock::now();
clientint = int(*client_msg);
myport = htons(their_addr.sin_port);
if (clientint >0)
{
serialPuts (serfd, &(*client_msg)) ;
auto sendser = chrono::high_resolution_clock::now();
send_client_udp(client_msg,mysock,myport);
auto sendcli = chrono::high_resolution_clock::now();
std::chrono::duration<double,std::milli> elapsrecv = recv2-recv1;
std::chrono::duration<double,std::milli> elapscli = sendcli-recv2;
std::chrono::duration<double,std::milli> elapsser = sendser-recv2;
//outfile << counter << "\t" << elapsrecv.count() << "\t" << elapsser.count() << "\t" << clientint << "\n";
outfile << counter << "\t" << elapsrecv.count() << "\t" << elapscli.count() << "\t" << elapsser.count() << "\t" << clientint << "\n";
counter++;
}
}
cout << "exit " << endl;
}
/* TCP data handling */
void *sr_es_tcp(void *)
{
int counter = 1;
int ardint;
char ardchar;
char *mesg;
while (run)
{
if (serialDataAvail (serfd) == -1)
{
fprintf(stdout, "(Serial) No data able to be received: %s\n", strerror (errno));
exit(EXIT_FAILURE);
}
auto recv1 = chrono::high_resolution_clock::now();
ardint = serialGetchar (serfd) ;
auto recv2 = chrono::high_resolution_clock::now();
if (ardint > 0)
{
ardchar = char(ardint);
mesg = &ardchar;
send_message_all_tcp(mesg);
auto sendcli = chrono::high_resolution_clock::now();
std::chrono::duration<double,std::milli> elapscli = (sendcli - recv2);
std::chrono::duration<double,std::milli> elapsrecv = (recv2 - recv1);
outfile << counter << "\t" << elapsrecv.count() << "\t"<< elapscli.count() << "\t" << ardint << "\n";
counter++;
}
}
cout << "exit" << endl;
exitard=true;
}
/* handle the connections from client */
void *er_es_tcp(void *pnewsock)
{
int mysock = *(int*)pnewsock;
char client_msg[MAXLEN];
int read_size;
int clientint;
int myport;
int counter = 1;
while(looprun){
read_size = recv(mysock, client_msg, 1, 0);
auto recv2 = chrono::high_resolution_clock::now();
clientint = int(*client_msg);
if (clientint > 0)
{
client_msg[read_size] = '\0';
serialPuts(serfd, &(*client_msg)) ;
auto sendser = chrono::high_resolution_clock::now();
send_client_tcp(client_msg,mysock); //was send_message
auto sendcli = chrono::high_resolution_clock::now();
std::chrono::duration<double,std::milli> elapsrecv = recv2-recv1;
std::chrono::duration<double,std::milli> elapscli = sendcli-recv2;
std::chrono::duration<double,std::milli> elapsser = sendser-recv2;
outfile << counter << "\t" << elapscli.count() << "\t" << elapsser.count() << "\t" << clientint << "\n";
counter++;
}
}
cout << "exit " << endl;
}
For the sr_es functions, the serialGetChar execution time changes depending on whether send_message_all is UDP or TCP. serialGetChar is from WiringPi serial library. Additionally, the send_message_client_tcp in Eth_recv_eth_send() is different for the send_message_all_tcp in Ser_recv_eth_send() for TCP specifically when serialGetChar is receiving at 115200 bps compared to 9600 bps. Why is this the case? There is only one client, so send_message_client_tcp() and send_message_all_tcp() should be the same. Shouldn't sending tcp be consistent regardless of the serial port baud rate, and why would serial receiving time change because of the internet protocol?
Here are the avg stats and standard deviation for a couple different tests (10 trials of 1000 data points each):
Receive/Send via Ethernet
- UDP receive: 0.5 +/- 0.37 ms, UDP send: 0.30 +/- 0.17 ms
- TCP receive: 0.44 +/- 0.4 ms, TCP send: 0.39 +/- 0.15 ms
Receive Serially, send via Ethernet
- serial baud 9600 receive: 4.3 +/- 0.1 ms, UDP send: 0.25 +/- 0.11 ms
- serial baud 9600 receive: 3.9 +/- 0.1 ms, TCP send: 0.77 +/- 0.19 ms -> interesting point is that the first 30 or so points are at 0.35, after that it shoots up to ~0.75-1 ms
- serial baud 115200 receive: 0.3 +/- 0.09 ms, UDP send: 0.23 +/- 0.11 ms
- serial baud 115200 receive: 1 +/- 0.15 ms, TCP send: 0.34 +/- 0.1 ms