CodeNarc performance drop after versions update


(Tomasz Przybysz) #1

After upgrading Gradle from 2.2.1 to 2.4 and CodeNarc (toolVersion from 0.21 to 0.23) I’ve noticed significant performance drop of CodeNarc tasks.
Moreover, it is not so rare to see java.lang.OutOfMemoryError: PermGen space now.

It’s not only on my ‘box’ but team members and jenkins boxes too.

How performance may be optimized and what’s the proper way of
setting bigger max PermGen space for CodeNarc? I mean, is $GRADLE_OPTS env variable being
propagated CodeNarc? Does it spawn own process?
It’s quite strange that PermGen happens only every few other runs, not each time - even on boxes without daemon set to true.

Let me add that the build runs on fairly small codebase. Less than 20 source files, average up to 50 lines per file.


(Benjamin Muschko) #2

The CodeNarc analysis does not run in a forked JVM process so whatever you use for $GRADLE_OPTS will be used. If you are concerned about CodeNarc 2.4, you can always go back to CodeNarc 2.2.1 by configuring the CodeNarc plugin.


(Tomasz Przybysz) #3

Thanks for info.

Do you mean I can switch back to older CodeNarc or Gradle as there is some tool name and version mismatch in your reply?

Anyway, I wouldn’t like staying behind neither with Gradle nor CodeNarc. Especially CodeNarc - older version was failing to compile some sources. Not sure is it related to bug fixes done with newer version or maybe the fact that CodeNarc pulls own (older) Groovy version as dependency thus it tries to compile with outdated one comparing to the one sources are written with. I mean unless dependency version eviction works well for codenarc gradle configuration, does it?

Now I’m running Gradle with following options:
-Xmx128m -Xmx512m -XX:PermSize=64m -XX:MaxPermSize=256m
…and daemon enabled. It helped significantly.

This way or the other I thought it’s good to bring performance drop and out of PermGen issue happing more often under the tool developers attention. No feedback - no improvement, yep?


(Benjamin Muschko) #4

It’s very likely that the latest version of CodeNarc consumes more memory. You don’t have to stay behind on the Gradle side. All I am saying is that you can change the version of CodeNarc through the extension.

CodeNarc doesn’t compile the Groovy code. It’s the Gradle Groovy plugin that does it. The CodeNarc analysis in Gradle runs with an isolated classpath as far as I know.


(Tomasz Przybysz) #5

I’m aware of toolVersion property, I use it and even mentioned in the first post. Confusion came from your previous post as you mentioned switching back with CodeNarc version while the versions you used are Gradle versions. CodeNarc versions under debate are 0.21 and 0.23. Never mind though and thanks for clarification.

We’ll get here a bit out of scope of my former question, I hope that’s OK.
Compilation - maybe that’s only confusing message from CodeNarc but there you go:

:my-project:codenarcMain
Compilation failed for [SourceFile[C:\path\to\my-project\src\main\groovy\com\domain\something\SomeClass.groovy]].

I altered paths and names in the above but Compilation failed for is original and comes from CodeNarc (doesn’t fail a build, the source file is skipped from being analysed).
I’m not certain about that but I think some CodeNarc rules require compilation and it’s being done within codenarcMain/codenarcTest task. Could you clarify that, please?
Maybe it’s worth of adding that the above message still appears with CodeNarc version 0.22, but on the same codebase and CodeNarc 0.23 it’s all right. There is quite a big difference in Groovy versions used between those two CodeNarc versions though (mentioned below).

Speaking about classpath, yup it’s certainly done in isolation or at least it has been. I wonder which groovy version is used now though. The one on which CodeNarc depends or the one specified in compile configuration for use of the groovy plugin itself.
I was assuming the first is true, especially I can see the older version of groovy is (or was) being downloaded (the one CodeNarc depends on) and because of that I though it fails to compile some source files as the sources being analysed are written with newer groovy version than CodeNarc uses. However this made me confused again:

Command issued: gradle dependencies --configuration=codenarc

With CodeNarc version 0.22 it gives:

codenarc - The CodeNarc libraries to be used for this project.
\--- org.codenarc:CodeNarc:0.22
     +--- org.gmetrics:GMetrics:0.5
     |    \--- org.codehaus.groovy:groovy-all:1.7.5
     +--- org.codehaus.groovy:groovy-all:1.7.5

While with CodeNarc version 0.23:

codenarc - The CodeNarc libraries to be used for this project.
\--- org.codenarc:CodeNarc:0.23
     +--- org.codehaus.groovy:groovy:2.1.8 -> 2.4.3
     +--- org.codehaus.groovy:groovy-xml:2.1.8 -> 2.4.3
     |    \--- org.codehaus.groovy:groovy:2.4.3
     +--- org.codehaus.groovy:groovy-ant:2.1.8 -> 2.4.3
     |    +--- org.codehaus.groovy:groovy-groovydoc:2.4.3
     |    |    +--- org.codehaus.groovy:groovy-templates:2.4.3
     |    |    |    +--- org.codehaus.groovy:groovy-xml:2.4.3 (*)
     |    |    |    \--- org.codehaus.groovy:groovy:2.4.3
     |    |    \--- org.codehaus.groovy:groovy:2.4.3
     |    +--- org.codehaus.groovy:groovy:2.4.3
     |    +--- org.apache.ant:ant-antlr:1.9.4
     |    \--- org.apache.ant:ant-junit:1.9.4
     +--- org.gmetrics:GMetrics:0.7
     |    +--- org.codehaus.groovy:groovy:[2.1.0,) -> 2.4.3
     |    +--- org.codehaus.groovy:groovy-xml:[2.1.0,) -> 2.4.3 (*)
     |    \--- org.codehaus.groovy:groovy-ant:[2.1.0,) -> 2.4.3 (*)
     \--- junit:junit:4.8.1

Both above outputs are done with the same Gradle version. Despite that in the first example CodeNarc’s (really) old version of Groovy is listed and not evicted. In the second example they upgraded to 2.1.8 which is nice but seems it doesn’t matter actually as it’s evicted anyway and the version declared as compile dependency is used, compile 'org.codehaus.groovy:groovy-all:2.4.3'. So it’s not so isolated anymore, is it?

Sorry for the long post but I would really like to understand what’s going on here.


(Benjamin Muschko) #6

This what I found on the CodeNarc page. It seems like it does use the Groovy compiler:

Several newer rules use a later compilation phase for parsing of the Groovy source code, allowing CodeNarc to use a richer and more complete Abstract Syntax Tree (AST). The downside is that the later compiler phase requires CodeNarc to have the application classes being analyzed, as well as any referenced classes, on the classpath.

I also checked the code of the Gradle CodeNarc plugin. The configuration codenarc doesn’t exist any other configuration which means only the dependencies assigned to this configuration will resolve the version of Groovy.

For CodeNarc 0.24 the reason that org.codehaus.groovy:groovy:2.4.3 is selected is that org.gmetrics:GMetrics:0.7 apparently defines a version range: [2.1.0,). In this case it tries to find the lastest version of Groovy starting with version 2.1.0. You can easily reproduce the behavior with the following build script:

apply plugin: 'groovy'
apply plugin: 'codenarc'

repositories {
    mavenCentral()
}

Generally speaking, for published artifacts that’s a bad practice. If you don’t want this version of Groovy used for CodeNarc, you will have to do your own conflict resolution. Probably something along these lines:

dependencies {
    codenarc('org.codenarc:CodeNarc:0.23') {
        exclude group: 'org.codehaus.groovy'
    }
    codenarc 'org.codehaus.groovy:groovy:2.1.8',
             'org.codehaus.groovy:groovy-xml:2.1.8',
             'org.codehaus.groovy:groovy-ant:2.1.8'
}