[threadpool] Improve the monitor thread heuristic
authorLudovic Henry <ludovic@xamarin.com>
Tue, 9 Feb 2016 19:17:14 +0000 (19:17 +0000)
committerLudovic Henry <ludovic@xamarin.com>
Tue, 9 Feb 2016 19:55:05 +0000 (19:55 +0000)
commit35c13bfe551d27e882a67031836fbc1a8e6f0fc7
treeeac5f295f6f80e765dd799bee26f01921c28dce6
parent7ecd89abdbacd5c7ace69f63ca73a6bee6a10ca6
[threadpool] Improve the monitor thread heuristic

Because the ThreadPool heuristic is optimized for short lived work item, it has more difficulty when executing long lived work item. That case can lead to a starvation of the worker threads: they are all doing work, while there is outstanding request, and these requests are not satisfied because we reached the max number of working thread.

To fix that issue, we have the monitor thread, whose sole job is to unstuck this kind of starvation cases. Unfortunately, it only works when all the worker threads are in the ThreadState.WaitSleepJoin state, which excludes the case of calling an IO operation in a Task. That includes the case of FileStream.BeginRead/Write/... which implementation can be simplified as follows: FileStream.BeginRead(...) -> Task.Run(() => FileStream.Read(...)).

The way we implement it in this commit is: every MONITOR_INTERVAL (500ms here), we check if there is any outstanding request, and if so, we assume that we are in the starvation case, and we simply increase the max number of working thread. Also to reduce the number of false positives, we do that only if there has been no completed work item for more than at least MONITOR_INTERVAL (in case of low CPU usage, more otherwise, see monitor_sufficient_delay_since_last_dequeue). This case is typically the case where we have all working thread stuck in long running work items.

Finally we increase the monitor interval from 100ms to 500ms so we guarantee we do not create more than 2 threads per second in the monitor thread. That is the value used by the old threadpool.
mono/metadata/threadpool-ms.c