views:

69

answers:

2

I'm trying to get sbt to compile and build some benchmarks. I've told it to add the benchmarks to the test path so they're recompiled along with tests, but I can't figure out how to write an action to let me actually run them. Is it possible to invoke classes from the Project definition class, or even just from the command line?

+1  A: 

Couldn't you simply write the benchmarks as tests, so they will be run when you call 'test' in SBT?

You could also run a specific test with 'test-only', or run a main with 'run' or 'exec' (see http://code.google.com/p/simple-build-tool/wiki/RunningSbt for details).

Fabian Steeg
They could potentially take a long time, so I wanted a separate action for running them.
Dial Z
@Dial I see, added some alternatives to the answer.
Fabian Steeg
+4  A: 

Yes, it is.

If you'd like to run them in the same VM the SBT is run in, then write a custom task similar to the following in your project definition file:

  lazy val benchmark = task {
    // code to run benchmarks
    None // Some("will return an error message")
  }

Typing benchmark in SBT console will run the task above. To actually run the benchmarks, or, for that matter, any other class you've compiled, you can reuse some of the existing infrastructure of SBT, namely the method runTask which will create a task that runs something for you. It has the following signature:

 def runTask(mainClass: => Option[String], classpath: PathFinder, options: String*): Task

Simply add the following to your file:

  lazy val benchmark = task { args =>
    runTask(Some("whatever.your.mainclass.is"), testClasspath, args)
  }

When running benchmarks, it is sometimes recommended that you run them in a separate jvm invocation, to get more reliable results. SBT allows you to run separate processes by invoking a method ! on a string command. Say you have a command java -jar path-to-artifact.jar you want to run. Then:

"java -jar path-to-artifact.jar" !

runs the command in SBT. You want to put the snippet above in a separate task, same as earlier.

And don't forget to reload when you change your project definition.

axel22
I'll second the recommendation to run the benchmark in another jvm. When I invoke tests from sbt it eventually runs out of memory (especially if many tests fail). This is annoying (but not fatal) for tests but would distort benchmarks.
Ben Jackson
I've seen this quite a lot, in Liftweb with sbt very often. I'm not 100% sure about this, but it is possible that sbt fails for the following reason. Each time sbt recompiles your files and you wish to use them from sbt, sbt will dynamically load the classfiles using a custom classloader. These then occupy the permgen space in the jvm. Once you recompile, both the old classes and the new ones remain in the permgen space, and sooner or later you run out of it if the old ones aren't collected. Increasing the permgen space for the jvm that runs sbt may help: ` -XX:MaxPermSize=256m`.
axel22