-
-
Notifications
You must be signed in to change notification settings - Fork 303
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Default 256 for bnd.executor.maximumPoolSize is excessive #6175
Comments
I think this is a reasonable suggestion. I tried it out locally, and could not observe a noticable negative difference for our project. Since you could set it via System.property one can set a higher value if needed. |
I can get a PR going but will likely be next week, unless someone gets to it before then. |
@bjhargrave any feedback on this? |
I always felt the enormous number was kind of annoying. But I recall vaguely something with download deadlocks. We download stuff massively with a new workspace. Since we use a thread per download, and these threads are suspended while waiting for input, we might have to give them a separate pool? |
This was the case. We did not have non-blocking I/O and we fanned out the many downloads across multiple threads. The repo code uses Promises but not always well. Sometimes the downloads blocked the the Promise callbacks (which generally should complete quickly) on I/O. 256 is a number I made up which was big enough that I did not hang because I was out of threads. I was primarily using the bnd Workspace as my "test" workspace. You will note that 256 is the MAX pool size not the default pool size. bnd/biz.aQute.bndlib/src/aQute/bnd/osgi/ExecutorGroup.java Lines 77 to 79 in c9ea777
So you only get 256 threads if something needs that many and this is probably downloads because you have massive repos. As Promise callbacks start blocking, new threads are requested from the pool to make progress. On a smaller workspace, you will probably never use that many (at least after startup). If you have a problem in Open Liberty, I would suggest you have all the developers set the
Perhaps moving to the new virtual threads for the executors will help. Then the repo impls could replace Promise usage (async programming) with boring old sync programming. Alternate would be a rewrite of the repo logic around removing blocking in Promise callbacks. Replacing the memoizing of the workspace to remove contention would also be nice but I am sure the contention would move somewhere deeper into the workspace startup. The Open Liberty workspace is absurdly large (>2000 projects). One of the repo |
I also recall that there was a solution to steal the current thread to run the callbacks? This tends to even out the load. I agree Liberty is insanely large but it is a wonderful testbed :-) |
This is the default behavior: But it does not help when the callback blocks on I/O. It also only applies when a callback is added to an already resolved Promise. If the Promise is not yet resolved, callbacks are added to a queue and when the Promise is resolved, the callbacks on the queue are dispatched to the executor so they can all end up in different threads so the callback execution is not serialized. |
Another idea may be to use an InlineExecutor for some Promises to force their callbacks to be run inline (and serialized). So top-level Promises would use the normal executor, but deeper Promises could use the InlineExecutor. But any Promise callback that blocks on I/O is still going to tie up the thread. Maybe virtual threads can help? |
based on
and
i dug a bit in the code: It seems all
And this What about introducing a
Wouldn't that give all "Downloads via HTTPClient" to run in a separate threadpool? |
So your idea is to use a different, smaller executor pool for HttpClient? How would you handle running out of threads? The current executors use a SynchronousQueue which will cause a rejection of work when there are no free threads and then the work runs on the caller's thread (RejectedExecutionHandler). This means you are still blocking the caller's thread for I/O. So this new executor for HttpClient would need to use a different queuing model to handle running out of threads which does not block the caller. |
Yes, but let's just stay with "different". I shouldn't have mentioned the sizing aspect. Maybe i misunderstood. Thus i brought up the places in the code up for discussion. But maybe I'm thinking to simple or haven't understood the problem. |
In looking through this, it seems most all of the issues are centered around use of bnd/bndtools.core/src/bndtools/central/Central.java Lines 353 to 359 in 75d7743
There are many callbacks queued up (one for each of the 2000 projects) and when the workspace promise is resolved, they all rush to execute consuming threads. And when the threads are all in use, they steal the caller's thread.
Changing the workspace promises to use a PromiseFactory with a custom executor will help. This could be an InlineExecutor to serialize all the callbacks onto the workspace promise resolver's thread. (Care then needs to be taken that the workspace promise resolver is not the main UI thread as this seems to be the case.) Or it could be an executor with a queue which has a smaller number of threads (16?) I would recommend pursuing a fix like this as I think it is fairly safe and easy to implement. |
It would also be good if it could be made so that the workspace promise is resolved AFTER the workspace is memoized. Not sure if that would be thread safe? |
This is a fun problem. Sorry I am no longer working on Bnd... |
On Tue, 9 July 2024, 7:46 pm BJ Hargrave, ***@***.***> wrote:
we might have to give them a separate pool
Perhaps moving to the new virtual threads for the executors will help.
Then the repo impls could replace Promise usage (async programming) with
boring old sync programming. Alternate would be a rewrite of the repo logic
around removing blocking in Promise callbacks.
This seems like an easy win. I have been following Project Loom (though not
so much recently) and it seemed like (in theory) it would solve many thread
contention issues simply, without the complexity of asynchronous
programming and callback chains. I am unsure as to the current state of
maturity of this project though - I don't think it made it into core Java
17?
—
… Reply to this email directly, view it on GitHub
<#6175 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/ABXDWF3BBRMKSPGRVALNXPLZLO2AVAVCNFSM6AAAAABKRF6LUGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDEMJXGI2DSNBZGM>
.
You are receiving this because you are subscribed to this thread.
Message ID: ***@***.***>
|
So are we!!! |
Catching up a bit while on vacation this week. I'm willing to try something out once I get back next week. I can also call on the Open Liberty developers to set the max pool size to something lower. I will also try importing into a fresh workspace with an empty .m2 cache to see how if that causes issues with a smaller pool size. |
I tried starting a new Eclipse workspace against a fresh clone of open-liberty and a fresh empty, local
|
You can see the parallelism in the Progress monitor. |
@tjwatson do we need to do anything or can this be closed? |
I'm still facing issues, even when I reduce the maximumPoolSize. It appears that is not the solution. It may involve one of the other suggestions to fix this. Unfortunately I am not familiar enough with the way BND behaves here to give something a try quickly. |
I will try to follow up on @bjhargrave suggestion from July 11th, to give central its own threadpool with a reasonable default. |
@juergen-albert since we're talking about releasing, will you fix this or should we close this? |
See:
bnd/biz.aQute.bndlib/src/aQute/bnd/osgi/ExecutorGroup.java
Lines 70 to 71 in c9ea777
For a very large workspace, like Open Liberty, this can cause massive contention on the
Memoize<Workspace>
inbndtools.central.Central.workspace
when launching the Eclipse workspace, in some cases it can take hours. If I setbnd.executor.maximumPoolSize
to something more reasonable (e.g. 16) then my workspace can launch much faster by allowing the threads to make progress without the massive contention.Here is a thread dump that shows the contention on
aQute.bnd.memoize.MemoizingSupplier@a4f5f834
out.threads.txtIt is unclear to me if the contention can somehow be removed, or if a better approach is to give a more reasonable default, like the number of cores available on the system.
The text was updated successfully, but these errors were encountered: