On Sat, 07 Jun 2014 08:12:10 GMT, Johannes Pfau wrote:
So I debugged this a little and two things caught my attention:
Problem 1
https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/core/drivers/libevent2.d#L747
while ((m_activeEvents & which) == Trigger.none) getThreadLibeventDriverCore().yieldForEvent();
What if I created the
FileDescriptorEvent
withTrigger.any
, thenwait(Trigger.read)
? A connection will almost always be signalled as writeable, and as long as I don't write data it will stay writeable. So the event will trigger all the time and setm_activeEvents
toTrigger.write
causing a busy loop?I think vibed should rearm the event instead of using a repeating event, at least if the trigger changed.
Problem 2
But the real problem here is different: The event is not unarmed fast enough:
After wait yields hereonFileTriggered
is called once. The first timeevt.m_waiter
is set, the task is continued and wait returns as expected. However, the event is still alive andonFileTriggered
will be called many more times this time doing effectively nothing.evt.m_waiter
is null, so it only sets the triggers but nobody ever reads/writes data on the file descriptor andonFileTriggered
fires again and again. I'm not sure why this even stops eventually is this only because of the GC collecting theFileDescriptorEvent
? This is obviously also a problem even if data is still being read.The naive solution to both problems it to create the event in wait, then delete it as soon as wait completes. I guess you ruled that out for performance reasons?
The other solution for problem two is to
event_add
the event at the start ofwait
andevent_del
beforewait
returns. Problem 1 still needs to be solved then, though. Probably by creating a new event when the trigger type changes.
There is a third possible cause for the CPU spikes - the wait
overload that takes a Duration
uses a timer to handle the timeout, but there is currently an issue in rearmTimer
where it doesn't always remove the timer from the internal timer heap. This can cause the heap to grow to huge sizes, if rearmTimer
is used repeatedly. Eventually, once time progresses, the heap will be cleared again.
I've created a ticket (#695) to remember this. I'll try to perform some testing in the coming days.