-
Notifications
You must be signed in to change notification settings - Fork 37
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
New: Add INVOKEDYNAMIC
instrumentation.
#64
base: master
Are you sure you want to change the base?
Conversation
@LlamaLad7 Thank you for a great work! I have only some performance concerns. Do I understand correctly, that the Making a hash table lookup per every method call was way slower than field/condy approach |
No, the |
@LlamaLad7 Looks like you are right. It looks better in terms of bytecode modifications with a small extra overhead, compared to field access |
Yes, it will result in more lookups than the field approach, but for one-time costs I think this is acceptable, given the benefits of much simpler transformation and not disrupting the user code. |
I think it still worth running benchmarks |
Ah, I didn't notice those benchmarks. I will run them now.
It doesn't seem like the benchmarks currently have any way to compare different coverage approaches within a version, but I could add one if you like? |
Yes, it would be great |
You can reuse |
It seems that the test libs (apache commons and joda time) were built with java 8 and 5 respectively, so am I correct in thinking that I'd need to transform those jars to use the Java 11 classfile version for the benchmarks to be effective? |
Oh, I forgot about this. It makes everything complicated. You could try instrumenting |
Joda was built with Java 5, so assuming most of the time is spent in library classes it wouldn't be affected by either the indy or condy approaches. |
I don't think it would be too hard to manually force the jars onto classfile version 11, if that would be an acceptable solution. You would then of course only be able to run the benchmarks with JDK 11+ |
I was going to approach this with Gradle's Artifact Transforms, but I forgot that classes below Java 7 don't have frames, and computing them is not possible without the entire set of classes. |
I need to clean up the code a bit but the benchmark results are:
This does give me some doubts about the legitimacy of the joda time benchmark, but hopefully this helps to alleviate your performance concerns. |
Looks suspicious -- FieldCoverage should be the same as CondyCoverage
|
Some of the strange results might have been due to external workload, rerunning the joda tests gives:
which seems better.
just to check. I don't think it's unreasonable for the field approach to be slower, there's a lot of extra jumping on every method call to check if the field is initialized yet. |
I've pushed my changes if you want to try the benchmarks yourself. |
fa0ff77
to
16e6b56
Compare
This is needed to ensure we can test all the coverage approaches.
16e6b56
to
fb6d03c
Compare
Any updates on this? Since Kotlin/kotlinx-kover#673 was fixed I can work round the issue by filtering the instrumented classes, but it would be great not to have to. |
return fieldInstrumentation | ||
? new FieldCoverageDataAccess(data.get(Key.CLASS_READER), className, init) | ||
: new NameCoverageDataAccess(init); | ||
CoverageDataAccess.Init init = isArray ? createTestTrackingArrayInit(className) : createTestTrackingInit(className, true); |
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.
You can pull this code out of both else
branches
@@ -22,6 +22,7 @@ public class OptionsUtil { | |||
&& "true".equals(System.getProperty("idea.new.tracing.coverage", "true")); | |||
public static final boolean NEW_TEST_TRACKING_ENABLED = "true".equals(System.getProperty("idea.new.test.tracking.coverage", "true")); | |||
public static boolean CONDY_ENABLED = "true".equals(System.getProperty("coverage.condy.enable", "true")); | |||
public static boolean INDY_ENABLED = "true".equals(System.getProperty("coverage.indy.enable", "true")); |
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 think it worth setting this option to false
by default for now. This option can be much slower then the field access when all the methods are called exactly once.
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.
Happy to have it off by default if you're tentative, but IMO the 1-time extra hash table lookup per method should be quite comparable in cost to the extra transformation per method that the field approach does.
This adds an additional
CoverageDataAccess
option with an implementation usingINVOKEDYNAMIC
.It is suitable for class file versions from Java 7 onwards, but from Java 11 onwards the ConDy implementation takes precedence by default. Where possible the new approach takes precedence over the field-based approach.
The principle is very similar to the ConDy approach, where a bootstrap method is invoked to find the correct array, and the result is then cached by the JVM. Unlike the ConDy approach, one lookup is required per method rather than per class, since each individual call-site will use the BSM on first load. The one-time cost is therefore slightly higher, so it makes sense to use ConDy where possible, but the approaches are for the most part equivalent and the JITed assembly is the same for both.
Compared to the field approach, however, the important benefit is that the changes are invisible to the user program. Additionally, the transformation itself is much simpler, which should roughly balance out the extra one-time hashtable lookups.
My primary motivation for this is to fix various tests in the Kotlin compiler which are currently broken by the field instrumentation approach, e.g. this one, but in general it is good to disrupt the user code as little as possible.