Author Topic: TCP Buffer  (Read 40174 times)

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: TCP Buffer
« Reply #15 on: January 08, 2009, 10:24:00 PM »
Hi Mark,
  Thanks for the reply.

So really, as we wont use much memory, the large buffers will help in dealing with promiscuous access to the chip. What happens if there is an overrun? Is the data simply not placed into the buffer, therefore lost, or does it wrap around to the start again? If it doesnt ovewrite any other parts in memory, then our code can handle it, and will resume reading the correct data when it settles down.

We have one application where no incoming connections are made, it only connects to our server, so there will be no promiscuous access to the chip. In this case it would be safe on lowering the buffer size(theres not much traffic sent/received here too)?
Regards
Neil
« Last Edit: January 08, 2009, 10:27:15 PM by neil »

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: TCP Buffer
« Reply #16 on: January 09, 2009, 01:56:40 AM »
Neil

A frame that can't be put to a buffer will be discarded by the Ethernet controller and lost. This is generally not serious since it will be repeated (higher layer protocol) but is is of course to keep loses as low as possible.

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: TCP Buffer
« Reply #17 on: January 09, 2009, 11:21:35 AM »
Mark,
  I reduced NUMBER_OF_RX_BUFFERS_IN_ETHERNET_DEVICE to 4, to set aside more memory.  What margin is there for changing OUR_HEAP_SIZE?

umalloc doesnt have a memory problem when sending with buffers now. But I still cant get it to work. I am now at the stage at the above message on7th Jan 11.49.  If I simply change the fnSendBufTCP() with uMemcpy(..), and    fnSendTCP(..) then it works fine.

Regards
Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: TCP Buffer
« Reply #18 on: January 09, 2009, 12:32:50 PM »
Hi Neil

When OUT_HEAP_SIZE is increased its reserved area grows into the space which is open for use by the CPU stack. Therefore the value of fnStackFree() will tell you how much can be added to OUT_HEAP_SIZE.

I don't known why you can send with buffered TCP. I just checked the way that Telnet uses it and the options set in the demo project. In addition to your settings it uses SUPPORT_PEER_MSS and the define USE_TELNET (there is also a part of fnSendBufTCP() which optionally filters TELNET escape sequences). The various configurations should however be able to live without other bits but you may like to quickly set these two defines just to be sure. [I just checked removing SUPPORT_PEER_MSS and USE_TELNET from the function and TELNET still worked normally in the demo project]

fnSendBufTCP() essentially does this.
- memcpy() of user data to a local ring buffer
- fnSendTCP()

