Hi all..

I have run into this as well. One of my products uses 10GBaseT ethernet, and is 
often hobbled when moving data.
I don’t have a good solution to offer for performance, but this is what I have 
come up with.

- Sockets and NSObjects perform an awful lot of memcpy’s. (Unnecessary copying 
memory can be one huge waste of time..)
- There is no way to shortcut any stream/socket reads by providing a dedicated 
buffer. (i.e.: like a “PF_Ring" style ring buffer)

The way that I have improved this was to use GCDAsyncSocket, and then to 
provide my own subclass of NSMutableData.
This required me to hack the GCDAsyncSocket code to switch between a 
traditional NSMutableData object, and my own.
The solution worked pretty nicely. I was able to moderately reduce the number 
of memcpy’s, which in turn, picked up performance.

In my mind, the best solution is to create a pin-able piece of memory that 
can’t be paged out, and then have the networking stack “read/stream” functions 
write directly into it. I have considered writing a Network Kernel Extension, 
which would essential provide the functionality of PF_RING.. (This exists in 
Linux.) But it would involve a new set of skills.. :)

Curious to hear what others have done to pick up performance.

bob..


> On Sep 11, 2015, at 06:15, Jens Alfke <j...@mooseyard.com> wrote:
> 
> GCDAsyncSocket has an interesting approach, where you can tell it what you 
> want to read, like a certain number of bytes, or everything up to a specific 
> byte sequence (like CRLF), and it'll call you back when it's read it.
> 
> Another approach would be to use synchronous I/O calls, of course, but Cocoa 
> APIs don't make that easy to do.
> 
> —Jens 
> 
>> On Sep 10, 2015, at 6:12 PM, Adam Kaplan <adk...@gmail.com> wrote:
>> 
>> It’s amazing how many times we solve this same problem over-and-over. It’s 
>> so difficult because every case is slightly nuanced :(  
>> 
>> I agree with everything Jens said, as usual. A ring buffer is fastest, but 
>> if your max message size is unknown and you can’t do stream-style parsing, 
>> they’ll always be some nasty edge cases…
>> 
>> Just feeding into an NSMutableData is a good approach too and probably the 
>> most common. There are some downsides, such as multi-threaded parsing 
>> complexity and manually having to manage the addition and removal of data 
>> blocks.
>> 
>> A third tool in the arsenal is GCDs dispatch_data_t, which is very well 
>> suited for combining, traversing and removing arbitrarily-sized data blocks 
>> in a multi-threaded streaming environment. The downsides there are GCD's 
>> boilerplate overhead and a performance profile that is not always easy to 
>> reason about.  
>> 
>> — adam
>> 
>> 
>>> On Wednesday, September 9, 2015 at 6:30 PM, Jens Alfke wrote:
>>> 
>>> 
>>>> On Sep 9, 2015, at 2:07 PM, Motti Shneor <su...@bezeqint.net 
>>>> (mailto:su...@bezeqint.net)> wrote:
>>>> I need reading messages off the stream, each prefixed by 4 bytes 
>>>> containing its size. I was wondering if it was advisable to first read 
>>>> just the size (4 bytes) then read the rest of the message, or maybe it was 
>>>> better to have a big buffer into which to “drain” the stream, then parse 
>>>> my messages off the buffer?  
>>> 
>>> The first approach won’t work, because the amount of data received is 
>>> unpredictable. For instance you might receive only three bytes, which isn’t 
>>> enough to parse the data size. Or you might be able to read the data size, 
>>> but then try to read a 100000-byte message and get only 1500 bytes of it.
>>> 
>>> The usual approach when parsing data asynchronously from a network stream 
>>> is to keep a variable-size buffer of unparsed data. When data arrives, you 
>>> read all of it and append it to the buffer; then you try to parse the data 
>>> in the buffer. If there’s not enough to parse yet, you give up till there’s 
>>> more; or if you parse some data, you remove it from the start of the buffer.
>>> 
>>> So in your case you’d first check whether the buffer has at least four 
>>> bytes; if so, you look at the length, and check whether that many more 
>>> bytes are available. If they are, you read the whole message and remove it 
>>> from the buffer.
>>> 
>>> An NSMutableData object works well as a buffer, if you’re not too concerned 
>>> about high performance. The fastest implementation is probably some sort of 
>>> custom ring buffer.
>>> 
>>> —Jens
>>> _______________________________________________
>>> Do not post admin requests to the list. They will be ignored.
>>> Macnetworkprog mailing list (Macnetworkprog@lists.apple.com 
>>> (mailto:Macnetworkprog@lists.apple.com))
>>> Help/Unsubscribe/Update your Subscription:
>>> https://lists.apple.com/mailman/options/macnetworkprog/adkapx%40gmail.com
>>> 
>>> This email sent to adk...@gmail.com (mailto:adk...@gmail.com)  
>> 
>> 
> 
> _______________________________________________
> Do not post admin requests to the list. They will be ignored.
> Macnetworkprog mailing list      (Macnetworkprog@lists.apple.com)
> Help/Unsubscribe/Update your Subscription:
> https://lists.apple.com/mailman/options/macnetworkprog/bob%40gluetools.com
> 
> This email sent to b...@gluetools.com


 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Macnetworkprog mailing list      (Macnetworkprog@lists.apple.com)
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/macnetworkprog/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to