[erlang-questions] why is gen_tcp:send slow?

Rapsey <>
Thu Jun 19 20:06:13 CEST 2008


It loops from another module, that way I can update the code at any time
without disrupting anything.
The packets are generally a few hundred bytes big, except keyframes which
tend to be in the kB range. I haven't tried looking with wireshark.  Still
it seems a bit odd that a large CPU consumption would be the symptom. The
traffic is strictly one way. Either someone is sending the stream or
receiving it.
The transmit could of course be written with a passive receive, but the code
would be significantly uglier. I'm sure someone here knows if setting
{active, once} every packet is CPU intensive or not.
It seems the workings of gen_tcp is quite platform dependent. If I run the
code in windows, sending more than 128 bytes per gen_tcp call significantly
decreases network output.
Oh and I forgot to mention I use R12B-3.


Sergej

On Thu, Jun 19, 2008 at 7:39 PM, Edwin Fine <>
wrote:

> How large is each packet? Can multiple packets fit into one TCP window?
> Have you looked at the TCP/IP wire-level data with Wireshark/Ethereal to see
> if the packets are being combined at the TCP level? If you see that you are
> only getting one packet per TCP frame (assuming a packet is much smaller
> than the window size), you might be falling foul of the Nagle congestion
> algorithm. The fact that manually buffering your packets improves
> performance suggests this may be the case. Nagle says that send, send, send
> is OK, receive, receive, receive is ok, and even send, receive, send,
> receive is ok, but you get into trouble if sends and receives are mixed
> asymmetrically on the same socket (e.g. send, send, receive).
>
> Also, I don't understand your transmit_loop. Where is it looping (or am I
> misunderstanding something)?
>
> From what I have seen, people writing Erlang TCP/IP code do an {active,
> once} receive, and when getting the first packet, drop into another loop
> that does a passive receive until there's no data waiting, then go back into
> the {active, once} receive. Are you doing this? I am not sure, but I fear
> that if all your receives are {active, once} it will incur more CPU overhead
> than the active/passive split. It's hard to know because I can't see enough
> of your code to know what you are doing overall. Disclaimer: I'm no Erlang
> or TCP/IP expert.
>
> Hope this helps.
>
> 2008/6/19 Rapsey <>:
>
>> I have a streaming server written in Erlang. When it was pushing 200-300
>> mb/s the CPU was getting completely hammered. I traced the problem to
>> gen_tcp:send.
>> So instead of sending every audio/video packet with a single gen_tcp:send
>> call, I buffer 3 packets and then send them all at once. CPU consumption
>> dropped dramatically.
>> On one of the servers I have a simple proxy, the main process that sends
>> packets between the client and some other server looks like this:
>>
>> transmit_loop({tcp, Sock, Data}, P) when P#transdat.client == Sock ->
>>     gen_tcp:send(P#transdat.server, Data),
>>     inet:setopts(P#transdat.client, [{active, once}]),
>>     {ok, P};
>> transmit_loop({tcp, Sock, Data}, P) when P#transdat.server == Sock ->
>>     gen_tcp:send(P#transdat.client, Data),
>>     inet:setopts(P#transdat.server, [{active, once}]),
>>     {ok, P};
>> transmit_loop({start, ServerPort}, P) ->
>>     {ok, Sock} = gen_tcp:connect("127.0.0.1", ServerPort, [binary,
>> {active, once}, {packet, 0}]),
>>     {ok, P#transdat{server = Sock}};
>> transmit_loop({tcp_closed, _}, _) ->
>>     exit(stop).
>>
>> The proxy is eating more CPU time than the streaming server.
>> Is this normal behavior? The server is running  OSX 10.4
>>
>>
>> Sergej
>>
>> _______________________________________________
>> erlang-questions mailing list
>> 
>> http://www.erlang.org/mailman/listinfo/erlang-questions
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20080619/fc643c18/attachment.html>


More information about the erlang-questions mailing list