so at the end of the day just uses fnSendTCP() to actually send. You could set a break at the line
        if ((ssReturn = fnSendTCP(TCP_socket, ucTCP_data_buf, TxFrameSize, TCP_FLAG_PUSH)) > TxFrameSize) {
where the frame is finally sent to ensure that it is arriving there and doesn't have any unexpected values.

If you don't identify the problem I think it will be best to send me your config.h file and the code which is controlling the socket and sending the data.

Regards

Mark



Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: TCP Buffer
« Reply #19 on: January 09, 2009, 01:26:00 PM »
Mark,
  the value returned from fnStackFree(), is this never used? Does the system know how much stack is needed through all the functions, along with their variable space?

The fnStackFree() function returns 2519bytes, so would it be safe for me to add 2k of this to OUR_HEAP_SIZE? If I have one function that uses 2k of stack, and add a new function that uses 1k of stack, will fnStackFree() still return the same as no more extra memory is needed?

But if I create a new function that uses 2.5k of stack, then fnStackFree() will return 500bytes less?

Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: TCP Buffer
« Reply #20 on: January 09, 2009, 02:31:57 PM »
Neil

The space between the top of heap and the stack pointer is filled with a pattern (pattern defined by UNUSED_STACK_PATTERN in config.h - default 0x55) when the system starts.

The function fnStackFree() counts the number of bytes which still have the initialization pattern by starting at the top of HEAP and counting upwards until a value of != UNUSED_STACK_PATTERN is found. Since CPU stack grows down, the lower the stack is used, the less the unused space becomes. As long as this value remains positive it means that the CPU stack has never 'collided' with the HEAP and so represents a safety margin. Of course there may be some special cases where the value measured is not perfect but if the value is reviewed after the system has been running for some time and exercising as much code as possible the value should be stable and representative.

In your case it looks safe to add 2k of heap to the present configuration.

Also your other remarks are generally correct. Of course if you have 2 functions using 2k and 1k and use them both at the same time (one calling the other) it will result in 3k stack used, but otherwise only the largest stack user will really be the limiting case. Note that interrupts will use stack too so an interrupt of the 2k stack case will result in 2k + interrupt use, but this is generally only a small addition.

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: TCP Buffer
« Reply #21 on: January 09, 2009, 05:32:15 PM »
Hi Mark,
  I have attached the config.h and a txt document showing the callback function along with how I call the send functions.

When I use fnSendTCP(..) I comment out the send in TCP_EVENT_ACK and TCP_EVENT_PARTIAL_ACK, and the fnSendBufTCP(..) command. And works fine.
When I use the fnSendBufTCP(..) and comment out fnSendTCP(..) doesnt work.

Regards
Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: TCP Buffer
« Reply #22 on: January 09, 2009, 07:09:56 PM »
Hi Neil

I am sorry but I am having difficulties to identify why you are having problems. With my tests I can't reproduce a problem with the same settings and the listener shouldn't actually have any influence on the transmission of the first packet.

Have you verified using Wireshark that nothing is physically being sent (maybe you see that something unexpected is being sent which may help to explain something?)

In Telnet.c you can also find a good example for the handling of listner events (not a problem at this stage). See fnTELNETListener().

For example, the best way to handle acks is:


        if (fnSendBufTCP(Socket, 0, 0, TCP_BUF_NEXT) != 0) {               // send next buffered (if waiting)
            return(APP_SENT_DATA);                                     // mark that data has been transmitted
        }


This will avoid TCP from unnecessarily sending additional ACKs.

The regenerate can also be used to kick of waiting messages like this, improving efficiency in repetition case:

    case TCP_EVENT_REGENERATE:
        if (fnSendBufTCP(Socket, 0, 0, TCP_BUF_REP) != 0) {              // repeat send buffered
  #ifdef SUPPORT_PEER_WINDOW
            fnSendBufTCP(Socket, 0, 0, (TCP_BUF_NEXT | TCP_BUF_KICK_NEXT)); // kick off any following data as long as windowing allows it
  #endif
            return APP_SENT_DATA;
        }
        break;



Since I can't work out what is happening in your case I think that we will need to debug the routine fnSendBufTCP() to find out what it is doing wrong. At the moment I have run out of ideas why it should not transmit something when called.
Could you step into the code and see whether you identify something unusual? It should simply copy the passed data to its own buffer and call fnSendTCP(). If it gets this far it is not actually doing anything differently to your other working case.

If you don't identify what is happening, can you give me a time when we can skype and debug in parallel?

Thanks

regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: TCP Buffer
« Reply #23 on: January 09, 2009, 07:18:23 PM »
Hi Mark,
  Thanks for the reply. I will do what you suggest, and will let you know of the results.

Regards
Neil

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: TCP Buffer
« Reply #24 on: January 10, 2009, 04:33:09 PM »
Hi Mark,
  I couldnt get it to work, the debugger kept freezing. So I re-installed a new utasker, and now seems to work.

After the memory gets allocated for the send buffer on the first buffer send, does it get freed again?
Does this feature use any more memory apart from the umalloc() of the send buffer?

I want to make sure I am correct, I added the following in the callback:

    case TCP_EVENT_ACK:       
     if (fnSendBufTCP(Socket, 0, 0, TCP_BUF_NEXT)) {               
            return APP_SENT_DATA;                                   
        }
      break;
   
    case TCP_EVENT_ARP_RESOLUTION_FAILED:
        break;
    case TCP_EVENT_PARTIAL_ACK:
        if (fnSendBufTCP(Socket, 0, 0, TCP_BUF_REP)) {                   // repeat send buffered
  #ifdef SUPPORT_PEER_WINDOW
            fnSendBufTCP(Socket, 0, 0, (TCP_BUF_NEXT | TCP_BUF_KICK_NEXT)); // kick off any following data as long as windowing allows it
  #endif
            return APP_SENT_DATA;
        }
       break;
    case TCP_EVENT_REGENERATE:
       break;

I dont have telit defined, and have #define SUPPORT_PEER_WINDOW , and #define USE_BUFFERED_TCP outside the #ifdef USE_TELNET.


Regards
Neil

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: TCP Buffer
« Reply #25 on: January 10, 2009, 08:28:10 PM »
Hi Neil

I am glad that it worked after the re-install.
The TCP buffer is allocated once, the first time it is used. It is never freed and the size doesn't grown. It uses only a few extra bytes bytes in the socket structure to manage the buffer but this is negligible in comparison to the buffer size.
The listener also looks good.

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: TCP Buffer
« Reply #26 on: January 10, 2009, 08:33:23 PM »
Hi Mark,
  If using fnSendBufTCP() with multiple sockets, I assume the buffer size doesnt increase?

Regards
Neil


Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: TCP Buffer
« Reply #27 on: January 10, 2009, 08:54:12 PM »
Hi Neil

When using on multiple sockets, each socket using fnSendBufTCP() requires its own buffer!!

Therefore increasing socket number in this case does increase memory use (and quite dramatically if the buffer is large).
This is unavoidable since each connection will need its own personal buffer to work with.

Since debug type output doesn't really need multiple sockets this shouldn't be an issue.

Other sockets which doesn't use fnSendBufTCP() do not need a buffer and so doesn't use additional memory.

Regards

Mark

Offline neil

  • Sr. Member
  • ****
  • Posts: 438
    • View Profile
Re: TCP Buffer
« Reply #28 on: January 21, 2009, 12:11:10 PM »
Hi mark,
    As my application wont be sending massive TCP data (when using fnSendBufTCP), probably amout 500 bytes a time, so if I change TCP_BUFFER to 700, then this will allow 4 TCP sockets to use fnSendBufTCP() with a max buffer of 700. Is this correct? And if so , is there much other memory overhead?

Also, TCP_BUFFER_FRAME does this make sense in having this larger than TCP_BUFFER value? If I can do the above, then reducing this to the same, will it save RAM?

Is TCP_BUFFER_FRAME used per socket, or for all sockets?

Regards
Neil
« Last Edit: January 21, 2009, 12:15:03 PM by neil »

Offline mark

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 3236
    • View Profile
    • uTasker
Re: TCP Buffer
« Reply #29 on: January 21, 2009, 02:42:54 PM »
Hi Neil

Each socket configured for buffer operation will have a structure of type TCP_TX_BUFFER. This contains a local buffer unsigned char  ucTCP_tx[TCP_BUFFER]; This is its own ring buffer used for buffered streaming. The structure TCP_TX_BUFFER is created on heap when the socket is actually used the first time (until used it will not have the memory).
This means that when 4 sockets are used there will be 4 TCP_TX_BUFFER structures (each with TCP_BUFFER buffer space) - [4 x TCP_BUFFER buffer memory will be used]. In your configuration there will be 4 x 700 bytes allocated for buffer use by the 4 sockets (when all are actually used).

TCP_BUFFER_FRAME is the largest TCP frame that will be send. This is temporary memory (on stack when the TCP frame is constructed). It is used to copy the buffered data from the ring buffer (if in TELNET mode it may also do some filtering or control character stuffing if in ASCII mode) to the TCP frame buffer which is then sent. You are right that it doesn't need to be larger than the buffer size since it will never need to build a frame of larger than a buffer length of data. It can also be smaller than a buffer (logical since its maximum size if about 1500 and a buffer can be several kbytes). The restriction is however more useful in systems where the maximum LAN buffer is reduced (in small systems where thsi saves memory space) so that the TCP layer doesn't try to build a frame which is too large to fit in the LAN buffer space.

Since TCP_BUFFER_FRAME doesn't belong to a socket it is shared by all. However this is stack memory (normal subroutine operation) and so as long as you have enough free stack it is not that critical.

Regards

Mark