Skip to content
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

Immutable leak detection level #13459

Open
wants to merge 1 commit into
base: 4.1
Choose a base branch
from

Conversation

franz1981
Copy link
Contributor

Motivation:

Unstrusted fields from the JDK perspective are more costy and subsequent decisions cannot be constant folded

Modifications:

Create a new sys property to set it up

Result:

Better performance and likely smaller native images for DISABLED cases

@franz1981 franz1981 self-assigned this Jun 22, 2023
@franz1981
Copy link
Contributor Author

franz1981 commented Jun 22, 2023

I've created a small benchmark to show the benefits (not transitive ones eg constant fold of decisions) of this at franz1981/java-puzzles@20a9ceb

which got on

VM version: JDK 20.0.1, OpenJDK 64-Bit Server VM, 20.0.1+9
Benchmark                             Mode  Cnt           Score          Error  Units
EnumSwitch.decorateStable            thrpt   10   930543469.666 ± 13829443.763  ops/s
EnumSwitch.decorateStableFastPath    thrpt   10  1276226193.380 ± 13865208.113  ops/s
EnumSwitch.decorateUnstable          thrpt   10   734376175.307 ±  3692811.792  ops/s
EnumSwitch.decorateUnstableFastPath  thrpt   10   857378668.982 ±  8328131.819  ops/s

which show that the changes to allow a fast path on DISABLE always pay off but in the "stable" ie immutable level case it pays a lot.

@@ -150,13 +158,19 @@ public static boolean isEnabled() {
* Sets the resource leak detection level.
*/
public static void setLevel(Level level) {
if (stableLevel != null) {
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should better throw in this case.

Copy link
Contributor Author

@franz1981 franz1981 Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a stackless Unsupported Ex?
I'm saying that because maybe users don't want to have some special paths in their code able to set the level at runtime to handle the case when the level is "immutable"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure what is better... At least it wouldn't be surprising in a sense that while they think they use paranoid (for example) it not actually does.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Me neither, be silent doesn't seem right, I agree...a warn?

Copy link
Contributor Author

@franz1981 franz1981 Jun 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have noticed https://github.com/eclipse-vertx/vert.x/blob/6a8aefb6ec84278774d2c03fdae83fdf1deafded/src/main/java/io/vertx/core/impl/VertxImpl.java#L104: it means that if I won't expose something public to check if the immutable sys prop is there, with an exception, this one will crash the application while starting

or...

I just add a warn?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any suggestion @normanmaurer ? do you want me to add an exception for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure ... @chrisvest @trustin thoughts ?

Copy link
Contributor

@zakkak zakkak Jan 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking out loud, what about:

  1. Throwing an unsupported exception if the new level is different than the immutable one.
  2. Always require io.netty.leakDetection.level to be set when setting io.netty.immutableResourceLeakDetection. This way we avoid the vert.x case.

@franz1981
Copy link
Contributor Author

Note on the DISABLE fast path: why don't let the JIT do it?
Current JIT would profile the switch and extract (via a guard) the branch that's always met, adding an uncommon trap
in case something different is observed.
So, although the level is stable/immutable:

  • JIT would run in C1/interpreted profiling the frequencies of matched conditions
  • the final fast path would include an unwelcome guard, absent otherwise (by extracting manually the fastest path we care the most)

Motivation:

Unstrusted fields from the JDK perspective are more costy and subsequent decisions cannot be constant folded

Modifications:

Create a new sys property to set it up

Result:

Better performance and likely smaller native images for DISABLED cases
@franz1981
Copy link
Contributor Author

@normanmaurer I've added a new hint isImmutableDisabled (bad name I know) which can be used to manually propagate the static final decision at instance field level (by not allocating specific types and make obvious the recheability of methods and types, no needed in case of disabled level known at compile time).

This lead me to modify the default channel pipeline to do the same: instead of using an internal field touch it relies on the runtime decision, but it means that, if the level is not stable at runtime, the same pipeline can start not tracking anymore buffer(s) (no idea it wasn't like that before, maybe you have some historical data point or @trustin)

@geoand
Copy link
Contributor

geoand commented Jun 22, 2023

Just wanted to add, that I've talked with Franz about how he can check what kind of effect this has on a GraalVM native-image for Quarkus - I do expect it to have some small effect since the Graal compiler will theoretically be able to do more folding of the static part of the class(es) (which we do enable in Quarkus)

@hyperxpro
Copy link
Contributor

With the growing number of props, should we create a dedicated wiki page for props and their definition?

@franz1981
Copy link
Contributor Author

@zakkak I would like your opinion on this, related potential improvements we could get on native image or if we have other options which doesn't require it


private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetector.class);

static {
final boolean immutableLevel = SystemPropertyUtil.get("io.netty.immutableResourceLeakDetection") != null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest changing the property name and explicitly treating it as a boolean:

Suggested change
final boolean immutableLevel = SystemPropertyUtil.get("io.netty.immutableResourceLeakDetection") != null;
final boolean immutableLevel = Boolean.getBoolean("io.netty.leakDetection.level.immutable");

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but use SystemPropertyUtil.getBoolean() instead of Boolean.getBoolean()

@@ -97,10 +97,12 @@ static Level parseLevel(String levelStr) {
}

private static Level level;
private static final Level stableLevel;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe call it immutableLevel?

@@ -139,33 +147,43 @@ public static void setEnabled(boolean enabled) {
setLevel(enabled? Level.SIMPLE : Level.DISABLED);
}

private static boolean isImmutableDisabled() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be slightly better:

Suggested change
private static boolean isImmutableDisabled() {
private static boolean isImmutablyDisabled() {

@zakkak
Copy link
Contributor

zakkak commented Jan 23, 2024

@zakkak I would like your opinion on this, related potential improvements we could get on native image

Currently Quarkus sets io.netty.leakDetection.level to DISABLED when building a native-image (AFAIK there is no way to override this). So I would expect it to also set io.netty.immutableResourceLeakDetection if this PR eventually gets merged.

In theory (you could confirm it by setting app a small Quarkus test and observing the generated binary size, as well as the number of reachable classes/methods) this should suffice, and would give you the benefits you expect (i.e. the static analysis will understand that you are disabling the leak detection and throw away all relevant parts as dead code).

or if we have other options which doesn't require it

AFAIK this (i.e., guarding dead code inside if-else statements with conditions that are final and initialized at build time) is one of the best ways to go.

Comment on lines -164 to +186
private final Set<DefaultResourceLeak<?>> allLeaks =
private final Set<DefaultResourceLeak<?>> allLeaks = isImmutableDisabled()? null :
Collections.newSetFromMap(new ConcurrentHashMap<DefaultResourceLeak<?>, Boolean>());

private final ReferenceQueue<Object> refQueue = new ReferenceQueue<Object>();
private final Set<String> reportedLeaks =
private final ReferenceQueue<Object> refQueue = isImmutableDisabled()? null : new ReferenceQueue<Object>();
private final Set<String> reportedLeaks = isImmutableDisabled()? null :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't these changes break trackForcibly?

@normanmaurer
Copy link
Member

@franz1981 I am still not convinced we need to add this extra complexity for the relativ small win... wdyt ?

@franz1981
Copy link
Contributor Author

franz1981 commented Feb 25, 2024

@normanmaurer

I have yet to address the changes as suggested by @zakkak and verify what happen on native image; I have some gut feeling that for native image this could reduce memory footprint (which depends on recheability) quite a bit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants