LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

LV for ARM UDP read 55 ms wait?

Hi Guys,

 

I may have misread some of the previous posts. Just to clarify:

  • You're correct in saying UDP does not require handshaking; it is a lossy, connectionless broadcast of data and therefore does not require any handshaking.

I will contact our LabVIEW for ARM team to see what reasons they can provide us with. My thoughts at this point are that this could be an explicit implementation of a timeout on the read function in case it were to be used iteratively, which would be especially useful in situations with sparse UDP communication.

 

I'll post any key responses from the team I contact in this thread. Thanks for your patience everyone.


Alex Thomas, University of Manchester School of EEE LabVIEW Ambassador (CLAD)

0 Kudos
Message 11 of 29
(1,764 Views)

Hi Everyone.

 

Below I've commented the code in question so that we properly understand the specific process in question.

 

while(bConnected){//Determine whether or not the system has an open connection.
       if ((sockState = RTX_tcp_get_state(wsock)) != TCP_STATE_CONNECT) {

       //If the current connection is timed out...
              if ((nTimeout >= 0) && ((LVGetTicks() - nStartMs) > (uInt32)nTimeout)) {              

                     //Notify and handle the timeout.
                     err = WSAETIMEDOUT;
                     goto niServiceLocatorGetServicePortOut;       

              }

       //Because the system has timed out, perform a new wait before attempting to make a new connection!

       WaitNextMultiple(55, NULL);//55ms value is arbitrary.
       }
       else {
              //The connection hasn't timed out. Continue communication as normal. (Don't perform the wait!)
              break;
       }
}

 

This means that we're only actually performing the wait if the current connection has timed out; therefore we're simply delaying the amount of times the system resources are made to perform a new connection. This particular delay should only have a significant impact on your application if you're continuing to make new connections; otherwise the only overhead I see with this function is the initial check.

 

The Product Support Engineers confirmed for me that this time used for the wait is arbitrary; however the particular delay that is used has been chosen to efficiently reduce the number of connection attempts your system makes without acting as a hindrence to the overall flow of the program. 

 

In short?

You can all rest easy knowing that you don't have to worry about modifiying the explicit delay that has been used when you're connected and communicating data; it will only have an effect when attempting to perform a new connection.

 

I hope this helps!


Alex Thomas, University of Manchester School of EEE LabVIEW Ambassador (CLAD)

0 Kudos
Message 12 of 29
(1,747 Views)

yes, this is A wait in the UDP connection. at opening a connection is doesn't matter to me that it takes a little longer.

BUT, I am talking about the UDPConnRead function, here is ALSO a wait. 

 

Row 745!

why does LabVIEW have to wait at a read of the UDP in

this function:

 

eRunStatus UDPConnRead(VoidHand connIdIn,
int32* pBytesToRead,
DataType dtBytesToRead,
int32* pTimeout,
DataType dtTimeout,
Cluster vherrin,
uInt16* pPortOut,
uInt32* pAddrOut,
NetConnRefNum* connIdOut,
VoidHand* dataOut,
Cluster vherrout,
Boolean bRunToFinish,
Boolean* bFirstRun,
int32* pRefN, // conn id
uInt32* pStartMs, // start ms
uInt32* pMaxBytes, // max bytes to read
int32* pSavedTimeout // saved timeout value
) {
int err = 0;
Boolean rVal = FALSE;
int32 nMaxBytes = 548;
int32 timeout = 25000;
SOCKET wsock = INVALID_SOCKET;
NCRefNumPtr pNCRef = NULL;
U16 pktSize;
VoidHand vhOut;

if (*bFirstRun)
{
*bFirstRun = FALSE;

// deallocate all inputs and allocate all outputs
pNCRef = (NCRefNum*)connIdIn;
if (!pNCRef) {
SetError(kPDANetConnSupportModNum, kBadLock );
return eFail;
}
wsock = pNCRef->rnum;
pNCRef = NULL;

if (pBytesToRead) nMaxBytes = LVPtrToLong(pBytesToRead, dtBytesToRead);
if (pTimeout) timeout = LVPtrToLong(pTimeout, dtTimeout);

// copy error in to out
rVal = CopyErrorInToOut(vherrin, vherrout);

if (pPortOut) *pPortOut = 0;
if (pAddrOut) *pAddrOut = 0;

if (connIdOut) {
*connIdOut = NetConnRefNumNew(connIdIn);
if (!(*connIdOut))
return eFail;
}

NetConnRefNumFree(connIdIn);

if (dataOut) {
*dataOut = PDAStrNew(NULL);
if (!(*dataOut))
return eFail;
}

// if there is a previous error or zero byte to read,
// don't do anything else
if (rVal || !nMaxBytes)
return eFinished;

*pRefN = wsock;
*pMaxBytes = nMaxBytes;

if (pSavedTimeout) *pSavedTimeout = timeout;

*pStartMs = LVGetTicks();
}
else // not first run
{
wsock = *pRefN;
nMaxBytes = *pMaxBytes;

if (pSavedTimeout) timeout = *pSavedTimeout;
}

// loop until reading is done (reading is done the moment a packet is received)
while(1) {
// RTX_udp_rx_bytes will return 0 if there is no packet to read
pktSize = RTX_udp_rx_bytes (wsock);
if (pktSize > 0) {
/* We have got a packet available in the RLARM ciruclar buffer
If the user requested nMaxBytes is less that the packet size, we can
only return nMaxBytes, otherwise we can return the entire packet
Also, if the output is not wired (dataOut == NULL), we still need to clear the packet
*/
if (dataOut) {
// Work out the packet size to read
pktSize = (pktSize < nMaxBytes) ? pktSize : nMaxBytes;

/* Allocate the LabVIEW string output buffer, and read the packet to it - we have to go to the
low level string functions to do this... */
PDAStrFree(*dataOut);
*dataOut = PDAStrNew(NULL); // new output string
if (!PDAStrResize(dataOut, pktSize + sizeof(PDAStr))) {
return eFail; // Allocate/size the output string (Check allocation succeeded)
}
vhOut = *dataOut;
// Read the packet into the string buffer
if (!RTX_udp_recv (wsock, (U8 *)((PDAStrPtr)vhOut)->str, &pktSize, (U8 *)pAddrOut, (U16 *)pPortOut)) {
err = WSAENOTSOCK;
}
}
else {
// Discard the packet
pktSize = 0;
if (!RTX_udp_recv (wsock, (U8 *)((PDAStrPtr)vhOut)->str, &pktSize, (U8 *)pAddrOut, (U16 *)pPortOut)) {
err = WSAENOTSOCK;
}
}
goto udpReadOut;
}

if ((timeout >= 0) && ((LVGetTicks() - *pStartMs) > (uInt32)timeout)) {
err = WSAETIMEDOUT;
goto udpReadOut;
}

if (bRunToFinish)
//WaitNextMultiple(55, NULL);  //row 745
WaitNextMultiple(1, NULL); //this is what I've made
else
return eNotFinished;
}

udpReadOut:
if (err && vherrout)
SendError(vherrout, err, _LVT(""));

if (!err) {
// Byte swap the address (necessary because LV treats it as a U32, RTX as a char[])
*pAddrOut = FIX_INT(*pAddrOut);
}

return eFinished;
}
#endif

Wouter.
"LabVIEW for ARM guru and bug destroyer"
Message 13 of 29
(1,743 Views)

After reading through this thread again and further consideration, I've come to the conclusion that the 55 ms wait is a bug. A bug that severely affects the data rate into the ARM board.

 

