[Live-devel] Performance
Marc Neuberger
mjn at oxysys.com
Fri Jun 1 13:34:57 PDT 2007
A couple of months ago, there was a discussion of performance of the
live555 libraries on Linux, and the discussion turned to the efficiency
of select() vs. epoll().
Studying the performance my own epoll()-based scheduler, I strongly
suspect that the far bigger source of inefficiency is the DelayQueue
implementation that BasicTaskScheduler0 uses. This queue is a linked
list, causing O(n) cost to adding and deleting timers. Which happens a
lot. If I understand the behavior correctly, a 45-second idle timer is
rescheduled on each packet. This almost invariably goes to the end of
the scheduling queue.
With the stock code, I had results similar to Vlad Seyakov's: I petered
out at about 140-150 sessions. With my rewritten scheduler, I've been
able to get to 400-500 sessions. My scheduling queue is based on an STL
set<> with an appropriate less-than operator. This provides O(log n)
insert/delete. Even so, I find that scheduling and unscheduling timers
accounts for approximately 1/3 of the CPU at 400 sessions.
I made one other observation: readSocket() in GroupsockHelper.cpp calls
blockUntilReadable(). blockUntilReadable() uses select() to wait for the
socket to be ready. This has two problems: first, we really shouldn't
ever be blocking, since this blocks all sessions: if the data isn't
ready, we should go back to the event loop. This should happen rarely,
if ever, of course, since presumably we're only calling this after a
select()/epoll() has triggered. The larger problem is that the use of
select() a server to 1024 file descriptors unless you override the size
of fd_sets in your build, and that of course, creates a performance
degradation. Architecturally is seems a little harder to replace parts
of groupsock than to replace parts of UsageEnvironment to make changes
like this.
Marc Neuberger
More information about the live-devel
mailing list