<div dir="ltr"><div>That's super interesting information, and once the port's buffer fills up once I can totally see now how it could get into cascading performance issues, since once the message queue is backed up with A/V data messages from the publisher's process every gen_tcp:send/3 call now has to do a selective receive past all of them to find the inet_reply message.  <br></div><div><br></div><div>Thanks!</div><div><br></div><div class="gmail_extra"><div class="gmail_quote">On Sun, Dec 4, 2016 at 9:13 PM, Fred Hebert <span dir="ltr"><<a href="mailto:mononcqc@ferd.ca" target="_blank">mononcqc@ferd.ca</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 12/04, Matthew Shapiro wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Yeah I think I can safely say this is something to do with how VLC is<br>
functioning.  Even remotely I'm getting stuck in send, though not as bad,<br>
and looking at what's going on in the difference between VLC and Ffmpeg I<br>
believe my timestamps are being unexpected and both are reacting weirdly<br>
too it, with VLC trying to slow the feed down for whatever reason and that<br>
may be causing it to be slow to do a TCP read.  Shot in the dark but at<br>
least I know now that it's not an BEAM issue (and my time on this hasn't<br>
been to waste).<br>
<br>
So sorry for the thread when Erlang/Beam isn't at fault in the end :)<br>
<br>
</blockquote>
<br></span>
It is and it is not. One of the interesting things with the TCP stack is that it sends a signal through ports, and if the send queue is full, the whole thing blocks; it however blocks with live data in there, and there's no good way to give it up.<br>
<br>
The reason is blocks that the TCP work is done over a port program, meaning message passing takes place:<br>
<br>
   Erlang Process               TCP port program<br>
        |                               |<br>
        |----------- Data ------------->|<br>
        |                               |<br>
        |<--- {inet_reply,S,Status} ----|<br>
<br>
This is roughly what takes place within the thing. This is done through calling erlang:port_command/2-3. The thing though is that if the buffer of the port program is full, you get descheduled until there's place.<br>
<br>
There's a cheat though, one we at Heroku have used in Logplex. The trick is to bypass the stack in critical 'must never block' circumstances and call port_command yourself, but by passing in the option list '[nosuspend]'.<br>
<br>
When you do this and the port program representing the TCP socket is busy, you'll get a 'false' return value indicating it failed because it was full (you get 'true' when it works):<br>
<br>
   case erlang:port_command(Socket, Data, [nosuspend]) of<br>
       false -><br>
           handle_busy(...);<br>
       true -><br>
           receive<br>
               {inet_reply, Socket, Status} -> % Status == send return<br>
                   Status<br>
           end<br>
   end<br>
<br>
This will let you do things like figure out the consumer side (in this case VLC) is too slow, and possibly give up sending a few frames and send newer ones later.<br>
<br>
Control flow is fun!<br>
<br>
Regards,<br>
Fred.<br>
</blockquote></div><br></div></div>