/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 */

import java.text.DecimalFormat

plugins {
    id "me.champeau.gradle.jmh" version "0.5.3"
}

configurations {
    stats
    testImplementation.extendsFrom(stats)
}

dependencies {
    jmh rootProject
    testImplementation rootProject
    testImplementation "junit:junit:$junitVersion"
    stats 'org.apache.commons:commons-math3:3.6.1'
}

jmh {
    jmhVersion = '1.21'
    if (project.hasProperty('benchInclude')) {
        include = ['.*' + project.benchInclude + '.*']
    }
    includeTests = true
    duplicateClassesStrategy = 'WARN'
}
jmhClasses.dependsOn clean

sourceCompatibility = 1.8
targetCompatibility = 1.8

def findProject = { name ->
    rootProject.subprojects.find{it.name == name }
}

task performanceTests {
    ext.outputDir = file("$buildDir/compilation")
    ext.dataFile = file("$buildDir/compilation-stats.csv")

    dependsOn rootProject.jar
    doLast {
        ext.outputDir.deleteDir()
        def versions = []
        dataFile.eachLine {
            def (version, mean, stdDev) = it.split(';')
            mean = Double.valueOf(mean)
            stdDev = Double.valueOf(stdDev)
            versions << [version == project.version ? 'current' : version, mean, stdDev]
        }
        versions = versions.sort { it[1] }
        def fastest = versions[0][1]
        versions.each { version, mean, stdDev ->
            print "Groovy $version Average ${mean}ms ± ${new DecimalFormat("#.##").format(stdDev)}ms "
            if (mean > fastest) {
                def diff = 100 * (mean - fastest) / fastest
                print "(${new DecimalFormat("#.##").format(diff)}% slower)"
            }
            println()
        }
        dataFile.delete()
    }
}

['2.1.9', '2.2.2', '2.3.11', '2.4.21', '2.5.16', '3.0.10', 'current'].each { version ->
    def t = task "performanceTestGroovy_${version.replace('.', '_')}"(type: JavaExec, dependsOn: compileTestGroovy) {
        def groovyConf = configurations.detachedConfiguration(
                *('current' == version ?
                        [rootProject, findProject('groovy-test')].collect { Project p ->
                            dependencies.create(files(p.jar.archivePath))
                        } + [dependencies.create("org.ow2.asm:asm:$asmVersion"), dependencies.create("antlr:antlr:$antlrVersion"), dependencies.create("com.tunnelvisionlabs:antlr4-runtime:$antlr4Version")] :
                        version < '2.5.0' ?
                                [dependencies.create("org.codehaus.groovy:groovy-all:$version")]
                                :
                                ['groovy', 'groovy-test'].collect { String p ->
                                    dependencies.create("org.codehaus.groovy:$p:$version")
                                })
        )
        groovyConf.transitive = false
        main = 'org.apache.groovy.perf.CompilerPerformanceTest'
        classpath = groovyConf + sourceSets.test.output + configurations.stats
        jvmArgs = ['-Xms512m', '-Xmx512m']

        // configure some files to compile. This is an arbitrary set of files which can be compiled
        // independently of the version of Groovy being tested
        def testFiles = [
                'org/codehaus/groovy/util',
        ].collect { "../../src/main/groovy/$it" }
//        ['groovy-docgenerator'].collect(testFiles) { "../../subprojects/$it/src/main/groovy" }

        ['ackermann', 'fibo', 'random', 'spectralnorm', 'ary', 'hello', 'recursive', 'threadring',
         'binarytrees', 'mandelbrot', 'regexdna', 'wordfreq',
         'fannkuch', 'nsieve', 'revcomp'].collect(testFiles) {
            "../../benchmark/bench/${it}.groovy"
        }

        doFirst {
            def compileClassPath = [
                    '-cp',
                    *groovyConf.files*.absolutePath
            ]
            rootProject.sourceSets.test.compileClasspath.files
                    .findAll { it.name.endsWith('jar') && !it.name.contains('groovy') }
                    .collect(compileClassPath) { it.absolutePath }

            args = [
                    *testFiles,
                    *compileClassPath
            ]
        }

    }
    performanceTests.dependsOn(t)
}

compileJmhGroovy {
    classpath += compileJmhJava.classpath
}
