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

Optimize annotation metadata resolution performance #1717

Merged
merged 2 commits into from
May 25, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions benchmarks/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
plugins {
id "me.champeau.gradle.jmh" version "0.4.8"
}

dependencies {
annotationProcessor project(":inject-java")
annotationProcessor project(":validation")
compile project(":inject")
compile project(":validation")
compile project(":runtime")


jmh 'org.openjdk.jmh:jmh-core:1.21'
jmh 'org.openjdk.jmh:jmh-generator-annprocess:1.21'
}
jmh {
duplicateClassesStrategy = 'warn'
warmupIterations = 2
iterations = 4
fork = 1
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package io.micronaut.core.annotation;

public class AnnotationValueBenchmark {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package io.micronaut.core.convert;

import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.net.URI;

@State(Scope.Benchmark)
public class ConversionServiceBenchmark {

ConversionService conversionService;

@Setup
public void prepare() {
conversionService = ConversionService.SHARED;
}

@Benchmark
public void convertCacheHit() {
conversionService.convert("10", Integer.class);
}

@Benchmark
public void convertCacheMiss() {
conversionService.convert(URI.create("http://test.com"), Integer.class);
}

public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(".*" + ConversionServiceBenchmark.class.getSimpleName() + ".*")
.warmupIterations(3)
.measurementIterations(5)
.forks(1)
// .jvmArgs("-agentpath:/Applications/YourKit-Java-Profiler-2018.04.app/Contents/Resources/bin/mac/libyjpagent.jnilib")
.build();

new Runner(opt).run();
}
}
3 changes: 2 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -547,7 +547,8 @@ subprojects { Project subproject ->

if (
!subproject.name.startsWith('test-') &&
!subproject.toString().contains('build-projects')
!subproject.toString().contains('build-projects') &&
!subproject.toString().contains('benchmarks')
) {

apply from: "${rootProject.rootDir}/gradle/publishing.gradle"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import io.micronaut.core.type.Argument;
import io.micronaut.core.util.ArgumentUtils;
import io.micronaut.core.util.ArrayUtils;
import io.micronaut.core.util.StringUtils;
import io.micronaut.core.value.OptionalValues;

import javax.annotation.Nonnull;
Expand Down Expand Up @@ -456,7 +457,7 @@ default boolean isDeclaredAnnotationPresent(@Nonnull Class<? extends Annotation>
* @return The {@link AnnotationValue}
*/
@Override
default @Nonnull <T extends Annotation> Optional<AnnotationValue<T>> findAnnotation(@Nonnull Class<T> annotationClass) {
default @Nonnull <T extends Annotation> Optional<AnnotationValue<T>> findAnnotation(@Nonnull Class<T> annotationClass) {
ArgumentUtils.requireNonNull("annotationClass", annotationClass);
Repeatable repeatable = annotationClass.getAnnotation(Repeatable.class);
if (repeatable != null) {
Expand Down Expand Up @@ -551,7 +552,7 @@ default boolean isDeclaredAnnotationPresent(@Nonnull Class<? extends Annotation>
* @param annotation The annotation
* @return An {@link Optional} class
*/
default @Nonnull Optional<Class> classValue(@Nonnull String annotation) {
default @Nonnull Optional<Class<?>> classValue(@Nonnull String annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);
return classValue(annotation, VALUE_MEMBER);
}
Expand All @@ -563,11 +564,13 @@ default boolean isDeclaredAnnotationPresent(@Nonnull Class<? extends Annotation>
* @param member The annotation member
* @return An {@link Optional} class
*/
default @Nonnull Optional<Class> classValue(@Nonnull String annotation, @Nonnull String member) {
default @Nonnull Optional<Class<?>> classValue(@Nonnull String annotation, @Nonnull String member) {
ArgumentUtils.requireNonNull("annotation", annotation);
ArgumentUtils.requireNonNull("member", member);

return getValue(annotation, member, Class.class);
Optional value = getValue(annotation, member, Class.class);
//noinspection unchecked
return value;
}

/**
Expand All @@ -576,10 +579,10 @@ default boolean isDeclaredAnnotationPresent(@Nonnull Class<? extends Annotation>
* @param annotation The annotation
* @return An {@link Optional} class
*/
default @Nonnull Optional<Class> classValue(@Nonnull Class<? extends Annotation> annotation) {
default @Nonnull Optional<Class<?>> classValue(@Nonnull Class<? extends Annotation> annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);

return classValue(annotation.getName());
return classValue(annotation, VALUE_MEMBER);
}

/**
Expand All @@ -589,13 +592,15 @@ default boolean isDeclaredAnnotationPresent(@Nonnull Class<? extends Annotation>
* @param member The annotation member
* @return An {@link Optional} class
*/
default @Nonnull Optional<Class> classValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
default @Nonnull Optional<Class<?>> classValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
ArgumentUtils.requireNonNull("annotation", annotation);
ArgumentUtils.requireNonNull("member", member);

return classValue(annotation.getName(), member);
}



/**
* The value as an {@link OptionalInt} for the given annotation and member.
*
Expand All @@ -611,6 +616,97 @@ default boolean isDeclaredAnnotationPresent(@Nonnull Class<? extends Annotation>
return result.map(OptionalInt::of).orElseGet(OptionalInt::empty);
}

/**
* The value as an {@link OptionalInt} for the given annotation and member.
*
* @param annotation The annotation
* @param member The member
* @return THe {@link OptionalInt} value
*/
default @Nonnull OptionalInt intValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think the @Nonnull annotation may be redundant here. Kotlin treats Optional as non null without the annotation. I haven't tested OptionalInt, though I assume it works the same

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks will remove them

ArgumentUtils.requireNonNull("annotation", annotation);
return intValue(annotation.getName(), member);
}

/**
* The value as an {@link OptionalInt} for the given annotation and member.
*
* @param annotation The annotation
* @return THe {@link OptionalInt} value
*/
default @Nonnull OptionalInt intValue(@Nonnull Class<? extends Annotation> annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);
return intValue(annotation, VALUE_MEMBER);
}

/**
* The value as an optional string for the given annotation and member.
*
* @param annotation The annotation
* @param member The member
* @return The string value if it is present
*/
default @Nonnull Optional<String> stringValue(@Nonnull String annotation, @Nonnull String member) {
ArgumentUtils.requireNonNull("annotation", annotation);
ArgumentUtils.requireNonNull("member", member);

return getValue(annotation, member, String.class);
}

/**
* The value as an optional string for the given annotation and member.
*
* @param annotation The annotation
* @param member The member
* @return The string value if it is present
*/
default @Nonnull Optional<String> stringValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
ArgumentUtils.requireNonNull("annotation", annotation);
return stringValue(annotation.getName(), member);
}

/**
* The values as string array for the given annotation and member.
*
* @param annotation The annotation
* @param member The member
* @return The string values if it is present
*/
default @Nonnull String[] stringValues(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
return StringUtils.EMPTY_STRING_ARRAY;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why doesn't this implementation default to getting the values the old way?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could do, but the old ways performance is not good. This method is overridden anyway be the implementation. I put this in there for backwards compatibility so if someone had implemented this interface (unlikely) it would still compile.

}

/**
* The values as string array for the given annotation and member.
*
* @param annotation The annotation
* @return The string values if it is present
*/
default @Nonnull String[] stringValues(@Nonnull Class<? extends Annotation> annotation) {
return stringValues(annotation, VALUE_MEMBER);
}

/**
* The value as an optional string for the given annotation and member.
*
* @param annotation The annotation
* @return The string value if it is present
*/
default @Nonnull Optional<String> stringValue(@Nonnull Class<? extends Annotation> annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);
return stringValue(annotation, VALUE_MEMBER);
}

/**
* The value as an optional string for the given annotation and member.
*
* @param annotation The annotation
* @return The string value if it is present
*/
default @Nonnull Optional<String> stringValue(@Nonnull String annotation) {
return stringValue(annotation, VALUE_MEMBER);
}

/**
* The value as an {@link OptionalDouble} for the given annotation and member.
*
Expand All @@ -626,6 +722,29 @@ default boolean isDeclaredAnnotationPresent(@Nonnull Class<? extends Annotation>
return result.map(OptionalDouble::of).orElseGet(OptionalDouble::empty);
}

/**
* The value as an {@link OptionalDouble} for the given annotation and member.
*
* @param annotation The annotation
* @param member The member
* @return THe {@link OptionalDouble} value
*/
default @Nonnull OptionalDouble doubleValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
ArgumentUtils.requireNonNull("annotation", annotation);
return doubleValue(annotation.getName(), member);
}

/**
* The value as an {@link OptionalDouble} for the given annotation and member.
*
* @param annotation The annotation
* @return THe {@link OptionalDouble} value
*/
default @Nonnull OptionalDouble doubleValue(@Nonnull Class<? extends Annotation> annotation) {
ArgumentUtils.requireNonNull("annotation", annotation);
return doubleValue(annotation, VALUE_MEMBER);
}

/**
* Get the value of default "value" the given annotation.
*
Expand Down Expand Up @@ -709,7 +828,7 @@ default boolean isPresent(@Nonnull String annotation, @Nonnull String member) {
}

/**
* Returns whether the value of the given member is <em>true</em>.
* Returns whether the value of the given member is present.
*
* @param annotation The annotation class
* @param member The annotation member
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,65 @@
* @since 1.0
*/
public interface AnnotationMetadataDelegate extends AnnotationMetadataProvider, AnnotationMetadata {
@Nonnull
@Override
default String[] stringValues(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
return getAnnotationMetadata().stringValues(annotation, member);
}

@Nonnull
@Override
default String[] stringValues(@Nonnull Class<? extends Annotation> annotation) {
return getAnnotationMetadata().stringValues(annotation, AnnotationMetadata.VALUE_MEMBER);
}

@Nonnull
@Override
default OptionalInt intValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
return getAnnotationMetadata().intValue(annotation, member);
}

@Nonnull
@Override
default OptionalInt intValue(@Nonnull Class<? extends Annotation> annotation) {
return getAnnotationMetadata().intValue(annotation);
}

@Nonnull
@Override
default Optional<String> stringValue(@Nonnull String annotation, @Nonnull String member) {
return getAnnotationMetadata().stringValue(annotation, member);
}

@Nonnull
@Override
default Optional<String> stringValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
return getAnnotationMetadata().stringValue(annotation, member);
}

@Nonnull
@Override
default Optional<String> stringValue(@Nonnull Class<? extends Annotation> annotation) {
return getAnnotationMetadata().stringValue(annotation);
}

@Nonnull
@Override
default Optional<String> stringValue(@Nonnull String annotation) {
return getAnnotationMetadata().stringValue(annotation);
}

@Nonnull
@Override
default OptionalDouble doubleValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
return getAnnotationMetadata().doubleValue(annotation, member);
}

@Nonnull
@Override
default OptionalDouble doubleValue(@Nonnull Class<? extends Annotation> annotation) {
return getAnnotationMetadata().doubleValue(annotation);
}

@Override
default @Nonnull <T> Optional<T> getValue(@Nonnull String annotation, @Nonnull Argument<T> requiredType) {
Expand Down Expand Up @@ -191,22 +250,22 @@ default boolean isDeclaredAnnotationPresent(@Nonnull Class<? extends Annotation>
}

@Override
default @Nonnull Optional<Class> classValue(@Nonnull String annotation) {
default @Nonnull Optional<Class<?>> classValue(@Nonnull String annotation) {
return getAnnotationMetadata().classValue(annotation);
}

@Override
default @Nonnull Optional<Class> classValue(@Nonnull String annotation, @Nonnull String member) {
default @Nonnull Optional<Class<?>> classValue(@Nonnull String annotation, @Nonnull String member) {
return getAnnotationMetadata().classValue(annotation, member);
}

@Override
default @Nonnull Optional<Class> classValue(@Nonnull Class<? extends Annotation> annotation) {
default @Nonnull Optional<Class<?>> classValue(@Nonnull Class<? extends Annotation> annotation) {
return getAnnotationMetadata().classValue(annotation);
}

@Override
default @Nonnull Optional<Class> classValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
default @Nonnull Optional<Class<?>> classValue(@Nonnull Class<? extends Annotation> annotation, @Nonnull String member) {
return getAnnotationMetadata().classValue(annotation, member);
}

Expand Down
Loading