Skip to content

Instantly share code, notes, and snippets.

@retronym
Last active December 16, 2015 10:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save retronym/5420028 to your computer and use it in GitHub Desktop.
Save retronym/5420028 to your computer and use it in GitHub Desktop.
fork join idle hands
scalaVersion := "2.10.1"
libraryDependencies += "jsr166" % "jsr166e" % "0.1" from "http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166e.jar"
libraryDependencies += "jsr166" % "jsr166y" % "0.1" from "http://gee.cs.oswego.edu/dl/jsr166/dist/jsr166y.jar"
import annotation.tailrec
import java.util.concurrent.CountDownLatch
object ConcurrentTest {
//
// Uncomment on of the import lines below to choose a FJ implementation.
//
import scala.concurrent.forkjoin._ // The problem only shows up in the version of ForkJoin repackaged in Scala
// import jsr166e._
// import jsr166y._
def banner(str: String) = {
val line = "=" * 80
println(s"\n$line\n$str\n$line")
}
def expensiveCalc() {
@tailrec
def loop(i: Int, accum: Double): Double =
if (i == 0) accum else loop(i - 1, math.pow(math.sqrt(accum), 2.00001))
loop(500000000, 42)
}
val N = Runtime.getRuntime.availableProcessors()
val numTasks = N
def nestedParallelismBench(pool: Pool, useFork: Boolean) {
import pool.forkJoin
val countDown = new CountDownLatch(numTasks)
forkJoin.execute(new RecursiveAction {
def compute() {
(1 to numTasks) foreach { i =>
val action = new RecursiveAction {
def compute() {
println(s"i = $i: ${Thread.currentThread.getName} ${forkJoin.toString.dropWhile(_ != '[')}")
expensiveCalc()
countDown.countDown()
}
}
// See https://github.com/scala/scala/blob/2.10.1/src/library/scala/concurrent/impl/ExecutionContextImpl.scala#L118-#L120
// The default ExecutionContext in Scala uses `fork` for nested parallelism.
// This seems to leave a lot of cores idle. Why is this?
if (useFork)
action.fork()
else
forkJoin.execute(action)
}
}
})
countDown.await()
}
def nestedParallelismBenchRepeat(pool: Pool, useFork: Boolean) {
(1 to 3).foreach { i =>
banner(s"${pool.id}, useFork = $useFork, iteration $i")
nestedParallelismBench(pool, useFork = useFork)
}
}
case class Pool(forkJoin: ForkJoinPool, id: String)
val pool = Pool(new ForkJoinPool(N), s"new ForkJoinPool($N)")
def main(args: Array[String]) {
nestedParallelismBenchRepeat(pool, useFork = false)
nestedParallelismBenchRepeat(pool, useFork = true)
nestedParallelismBenchRepeat(pool, useFork = false)
}
}
// Using Scala 2.10.2.
================================================================================
new ForkJoinPool(8), useFork = false, iteration 1
================================================================================
i = 5: ForkJoinPool-1-worker-6 [Running, parallelism = 8, size = 8, active = 8, running = 4, steals = 0, tasks = 0, submissions = 2]
i = 7: ForkJoinPool-1-worker-7 [Running, parallelism = 8, size = 8, active = 8, running = 3, steals = 0, tasks = 0, submissions = 1]
i = 6: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 0, tasks = 0, submissions = 2]
i = 4: ForkJoinPool-1-worker-5 [Running, parallelism = 8, size = 7, active = 7, running = 6, steals = 0, tasks = 0, submissions = 2]
i = 2: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 4, active = 4, running = 4, steals = 0, tasks = 0, submissions = 2]
i = 3: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 5, active = 5, running = 5, steals = 0, tasks = 0, submissions = 2]
i = 1: ForkJoinPool-1-worker-2 [Running, parallelism = 8, size = 4, active = 4, running = 3, steals = 0, tasks = 0, submissions = 2]
i = 8: ForkJoinPool-1-worker-8 [Running, parallelism = 8, size = 8, active = 8, running = 2, steals = 0, tasks = 0, submissions = 0]
================================================================================
new ForkJoinPool(8), useFork = false, iteration 2
================================================================================
i = 1: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 5, running = 2, steals = 9, tasks = 0, submissions = 5]
i = 2: ForkJoinPool-1-worker-8 [Running, parallelism = 8, size = 8, active = 8, running = 3, steals = 9, tasks = 0, submissions = 5]
i = 3: ForkJoinPool-1-worker-6 [Running, parallelism = 8, size = 8, active = 8, running = 4, steals = 9, tasks = 0, submissions = 5]
i = 4: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 8, running = 4, steals = 9, tasks = 0, submissions = 4]
i = 5: ForkJoinPool-1-worker-7 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 9, tasks = 0, submissions = 3]
i = 6: ForkJoinPool-1-worker-5 [Running, parallelism = 8, size = 8, active = 8, running = 6, steals = 9, tasks = 0, submissions = 2]
i = 7: ForkJoinPool-1-worker-2 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 9, tasks = 0, submissions = 1]
i = 8: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 8, running = 8, steals = 9, tasks = 0, submissions = 0]
================================================================================
new ForkJoinPool(8), useFork = false, iteration 3
================================================================================
i = 1: ForkJoinPool-1-worker-6 [Running, parallelism = 8, size = 8, active = 8, running = 2, steals = 18, tasks = 0, submissions = 7]
i = 4: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 18, tasks = 0, submissions = 3]
i = 5: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 18, tasks = 0, submissions = 3]
i = 3: ForkJoinPool-1-worker-8 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 18, tasks = 0, submissions = 3]
i = 2: ForkJoinPool-1-worker-2 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 18, tasks = 0, submissions = 3]
i = 6: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 8, running = 6, steals = 18, tasks = 0, submissions = 2]
i = 7: ForkJoinPool-1-worker-5 [Running, parallelism = 8, size = 8, active = 8, running = 6, steals = 18, tasks = 0, submissions = 0]
i = 8: ForkJoinPool-1-worker-7 [Running, parallelism = 8, size = 8, active = 8, running = 6, steals = 18, tasks = 0, submissions = 0]
================================================================================
new ForkJoinPool(8), useFork = true, iteration 1
================================================================================
i = 8: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 2, steals = 27, tasks = 7, submissions = 0]
i = 1: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 27, tasks = 5, submissions = 0]
i = 2: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 27, tasks = 5, submissions = 0]
i = 3: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 27, tasks = 4, submissions = 0]
i = 7: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 27, tasks = 3, submissions = 0]
i = 4: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 27, tasks = 2, submissions = 0]
i = 5: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 27, tasks = 1, submissions = 0]
i = 6: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 27, tasks = 0, submissions = 0]
================================================================================
new ForkJoinPool(8), useFork = true, iteration 2
================================================================================
i = 8: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 1, steals = 33, tasks = 7, submissions = 0]
i = 1: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 33, tasks = 5, submissions = 0]
i = 2: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 33, tasks = 5, submissions = 0]
i = 7: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 33, tasks = 4, submissions = 0]
i = 3: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 33, tasks = 3, submissions = 0]
i = 4: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 33, tasks = 2, submissions = 0]
i = 6: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 33, tasks = 1, submissions = 0]
i = 5: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 33, tasks = 0, submissions = 0]
================================================================================
new ForkJoinPool(8), useFork = true, iteration 3
================================================================================
i = 8: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 3, running = 1, steals = 39, tasks = 7, submissions = 0]
i = 1: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 39, tasks = 5, submissions = 0]
i = 2: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 39, tasks = 5, submissions = 0]
i = 3: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 39, tasks = 4, submissions = 0]
i = 7: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 39, tasks = 3, submissions = 0]
i = 4: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 39, tasks = 2, submissions = 0]
i = 5: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 39, tasks = 1, submissions = 0]
i = 6: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 3, running = 3, steals = 39, tasks = 0, submissions = 0]
================================================================================
new ForkJoinPool(8), useFork = false, iteration 1
================================================================================
i = 2: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 8, running = 6, steals = 46, tasks = 0, submissions = 6]
i = 1: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 6, running = 2, steals = 46, tasks = 0, submissions = 4]
i = 4: ForkJoinPool-1-worker-8 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 46, tasks = 0, submissions = 2]
i = 3: ForkJoinPool-1-worker-7 [Running, parallelism = 8, size = 8, active = 8, running = 6, steals = 46, tasks = 0, submissions = 2]
i = 5: ForkJoinPool-1-worker-6 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 46, tasks = 0, submissions = 2]
i = 7: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 46, tasks = 0, submissions = 1]
i = 6: ForkJoinPool-1-worker-2 [Running, parallelism = 8, size = 8, active = 8, running = 6, steals = 46, tasks = 0, submissions = 2]
i = 8: ForkJoinPool-1-worker-5 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 46, tasks = 0, submissions = 0]
================================================================================
new ForkJoinPool(8), useFork = false, iteration 2
================================================================================
i = 6: ForkJoinPool-1-worker-7 [Running, parallelism = 8, size = 8, active = 8, running = 4, steals = 55, tasks = 0, submissions = 1]
i = 3: ForkJoinPool-1-worker-2 [Running, parallelism = 8, size = 8, active = 8, running = 6, steals = 55, tasks = 0, submissions = 0]
i = 4: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 55, tasks = 0, submissions = 0]
i = 2: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 55, tasks = 0, submissions = 0]
i = 7: ForkJoinPool-1-worker-5 [Running, parallelism = 8, size = 8, active = 8, running = 3, steals = 55, tasks = 0, submissions = 0]
i = 1: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 55, tasks = 0, submissions = 0]
i = 8: ForkJoinPool-1-worker-8 [Running, parallelism = 8, size = 8, active = 8, running = 5, steals = 55, tasks = 0, submissions = 0]
i = 5: ForkJoinPool-1-worker-6 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 55, tasks = 0, submissions = 1]
================================================================================
new ForkJoinPool(8), useFork = false, iteration 3
================================================================================
i = 2: ForkJoinPool-1-worker-7 [Running, parallelism = 8, size = 8, active = 7, running = 4, steals = 64, tasks = 0, submissions = 3]
i = 7: ForkJoinPool-1-worker-5 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 64, tasks = 0, submissions = 1]
i = 4: ForkJoinPool-1-worker-2 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 64, tasks = 0, submissions = 1]
i = 8: ForkJoinPool-1-worker-1 [Running, parallelism = 8, size = 8, active = 8, running = 3, steals = 64, tasks = 0, submissions = 0]
i = 3: ForkJoinPool-1-worker-8 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 64, tasks = 0, submissions = 1]
i = 6: ForkJoinPool-1-worker-6 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 64, tasks = 0, submissions = 1]
i = 5: ForkJoinPool-1-worker-3 [Running, parallelism = 8, size = 8, active = 8, running = 7, steals = 64, tasks = 0, submissions = 1]
i = 1: ForkJoinPool-1-worker-4 [Running, parallelism = 8, size = 8, active = 6, running = 4, steals = 64, tasks = 0, submissions = 3]
Process finished with exit code 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment