On Improving Open Transport Network Application PerformanceIncreasing 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
kOTNetbufDataIsOTBufferStarin the length parameter of theOTRcv. This will return you a pointer to theOTBufferstructure, as illustrated here:OTBuffer* myBuffer; OTResult result = OTRcv(myEndpoint, &myBuffer, kOTNetbufDataIsOTBufferStar);TheOTBufferdata structure is based on the STREAMSmblk_tdata 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
OTBufferstructure. You can useOTReadBufferto read data from the buffer, toOTBufferDataSizecalculate its total length andOTReleaseBufferto dispose of theOTBufferwhen 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
OTReleaseBufferto 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 theOTBufferdata 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 byOTSnd. Instead, a pointer to the data will be passed downstream. Once the memory is no longer being used, the notifier receives aT_MEMORYRELEASEDevent.esp good for datagram.. if frag > 8K flow control is required.
Note:
You don't have to wait for theT_MEMORYRELEASEDevent before callingOTSndagain, however you can't reuse any memory that you passed OTSnd until Open Transport has released it through theT_MEMORYRELEASEDevent.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.,OTSndthat have been passed aOTDatastructure. Therefore, use AckSend only when sending contiguous dataIS 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 byOTSnd. 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 timesOTSndis called.You can determine the endpoints TSDU size by inspecting the
TEndpointInforeturned byOTOpenEndpointorOTGetEndpointInfo.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
OTSndwill wait for flow control to lift, then complete the send.Conversely, when an endpoint is in non-blocking mode,
OTSndwill 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 returnkOTFlowErr.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_GODATAorT_GOEXDATAevent.Under a low memory condition it is possible for
OTSndto return akENOMEMErr.In this case, you should back off and attempt to send later, possibly by means of a timer. Unlike thekOTFlowErrcase, your application is not flow controlled and thus your notifier will not get aT_GODATAevent.
Note:
If your application is callsOTSndoutside of your notifier for instance, at System Task time it should be prepared to handle problems similar to theOTRcv/T_DATAcase outlined in the section, Avoiding Synchronization Problems.
[Prev] p. 1 2 3 4 5 6 7 8 [Next]