I am currently developing a Scala framework for multi-process, parallel algorithms using MPJ-Express (i.e. a Java MPI-variant).
MPJ-Express, and basically all MPI-variants, work by starting many processes with the same program. Since I have no control over the processes at runtime (my program does not spawn processes), I can’t use standard unit testing frameworks due to the following reasons:
-
Not all processes will own a local copy of the results after execution (ideally, the results should be collected at an arbitrary root-process)
-
Lack of control over standard-output. It is not easily possible to get output only from a single process.
- Lack of flow control. All processes must enter the same test at the same time to allow single-program multiple data algorithms.
Number 2 is mainly the problem, as 3 might work as expected and 1 can be fixed with an extra communication operation. Does anyone have practical experience, or know of better unit testing strategies for multi-process algorithms?
EDIT
Right now, I seem to be having luck with the following code using scalacheck:
package it.vigtig.thesis.collection.scalacheck
import java.io.OutputStream
import java.io.PrintStream
import org.scalacheck.Prop.forAll
import org.scalacheck.Properties
import it.vigtig.thesis.env.DistEnv.globalRank
import it.vigtig.thesis.env.DistEnv.parallelize
object CollectionCheck {
def main(args: Array[String]) {
parallelize(args) {
if (globalRank > 0) {
Console.setOut(new PrintStream(new OutputStream() {
def write(b: Int) { //nop
}
}))
}
ST.main(Array())
}
}
}
object ST extends Properties("String") {
// def println(a: String*) = gprintln(a)
property("startsWith") = forAll((a: String, b: String) => (a + b).startsWith(a))
property("concatenate") = forAll((a: String, b: String) =>
(a + b).length > a.length && (a + b).length > b.length)
property("substring") = forAll((a: String, b: String, c: String) =>
(a + b + c).substring(a.length, a.length + b.length) == b)
}
The above code reroutes the scala-println method to a nop-operation for all other processes than p=0. I should be able to run the test-suites with parallel-methods, allowing only the root process to verify the results. The above yields the following output:
MPJ Express (0.38) is started in the multicore configuration
rank-0: 0.212437745 time taken for initialize
+ String.startsWith: OK, passed 100 tests.
! String.concatenate: Falsified after 0 passed tests.
> ARG_0:
> ARG_1:
+ String.substring: OK, passed 100 tests.
github.com/rickynils/scalacheck/issues/37 Apparently, it was due to a kind of bug in scalacheck. This bug will be fixed, but for now it seems you can clone the repository in that post and get a working copy! 🙂