Hi Biping,

(including the Drizzle mailing list for more feedback)

On Thu, May 07, 2009 at 07:36:04PM +0800, Biping MENG wrote:
>    I've got some questions about the pool of threads scheduler here.
>    As far as I know, libevent uses Level Trigger epoll on READ/WRITE event on
>    the Linux platform. Epoll don't perform so excellent in this mode,
>    especially when watching on too many FDs. So may it be a possible reason
>    of low performance?

I don't think libevent is the performance culprit here. The usage of
libevent in the current pool of threads is not optimal, but it's not
a significant overhead (at least I think).

I think the bigger problem is that libevent is only being used when
waiting for a new command (not for reading if the command is big or
when writing the command out). This means the threads in the pool
may be stuck blocking on socket I/O and/or disk I/O, which is bad
when you have a fixed pool size. You may have new commands ready to
run but there are no free threads because they are all blocking on
something else.

Unfortunately this is not easily fixed, since the I/O code is spread
throughout the query processing. We would need to make much of it
stateful so it could yield the threads when it knows it will be
blocking. This will be a big task, but ultimately, will be a big
win. :)

Stewart has also been looking at using fibers here (usserland
threads) where Drizzle would essentially have it's own userland
threading library. This would allow a scheduler to switch between
"threads" when they are blocking, allowing us to avoid making the
query execution code stateful. I'll let him comment more on this. :)

>    How do we set size? I mean, size of the pool that containing working
>    threads. Do we try to know the number of cores on the machine through some
>    API, and set the size accordingly? I thought the most great advantage of
>    pool of threads scheduling over multi-threads scheduling should be pool of
>    threads has a definitely control over the number of concurrent working
>    threads, and thus, could avoid some CPU consumption spent on context
>    switch. So we have to set the size of pool equal to the core number to
>    take good advantage of this saving. Do I take it right?

Well, this entirely depends on the load. If we are CPU bound and
the threads never block for any reason (disk, network, ...) having
the same number of threads as we have cores is what we probably
the correct answer. As soon as the threads can block for any reason
(introduce idle CPU time), we need to start adding more threads into
the pool to make sure there is always something to run. This is where
some benchmarking would come in handy to see what the optimal balance
is between thread count, CPU usage, and the context-switching overhead.

Like I said above though, I think the "correct" solution is to never
allow these threads to block and work towards an execution engine that
can be stateful to yield the threads they are running on when possible.
Some blocking factors, like disk I/O, are not always possible to
yield on so we may want to look at using an async queue and a pool
of threads dedicated to disk I/O. This allows operations that are
normally blocking to be non-blocking for threads (allowing them to
yield). I realize these may be high-hopes, but we can get there. :)

-Eric

_______________________________________________
Mailing list: https://launchpad.net/~drizzle-discuss
Post to     : [email protected]
Unsubscribe : https://launchpad.net/~drizzle-discuss
More help   : https://help.launchpad.net/ListHelp

Reply via email to