I wonder how many developers have pulled their hair out in frustration wondering why data rates into the ARM board are so slow. (By data rate, I don't mean transfer rates, but update rates.)

 

Thanks w0utje for showing us how to fix this. Much appreciated. (I would comment out the line entirely rather than wait 1 ms.)

0 Kudos
Message 14 of 29
(1,733 Views)

Hi Everyone,

 

I've passed this up to one of the ARM Product Support Engineers and I can confirm that this is a bug! A Corrective Action Request has been created in order to get this patched in later releases of LabVIEW for ARM. Thank you all for your patience.

 

Finally, a great big thanks to w0utje for his solution for anyone who has issues with this communication delay; comment out the 55ms wait from RLARM_CCGTcpUdpSupport.c and RLARM_TCPWrapper.c. 

 

Kind Regards,


Alex Thomas, University of Manchester School of EEE LabVIEW Ambassador (CLAD)

Message 15 of 29
(1,702 Views)

nice!

 

thanks Alex!

Wouter.
"LabVIEW for ARM guru and bug destroyer"
0 Kudos
Message 16 of 29
(1,699 Views)

Hey w0ujte,

Would you or anyone else be able to post your LabVIEW code which replicates this issue? We are trying to replicate it here in office and have been unable to. The 55ms delay in the C code does not seem to have any affect on the update rate.

 

Thanks

Kevin

Kevin Fort
Principal Software Engineer
NI
0 Kudos
Message 17 of 29
(1,671 Views)

see the attachment UDP test.zip

 

choose in the labview for arm project build specification > communication, an IP Address you can use. fill this IP address in the pc application to talk to the ARM.

this project is for the EK-LM3S8962.

in hypterterminal open the comport that is created when you connect the EK-lm3s8962.

BAUD: 115200

 

you see that the UDP read time out is given 1 ms (I just want it to check if data is available in buffer)

you'll see that it takes 55 ms to read/check nothing.

 

if you change the timeout to, for example 100 ms, it will take 110 ms (2 x 55 ms)

 

if you change/delete the WaitNextMultiple(55, NULL);

you will see that this is causing it.

 

regards,

 

Wouter

Wouter.
"LabVIEW for ARM guru and bug destroyer"
0 Kudos
Message 18 of 29
(1,660 Views)

Hey Wouter,

I looked into this issue and was able to replicate the 55ms delay for a UDP read (only occurs when executing with parrallel execution disabled).  The delay is there to prevent pegging the CPU when the UDP read is the only thing to execute. It is only executed when we detect nothing else currently needs to be executed. Your solution of decreasing that wait should be a safe change to that driver but we recommend decreasing it in steps testing as you go to make sure you don't affect other portions of your code in an unexpected way.

 

 

Kevin Fort
Principal Software Engineer
NI
0 Kudos
Message 19 of 29
(1,650 Views)

Hi Alex/Kevin,

 

It states earlier to "comment out the 55ms wait from RLARM_CCGTcpUdpSupport.c and RLARM_TCPWrapper.c". I found four occurrences of a 55 ms wait in the first file and no occurrences in the second file. Is this correct? Do I comment out all four occurrences?

 

Also, why is the delay only happening when "Disable parallel executing" is on?

 

Hi All,

 

I've done some speed checks for UDP and TCP/IP and I thought I'd share my findings. Results shown below are with the 55 ms wait changed to 0 ms. Basically the embedded Target was set to either wait indefinitely to read or write as fast as it could. The PC Host would either write as fast as it could (loop with zero wait) or wait indefinitely to read. Timing was done by taking the time for 10,000 loops and calculating the loop rate. Target was LM3S8962 Evaluation Board.

 

Target operation           Disable parallel execution on        Disable parallel execution off

UDP Read                       4,770 Hz                             4,021 Hz

UDP Write                     13,344 Hz                            14,371 Hz                            

TCP/IP Read                      515 Hz                               516 Hz

TCP/IP Write                      58 Hz                                60 Hz

 

These values basically show the maximum loop rates possible. If you have control of both ends and are not doing things such as file transfers, it pays to use UDP rather than TCP/IP!

 

To examine the effect of the "55 ms wait", the wait was adjusted to the values shown below with "Disable parallel executing" on (there was no effect if this option is off - as already stated by Kevin).

 

 Wait              Loop Rate

   0 ms             4,770 Hz

   5 ms             4,428 Hz

  55 ms             1,904 Hz

1000 ms               126 Hz

 

It is interesting to note that the wait effects the loop rate, but not on a one-to-one basis. The "superfluous" 55 ms wait reduces UDP read performance by up to 60%.

 

Regards,

Vito

 

 

 

 

0 Kudos
Message 20 of 29
(1,635 Views)