Hi folks,

I just wanted to share the result of profiling the performance of the
compiler on "real world" classes, namely compiling the tests of Gradle. We
have a lot of tests, so compilation times becomes really a pain point, so I
have checked where we spend time. I have attached the export of hotspots
from a real compilation session.

It's no surprise to me, most of the time (70%) is spent in the resolve
visitor, and most of this time itself is spent in loading classes. We made
some improvements in the past, by not initializing those classes, but it's
still a crazy amount of time.

Similarly, we spend around 10% of our time in filling stack traces which
are used for flow control. Unfortunately we don't have the opportunity to
change this because it's either ClassNotFoundException (during resolution)
sent by the classloader, or ANTLR recognition exception, used for flow
control (duh!).

I remember that for Gradle I had implemented a custom ResolveVisitor that
adds some assumptions for Gradle scripts to avoid too many lookups for
classes which would obvisouly not exist, and it significantly improved the
performance of compiling scripts, but that was because there were lots of
implicit imports. For regular classes I'm not sure it's as simple.

Resolution is also very easy to break... Anyway, any change in this area
would probably make the lives of our users better!
CPU hot spots

+-----------------------------------------------------------------------------------------------------------------------------------------------------------+----------------+
|                                                                          
Method                                                                          
 |   Time (ms)    |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------+----------------+
|  java.net.URLClassLoader.findClass(String) URLClassLoader.java                
                                                                            |  
6,531   54 %  |
|  java.security.AccessController.doPrivileged(PrivilegedExceptionAction, 
AccessControlContext) AccessController.java (native)                            
  |  6,090   50 %  |
|  java.net.URLClassLoader$1.run() URLClassLoader.java                          
                                                                            |  
5,987   50 %  |
|  java.net.URLClassLoader$1.run() URLClassLoader.java                          
                                                                            |  
5,987   50 %  |
|  org.codehaus.groovy.control.ResolveVisitor.startResolving(ClassNode, 
SourceUnit) ResolveVisitor.java                                                 
    |  4,711   39 %  |
|  org.codehaus.groovy.control.ResolveVisitor.visitClass(ClassNode) 
ResolveVisitor.java                                                             
        |  4,711   39 %  |
|  org.codehaus.groovy.control.ResolveVisitor.resolve(ClassNode, boolean, 
boolean, boolean) ResolveVisitor.java                                           
  |  4,486   37 %  |
|  org.codehaus.groovy.control.ClassNodeResolver.findClassNode(String, 
CompilationUnit) ClassNodeResolver.java                                         
     |  4,363   36 %  |
|  org.codehaus.groovy.control.ClassNodeResolver.resolveName(String, 
CompilationUnit) ClassNodeResolver.java                                         
       |  4,363   36 %  |
|  
org.codehaus.groovy.control.ClassNodeResolver.tryAsLoaderClassOrScript(String, 
CompilationUnit) ClassNodeResolver.java                                   |  
4,363   36 %  |
|  org.codehaus.groovy.control.ResolveVisitor.resolveToOuter(ClassNode) 
ResolveVisitor.java                                                             
    |  4,363   36 %  |
|  groovy.lang.GroovyClassLoader.loadClass(String, boolean, boolean, boolean) 
GroovyClassLoader.java                                                        | 
 4,183   35 %  |
|  groovy.lang.GroovyClassLoader.loadClass(String, boolean, boolean) 
GroovyClassLoader.java                                                          
       |  3,984   33 %  |
|  org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit$1.call(SourceUnit, 
GeneratorContext, ClassNode) JavaAwareCompilationUnit.java                   |  
3,438   28 %  |
|  java.net.URLClassLoader.defineClass(String, Resource) URLClassLoader.java    
                                                                            |  
3,070   25 %  |
|  sun.misc.URLClassPath.getResource(String, boolean) URLClassPath.java         
                                                                            |  
2,978   25 %  |
|  java.lang.ClassLoader.defineClass(String, byte[], int, int, 
ProtectionDomain) ClassLoader.java                                              
             |  2,292   19 %  |
|  java.lang.ClassLoader.defineClass1(String, byte[], int, int, 
ProtectionDomain, String) ClassLoader.java (native)                             
            |  2,292   19 %  |
|  java.security.SecureClassLoader.defineClass(String, byte[], int, int, 
CodeSource) SecureClassLoader.java                                              
   |  2,292   19 %  |
|  sun.misc.URLClassPath$FileLoader.getResource(String, boolean) 
URLClassPath.java                                                               
           |  2,044   17 %  |
|  org.codehaus.groovy.control.ResolveVisitor.resolve(ClassNode) 
ResolveVisitor.java                                                             
           |  1,926   16 %  |
|  
org.codehaus.groovy.control.ResolveVisitor.resolveFromDefaultImports(ClassNode, 
boolean) ResolveVisitor.java                                             |  
1,743   14 %  |
|  org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ClassNode, String, 
ASTNode) ResolveVisitor.java                                                 |  
1,693   14 %  |
|  java.io.File.exists() File.java                                              
                                                                            |  
1,549   13 %  |
|  java.io.UnixFileSystem.getBooleanAttributes(File) UnixFileSystem.java        
                                                                            |  
1,549   13 %  |
|  java.io.UnixFileSystem.getBooleanAttributes0(File) UnixFileSystem.java 
(native)                                                                        
  |  1,549   13 %  |
|  org.codehaus.groovy.control.ResolveVisitor.resolveOrFail(ClassNode, ASTNode) 
ResolveVisitor.java                                                         |  
1,538   13 %  |
|  
org.codehaus.groovy.control.ResolveVisitor.resolveFromStaticInnerClasses(ClassNode,
 boolean) ResolveVisitor.java                                         |  1,520  
 13 %  |
|  
org.codehaus.groovy.control.ResolveVisitor.visitConstructorOrMethod(MethodNode, 
boolean) ResolveVisitor.java                                             |  
1,467   12 %  |
|  org.codehaus.groovy.control.ResolveVisitor.resolveNestedClass(ClassNode) 
ResolveVisitor.java                                                             
|  1,383   11 %  |
|  org.codehaus.groovy.control.CompilationUnit$12.call(SourceUnit) 
CompilationUnit.java                                                            
         |  1,329   11 %  |
|  org.codehaus.groovy.ast.ClassNode.lazyClassInit() ClassNode.java             
                                                                            |  
1,292   11 %  |
|  org.codehaus.groovy.vmplugin.v5.Java5.configureClassNode(CompileUnit, 
ClassNode) Java5.java                                                           
   |  1,292   11 %  |
|  sun.misc.URLClassPath$JarLoader.getResource(String, boolean) 
URLClassPath.java                                                               
            |  1,096    9 %  |
|  java.lang.Throwable.fillInStackTrace(int) Throwable.java (native)            
                                                                            |  
1,078    9 %  |
|  java.lang.Throwable.fillInStackTrace() Throwable.java                        
                                                                            |  
1,078    9 %  |
|  java.util.jar.JarFile.getEntry(String) JarFile.java                          
                                                                            |  
1,044    9 %  |
|  java.util.jar.JarFile.getJarEntry(String) JarFile.java                       
                                                                            |  
1,044    9 %  |
|  
org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitConstructorOrMethod(MethodNode,
 boolean) ClassCodeExpressionTransformer.java                 |  1,036    9 %  |
|  java.util.zip.ZipFile.getEntry(String) ZipFile.java                          
                                                                            |  
1,032    9 %  |
|  org.codehaus.groovy.control.CompilationUnit$17.call(SourceUnit, 
GeneratorContext, ClassNode) CompilationUnit.java                               
         |  1,030    9 %  |
|  org.codehaus.groovy.control.ResolveVisitor.transform(Expression) 
ResolveVisitor.java                                                             
        |    896    7 %  |
|  
org.codehaus.groovy.control.ResolveVisitor.visitBlockStatement(BlockStatement) 
ResolveVisitor.java                                                       |    
859    7 %  |
|  org.codehaus.groovy.classgen.AsmClassGenerator.visitClass(ClassNode) 
AsmClassGenerator.java                                                          
    |    791    7 %  |
|  groovyjarjarantlr.TokenBuffer.LA(int) TokenBuffer.java                       
                                                                            |   
 747    6 %  |
|  java.util.zip.ZipFile.getEntry(long, byte[], boolean) ZipFile.java (native)  
                                                                            |   
 743    6 %  |
|  
org.codehaus.groovy.ast.ClassCodeExpressionTransformer.visitExpressionStatement(ExpressionStatement)
 ClassCodeExpressionTransformer.java                 |    726    6 %  |
|  
org.codehaus.groovy.classgen.AsmClassGenerator.visitConstructorOrMethod(MethodNode,
 boolean) AsmClassGenerator.java                                      |    720  
  6 %  |
|  
org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor.findMethod(ClassNode,
 String, ClassNode[]) StaticTypeCheckingVisitor.java                    |    
709    6 %  |
|  org.codehaus.groovy.control.ResolveVisitor.resolveFromModule(ClassNode, 
boolean) ResolveVisitor.java                                                    
 |    685    6 %  |
|  java.lang.Class.getDeclaredMethods0(boolean) Class.java (native)             
                                                                            |   
 683    6 %  |
|  java.lang.Class.privateGetDeclaredMethods(boolean) Class.java                
                                                                            |   
 683    6 %  |
|  java.security.AccessController.doPrivileged(PrivilegedAction) 
AccessController.java (native)                                                  
           |    674    6 %  |
|  groovyjarjarantlr.TokenBuffer.fill(int) TokenBuffer.java                     
                                                                            |   
 669    6 %  |
|  org.codehaus.groovy.classgen.AsmClassGenerator.visitStdMethod(MethodNode, 
boolean, Parameter[], Statement) AsmClassGenerator.java                        
|    661    5 %  |
|  org.codehaus.groovy.ast.expr.BinaryExpression.visit(GroovyCodeVisitor) 
BinaryExpression.java                                                           
  |    649    5 %  |
|  org.codehaus.groovy.ast.stmt.IfStatement.visit(GroovyCodeVisitor) 
IfStatement.java                                                                
       |    644    5 %  |
|  
org.codehaus.groovy.classgen.AsmClassGenerator.visitBlockStatement(BlockStatement)
 AsmClassGenerator.java                                                |    629 
   5 %  |
|  
org.codehaus.groovy.classgen.asm.StatementWriter.writeBlockStatement(BlockStatement)
 StatementWriter.java                                                |    627   
 5 %  |
|  java.lang.Class.getDeclaredMethods() Class.java                              
                                                                            |   
 612    5 %  |
|  java.lang.Exception.<init>(String) Exception.java                            
                                                                            |   
 610    5 %  |
|  java.lang.Throwable.<init>(String) Throwable.java                            
                                                                            |   
 610    5 %  |
|  org.codehaus.groovy.classgen.AsmClassGenerator.visitMethod(MethodNode) 
AsmClassGenerator.java                                                          
  |    604    5 %  |
|  java.io.FileInputStream.read(byte[], int, int) FileInputStream.java          
                                                                            |   
 562    5 %  |
|  java.io.FileInputStream.readBytes(byte[], int, int) FileInputStream.java 
(native)                                                                        
|    562    5 %  |
|  
org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl.registerMethods(Class,
 boolean, boolean, Map) MetaClassRegistryImpl.java                     |    549 
   5 %  |
|  java.lang.Class.getDeclaredFields() Class.java                               
                                                                            |   
 527    4 %  |
|  java.lang.Class.getDeclaredFields0(boolean) Class.java (native)              
                                                                            |   
 527    4 %  |
|  java.lang.Class.privateGetDeclaredFields(boolean) Class.java                 
                                                                            |   
 527    4 %  |
|  
org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor.visitBinaryExpression(BinaryExpression)
 StaticTypeCheckingVisitor.java                       |    523    4 %  |
|  java.net.URL.<init>(URL, String) URL.java                                    
                                                                            |   
 508    4 %  |
|  java.net.URL.<init>(URL, String, URLStreamHandler) URL.java                  
                                                                            |   
 508    4 %  |
|  sun.net.www.protocol.file.Handler.parseURL(URL, String, int, int) 
Handler.java                                                                    
       |    508    4 %  |
|  java.lang.ClassNotFoundException.<init>(String) ClassNotFoundException.java  
                                                                            |   
 468    4 %  |
|  java.lang.Exception.<init>(String, Throwable) Exception.java                 
                                                                            |   
 468    4 %  |
|  java.lang.ReflectiveOperationException.<init>(String, Throwable) 
ReflectiveOperationException.java                                               
        |    468    4 %  |
|  java.lang.Throwable.<init>(String, Throwable) Throwable.java                 
                                                                            |   
 468    4 %  |
|  
org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.writeBlockStatement(BlockStatement)
 OptimizingStatementWriter.java                            |    465    4 %  |
|  sun.misc.Resource.getBytes() Resource.java                                   
                                                                            |   
 460    4 %  |
|  java.lang.String.indexOf(char[], int, int, char[], int, int, int) 
String.java                                                                     
       |    451    4 %  |
|  java.lang.String.indexOf(String, int) String.java                            
                                                                            |   
 451    4 %  |
|  java.net.URLStreamHandler.parseURL(URL, String, int, int) 
URLStreamHandler.java                                                           
               |    451    4 %  |
|  sun.misc.Resource.getByteBuffer() Resource.java                              
                                                                            |   
 449    4 %  |
|  sun.misc.Resource.cachedInputStream() Resource.java                          
                                                                            |   
 443    4 %  |
|  org.codehaus.groovy.ast.stmt.ReturnStatement.visit(GroovyCodeVisitor) 
ReturnStatement.java                                                            
   |    441    4 %  |
|  org.codehaus.groovy.reflection.ReflectionCache.getCachedClass(Class) 
ReflectionCache.java                                                            
    |    441    4 %  |
|  org.codehaus.groovy.ast.ClassNode.getUnresolvedSuperClass() ClassNode.java   
                                                                            |   
 441    4 %  |
|  org.codehaus.groovy.ast.ClassNode.getUnresolvedSuperClass(boolean) 
ClassNode.java                                                                  
      |    441    4 %  |
|  org.spockframework.compiler.SpockTransform.visit(ASTNode[], SourceUnit) 
SpockTransform.java                                                             
 |    438    4 %  |
|  org.codehaus.groovy.ast.ClassNode.getDeclaredMethods(String) ClassNode.java  
                                                                            |   
 423    3 %  |
|  
org.codehaus.groovy.classgen.AsmClassGenerator.visitExpressionStatement(ExpressionStatement)
 AsmClassGenerator.java                                      |    421    3 %  |
|  
org.codehaus.groovy.classgen.asm.StatementWriter.writeExpressionStatement(ExpressionStatement)
 StatementWriter.java                                      |    421    3 %  |
|  org.codehaus.groovy.ast.expr.DeclarationExpression.visit(GroovyCodeVisitor) 
DeclarationExpression.java                                                   |  
  417    3 %  |
|  java.security.AccessController.doPrivileged(PrivilegedAction, 
AccessControlContext) AccessController.java (native)                            
           |    416    3 %  |
|  
org.codehaus.groovy.ast.expr.ConstructorCallExpression.visit(GroovyCodeVisitor) 
ConstructorCallExpression.java                                           |    
412    3 %  |
|  org.codehaus.groovy.ast.ClassNode.getMethods(String) ClassNode.java          
                                                                            |   
 400    3 %  |
|  org.codehaus.groovy.control.io.FileReaderSource.getReader() 
FileReaderSource.java                                                           
             |    394    3 %  |
|  org.codehaus.groovy.control.ClassNodeResolver.tryAsScript(String, 
CompilationUnit, Class) ClassNodeResolver.java                                  
       |    378    3 %  |
