On Improving Open Transport Network Application Performance

Increasing Throughput

This section discusses methods for increasing network data throughput to your server to enhance performance.

Receiving Data

Some intro text here..

process T_DATA until kNoDataErr

Use T_DATA in notifier TO gather and process info. this might involve feeding a protocol state machine.

No-Copy Receive One way to avoid wasting memory access bandwidth is to employ the No-Copy Receive option to directly access the network interface's actual DMA buffers. This process lets you determine where and how data to copy, typically this results in decreasing memory copies by a factor of 2.

To request that Open Transport initiate a no-copy receive, you must pass the constant kOTNetbufDataIsOTBufferStar in the length parameter of the OTRcv. This will return you a pointer to the OTBuffer structure, as illustrated here:

	OTBuffer* myBuffer;
	
	OTResult result = OTRcv(myEndpoint, &myBuffer, kOTNetbufDataIsOTBufferStar);
The OTBuffer data structure is based on the STREAMS mblk_t data structure, as illustrated below. By tracing the chain of fNext pointers, all of the data associated with the message can be accessed.

    struct OTBuffer 
    { 
        void*       fLink;  // b_next & b_prev
        void*       fLink2; 
        OTBuffer*   fNext;  // b_cont
        UInt8*      fData;  // b_rptr
        size_t      fLen;   // b_wptr
        void*       fSave;  // b_datap
        UInt8       fBand;  // b_band
        UInt8       fType;  // b_pad1
        UInt8       fPad1;
        UInt8       fFlags; // b_flag
    };

A few utilities are available to the Open Transport programmer to simplify access to the OTBuffer structure. You can use OTReadBuffer to read data from the buffer, to OTBufferDataSize calculate its total length and OTReleaseBuffer to dispose of the OTBuffer when you are done.

When processing a no-copy receive, it is very important that you minimize the time that you hold onto the buffer and be sure to call OTReleaseBuffer to return it to Open Transport. Otherwise, you run the risk of starving the network driver for DMA buffers and adversely affecting the performance of the operating system.

The Open Transport Client Developer Note further documents the no-copy receive method of processing network data.

Warning:
Under no circumstances should you write to the OTBuffer data structure. Doing so will run the result in either an an access fault or system crash .

A Code Snippet Illustrating a No-Copy Receive

This snippet demonstrates how you might process a no-copy receive in your notifier:

#include <OpenTransport.h>
#include <OpenTptClient.h>


// QUEUE_NET_EVENT(T_DATA) deferes a particuylar event to later
// MyProcessBuffer(buffer,actCount) consumes network data


void HandleDataAvail(EndpointRef ep) {
        OTFlags         flags;
        OTResult        status;
        OTBuffer*       buffP;
        OTBufferInfo    buffInfo;
        size_t          actCount;
        char*           buffer;
            
// do while data left in OT
    while((status = ::OTRcv(ep, &buffP,
                             kOTNetbufDataIsOTBufferStar, &flags)) > 0)
     {
        
    // get count of bytes in buffer
        OTInitBufferInfo(&buffInfo, buffP);
        actCount = status;


    // reserve buffer space
    // You should handle OTAllocMem failures. Maybe use a defered task
        ThrowIfNil( buffer = OTAllocMem(actCount));
       
     
    // read data into buffer
         ::OTReadBuffer(&buffInfo, buffer, &actCount);
         
    // Call code to consume network data
        MyProcessBuffer(buffer,actCount);
    
    // return OTBuffer to system
        ::OTReleaseBuffer(buffP);
    }   
    

// Did we read all the data
        if(status ==  kOTNoDataErr) return;

// was  the endpoint not ready yet
        else if(status ==  kOTStateChangeErr) QUEUE_NET_EVENT(T_DATA);
                    
// Check for Rcv Error 
        else ThrowIfTErr( status ); 

};

Sending Data

Some intro text here..

Pre-allocating & Pre-computing Data

Optimize for the expected case by preallocate or precompute any frequently used headers. Use the Gather-write capability to link together non-contiguous data with OTData structure.

The structure is used by Snd by passing a pointer to the OTData as the buffer parameter, and using the constant kNetbufDataIsOTData as the length.

Diagram here....

  TCP can corrupt OTSnd data if not using OTData.

Using AckSend

By enabling the AckSend option on endpoint, you can eliminate the need for Open Transport to perform a memory copy of contiguous data to be transmitted by OTSnd. Instead, a pointer to the data will be passed downstream. Once the memory is no longer being used, the notifier receives a T_MEMORYRELEASED event.

esp good for datagram.. if frag > 8K flow control is required.

Note:
You don't have to wait for the T_MEMORYRELEASED event before calling OTSnd again, however you can't reuse any memory that you passed OTSnd until Open Transport has released it through the T_MEMORYRELEASED event.

The following snippet provides an example of usage:

    OTAckSends(ep)                      // enable AckSend option
    
    ......  
    
    buf = OTAllocMem( nbytes);          // Allocate nbytes of memory from OT
    OTSnd(ep, buf, nbytes, 0);          // send a packet 
    
    ......
    
    NotifyProc( .... void* theParam)    // Notifier Proc    
    
    case T_MEMORYRELEASED:              // process event   
            OTFreeMem( theParam);       // free up memory   
            break;

Note:
Because of the complexity of handling endpoint flow-control, Open Transport performance will suffer when the AckSend option is used to handle non-contiguous data, i.e., OTSnd that have been passed a OTData structure. Therefore, use AckSend only when sending contiguous data

IS THIS TRUE???

Sending Large Blocks of Data

Another way to improve the performance of a high volume network server is by minimizing the overhead incurred by OTSnd. You can do this by sending as large a block as the endpoint's transport service data unit (TSDU) will allow, thus reducing the number of times OTSnd is called.

You can determine the endpoints TSDU size by inspecting the TEndpointInfo returned by OTOpenEndpoint or OTGetEndpointInfo.

For endpoints that support infinite data unit size (T_INFINITE) such as TCP/IP, empirical evidence suggests that a size around 8K bytes might be optimal for ethernet. Other media may vary.

There are a number of tradeoffs involved in selecting the proper size block to pass to OTSnd, but the overall guideline is to do whatever you can to keep the outbound pipe full.

Flow Control

To take optimal advantage of Open Transport's throughput, your server should attempt to keep the outbound data stream full. In order to do this, your application must properly handle flow-control restrictions. Flow-control restrictions are imposed by Open Transport when only a part of the data passed to an endpoint can be accepted by the transport provider. This may be due to many things, including local memory restrictions or even network throughput limitations. In order to prevent data loss, Open Transport will impose a flow-control state on that endpoint.

How Open Transport handles flow control for a given endpoint depends on that endpoint's blocking mode. When an endpoint is in blocking mode, a send request such as OTSnd will wait for flow control to lift, then complete the send.

Conversely, when an endpoint is in non-blocking mode, OTSnd will return immediately with a value that is less than the value of the number of bytes passed to it, or if no bytes at all were sent, it will return kOTFlowErr.

Once in a flow-control state, the endpoint will remain there until the remote side has accepted the pending data. Once the flow-control restrictions are lifted your notifier will be issued a T_GODATA or T_GOEXDATA event.

Under a low memory condition it is possible for OTSnd to return a kENOMEMErr.In this case, you should back off and attempt to send later, possibly by means of a timer. Unlike the kOTFlowErr case, your application is not flow controlled and thus your notifier will not get a T_GODATA event.

Note:
If your application is calls OTSnd outside of your notifier for instance, at System Task time it should be prepared to handle problems similar to the OTRcv/T_DATA case outlined in the section, Avoiding Synchronization Problems.


[Prev] p. 1 2 3 4 5 6 7 8 [Next]