About Me

My photo
Author of Groovy modules: GBench, GProf, Co-author of a Java book パーフェクトJava, Game Developer at GREE

Friday, June 10, 2011

@Benchmark annotation for Groovy gets a big update!

I released @Benchmark annotation for Groovy v11.06.11. This release includes some big changes and a big bug fix:


- Changes
  - Added classes / methods information to benchmark results
  - New option to customize handling of benchmark results
  - Supported class annotation


- Bug fixes
  - Fixed a problem that not working with methods of classes


Added classes / methods information to benchmark results


You can get benchmarked methods and their classes information as benchmark results. For example with the following code,
----
package foo


class Foo {
    @Benchmark
    def foo() {
    }
}
----


the output will be:
----
foo.Foo java.lang.Object foo(): xxx ns
----


New option to customize handling of benchmark results


Added "value" option to customize handling of benchmark results instead of poor options, "prefix" and "suffix". There are three ways to assign value to it:


- Use handler classes
- Use closures
- Use a system property


In the case of using handler classes, create classes that implement Benchmark.BenchmarkHandler interface and add two methods, handle() and getInstance() to them:
----
class MyHandler implements Benchmark.BenchmarkHandler {
    static def instance = new MyHandler()
    static MyHandler getInstance() {
        instance    
    }
    void handle(klass, method, time) {
        println("${method} of ${klass}: ${(time/1000000) as long} ms")
    }    
}
----


Yes, singleton classes as the above example can be writtern shorter by using @Singleton annotation in Groovy :-)
----
@Singleton
class MyHandler implements Benchmark.BenchmarkHandler {
    void handle(klass, method, time) {
        println("${method} of ${klass}: ${(time/1000000) as long} ms")
    }
}
----


In the end, assign handler classes to @Benchmark:
----
@Benchmark(MyHandler.class)
def foo() {
}
----


Since Groovy 1.8, you can also use closures instead of handler classes. With closures, you just need to assign closures that handle benchmark results:
----
@Benchmark({println("${method} of ${klass}: ${(time/1000000) as long} ms")})
def foo() {
}
----


And you can replace the default handling operation with a system property, "groovybenchmark.sf.net.defaulthandle":
----
> groovy -cp groovybenchmark-11.06.11.jar 
-Dgroovybenchmark.sf.net.defaulthandle="println(method + ' of ' + klass + ': ' + ((time/1000000) as long) + ' ms')" foo\Foo.groovy
----


In the cases of the examples, the outputs will be:
----
java.lang.Object foo() of foo.Foo: xxx ms
----
  
Supported class annotation


By annotating classes, you can get benchmark results of all the methods of the classes:
----
package foo


@Benchmark
class Foo {
    def foo() {
    }
    def bar() {
    }
}
----


In the case of the example, you will get the benchmark results of foo() and bar() methods:
----
foo.Foo java.lang.Object foo(): xxxx ns
foo.Foo java.lang.Object bar(): xxxx ns
----


And this means, now you've got a power to benchmark all the methods of your program without modifying code and profiling tools! Because Groovy 1.8 provides a compilation customizer to apply annotations to all the classes:
----
// BenchmarkGroovyc.groovy
import groovybenchmark.sf.net.Benchmark


import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
import org.codehaus.groovy.tools.FileSystemCompiler


def cc = new CompilerConfiguration()
cc.addCompilationCustomizers(new ASTTransformationCustomizer(Benchmark))
new FileSystemCompiler(cc).commandLineCompile(args)
----


----
> groovy -cp groovybenchmark-11.06.11.jar BenchmarkGroovyc.groovy MyApp.groovy
> java -cp .;%GROOVY_HOME%\embeddable\groovy-all-1.8.0.jar;groovybenchmark-11.06.11.jar MyApp 
----


----
Xxx xxxx foo(): xxx ns
Xxx xxxx bar(): xxx ns
Xxx xxxx baz(): xxx ns
MyApp java.lang.Object main(java.lang.Object): xxx ns
----


Please try and let me know your feedback!

No comments:

Post a Comment