|  
org.codehaus.groovy.control.ResolveVisitor.transformMethodCallExpression(MethodCallExpression)
 ResolveVisitor.java                                       |    375    3 %  |
|  groovy.lang.GroovyClassLoader.getSourceFile(String, String) 
GroovyClassLoader.java                                                          
             |    374    3 %  |
|  groovy.lang.GroovyClassLoader$1.loadGroovySource(String) 
GroovyClassLoader.java                                                          
                |    374    3 %  |
|  groovy.lang.GroovyClassLoader$1$1.run() GroovyClassLoader.java               
                                                                            |   
 374    3 %  |
|  groovy.lang.GroovyClassLoader$1$1.run() GroovyClassLoader.java               
                                                                            |   
 374    3 %  |
|  java.lang.ClassLoader.getResource(String) ClassLoader.java                   
                                                                            |   
 374    3 %  |
|  java.net.URLClassLoader.findResource(String) URLClassLoader.java             
                                                                            |   
 374    3 %  |
|  java.net.URLClassLoader$2.run() URLClassLoader.java                          
                                                                            |   
 365    3 %  |
|  java.net.URLClassLoader$2.run() URLClassLoader.java                          
                                                                            |   
 365    3 %  |
|  sun.misc.URLClassPath.findResource(String, boolean) URLClassPath.java        
                                                                            |   
 365    3 %  |
|  groovyjarjarantlr.InputBuffer.LA(int) InputBuffer.java                       
                                                                            |   
 358    3 %  |
|  org.codehaus.groovy.ast.ClassNode.getSuperClass() ClassNode.java             
                                                                            |   
 356    3 %  |
|  org.spockframework.compiler.SpockTransform$Impl.visit(ASTNode[], SourceUnit) 
SpockTransform.java                                                         |   
 354    3 %  |
|  java.io.BufferedInputStream.fill() BufferedInputStream.java                  
                                                                            |   
 353    3 %  |
|  java.io.BufferedInputStream.read() BufferedInputStream.java                  
                                                                            |   
 353    3 %  |
|  
org.codehaus.groovy.ast.ClassCodeVisitorSupport.visitConstructor(ConstructorNode)
 ClassCodeVisitorSupport.java                                           |    
348    3 %  |
|  org.spockframework.compiler.SpockTransform$Impl.processSpec(ClassNode, 
ErrorReporter, SourceLookup) SpockTransform.java                                
  |    343    3 %  |
|  
org.codehaus.groovy.classgen.asm.BinaryExpressionHelper.evaluateEqual(BinaryExpression,
 boolean) BinaryExpressionHelper.java                             |    339    3 
%  |
|  org.codehaus.groovy.util.LazyReference.get() LazyReference.java              
                                                                            |   
 334    3 %  |
|  org.codehaus.groovy.util.LazyReference.getLocked(boolean) LazyReference.java 
                                                                            |   
 334    3 %  |
|  org.codehaus.groovy.ast.expr.PropertyExpression.visit(GroovyCodeVisitor) 
PropertyExpression.java                                                         
|    334    3 %  |
|  
org.codehaus.groovy.control.ResolveVisitor.transformVariableExpression(VariableExpression)
 ResolveVisitor.java                                           |    333    3 %  
|
|  org.codehaus.groovy.ast.expr.Expression.transformExpressions(List, 
ExpressionTransformer) Expression.java                                          
      |    332    3 %  |
|  
org.codehaus.groovy.transform.sc.StaticCompilationVisitor.findMethodOrFail(Expression,
 ClassNode, String, ClassNode[]) StaticCompilationVisitor.java     |    329    
3 %  |
|  
org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor.findMethodOrFail(Expression,
 ClassNode, String, ClassNode[]) StaticTypeCheckingVisitor.java  |    329    3 
%  |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------+----------------+

Generated by YourKit Java Profiler 2017.02-b63 May 24, 2018 08:22:36 AM

Reply via email to