-
Notifications
You must be signed in to change notification settings - Fork 324
Use alternative weak-keyed map implementations to reduce work done in CommonTaskExecutor #1812
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
Conversation
tylerbenson
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job. I think we should merge the ClassValue changes even if we decide to skip the inlining.
|
Well, we really need to get the amount of background "work" down, whether it's by expunging inline or some other mechanism. |
f094977 to
f427454
Compare
…d background cleaning of WeakConcurrentHashMap which persists beyond the usage of the map, use ClassValue instead of WeakMap in JAX-RS instrumentations
f427454 to
ead09a5
Compare
|
I think there's another solution - don't use |
|
I'll admit I don't find WeakMap terribly helpful. I understand the idea of substituting out different WeakMaps, but in practice, I don't really want to do that. WeakMaps aren't really Maps per se but Caches. For me when writing a Cache, it is crucial to consider the eviction policy including cache size in context. WeakMap provides little control over the eviction policy which I find to be a major failure in its design. |
|
|
||
| private final WeakMap<ClassLoader, Boolean> injectedClassLoaders = newWeakMap(); | ||
| private final Map<ClassLoader, Boolean> injectedClassLoaders = | ||
| Collections.synchronizedMap(new WeakHashMap<ClassLoader, Boolean>()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that WeakHashMap is still doing expungeStaleEntries() inline. If that's the case, is it still better to use that instead of WeakConcurrentMap?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it does, whenever getTable() is called.
However, this question suggests that you may not have understood what I'm trying to achieve here. We have hundreds of background tasks executed once per second, because we use a WeakMap implementation with a "background" cleanup policy. These background tasks continue until the application shuts down, but the injectedClassLoaders map may never actually be used, and even if it is, its usefulness is short-lived and concentrated at the start of the application's life. To reduce the total cost of these maps' existence, increasing the costs of access (if the map is ever used) would make sense, but there's no evidence a synchronized wrapper around a WeakHashMap incurs significant (any?) cost over WeakConcurrentMap.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I understand what you're trying to achieve here. I just didn't understand why you chose this option vs the inline WeakConcurrentMap. That said, I don't disagree with your choice.
As for why the tests are failing, I'm not sure. I can look into it. Is it easy to reproduce if I run locally?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The motivation is for this to be completely independent of the (quite complex) provision mechanism. I don't expect there to be any contention on injectedClassLoaders and the wrapper is there as an insurance policy against multithreaded use, so I don't expect to get anything in return for using WeakConcurrentMap here. I found the changes necessary to support multiple WeakMap implementations broke the test suite mysteriously, in exactly the same way this commit does. (This is my second attempt at getting rid of these background tasks).
To reproduce, run
./gradlew :dd-java-agent:test --stacktrace
It will time out after 120s and probably give you as much information about why as can be seen here: none whatsoever :(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was reduced to putting System.err.printlns into CoreTracer's constructor - PendingTrace.initialize() hangs. It seems PendingTrace relies on HelperInjector to initialise the background clean up, I'd need to take a thread dump to check if it's deadlocked somehow, but that's a task for tomorrow.
I wonder why the author of this comment in CoreTracer just before initializing PendingTrace wrote this comment:
// Ensure that PendingTrace.SPAN_CLEANER is initialized in this thread:
// FIXME: add test to verify the span cleaner thread is started with this call.
PendingTrace.initialize();There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check out my latest commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, seems like we have a lot of brittleness in our initialization order.
I'd expect the first job to always start-up the background thread regardless of which job it is & order. From a maintenance perspective, it seems like a pretty serious design flaw to be relying on something else to start the pool.
This looks a nice improvement. Although, I'm wondering if we don't need to just take a hard look at our initialization in general.
|
I agree that the What's very interesting about this change is that certain tests time out as a result of this change: private final WeakMap<ClassLoader, Boolean> injectedClassLoaders = newWeakMap();to private final Map<ClassLoader, Boolean> injectedClassLoaders =
Collections.synchronizedMap(new WeakHashMap<ClassLoader, Boolean>());I previously found that tests would time out when I made it possible for |
|
Here's a thread dump of the hanging task, I can't see a dead lock here, but making sure the |
|
I hadn't realised how many |
|
As justification for the change, I put some tracing in to the With the change, after applying load, I see this (I included 2 duty cycles to draw attention to the variation in time of one of the tasks): The very slow task appears when the load starts - the map's purpose is for |
No description provided.