Advertisement
Ichoran

Scala collections benchmarking: foreach vs. iterator

Oct 8th, 2012
159
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Scala 27.55 KB | None | 0 0
  1. /** ForeachIteratorShootout.scala
  2.  *  Copyright Rex Kerr 2012; BSD 3-clause license (ask me for others)
  3.  **/
  4.  
  5. import scala.annotation.tailrec
  6.  
  7. object ForeachIteratorShootout {
  8.   /***** Random utility stuff *****/
  9.  
  10.   // We will fill our objects with these, in order to avoid object creations
  11.   // And we will compute the XOR of the contents to make sure no work can be skipped
  12.   sealed trait Bool { def flip: Bool; def ^(b: Bool): Bool }
  13.   object Bool { def apply(i: Int) = if ((i&1)==1) T else F }
  14.   final class True extends Bool { def flip = F; def ^(b: Bool) = b }
  15.   final class False extends Bool { def flip = T; def ^(b: Bool) = b.flip }
  16.   val T = new True
  17.   val F = new False
  18.  
  19.   // Random container class
  20.   class Box[A] {
  21.     var value: A = _
  22.     def apply() = value
  23.     def update(a: A) { value = a }
  24.   }
  25.   object Box {
  26.     def apply[A]() = new Box[A]
  27.   }
  28.  
  29.   // Statistics--approximate only, ignoring all -1s (sample SD, etc.)
  30.   case class ErrEst(center: Double, deviation: Double) {
  31.     def variance = deviation*deviation
  32.     def fracErr = deviation/center
  33.     def fracErrSq = fracErr*fracErr
  34.     def lo = center - deviation*ErrEst.ci95 // Low bound for 95% CI (2-tailed)
  35.     def hi = center + deviation*ErrEst.ci95 // High bound for 95% CI (2-tailed)
  36.     def +(ee: ErrEst) = ErrEst(center + ee.center, math.sqrt(variance + ee.variance))
  37.     def -(ee: ErrEst) = ErrEst(center - ee.center, math.sqrt(variance + ee.variance))
  38.     def *(ee: ErrEst) = ErrEst(center * ee.center, deviation*ee.center + ee.deviation*center)
  39.     def /(ee: ErrEst) = ErrEst(center / ee.center, (center/ee.center)*math.sqrt(fracErrSq + ee.fracErrSq))
  40.     def scale(k: Double) = ErrEst(center*k, deviation*k)
  41.   }
  42.   object ErrEst {
  43.     // This is the standard error of the mean, approximately
  44.     final val ci95 = 1.9599639845400538
  45.     def apply(xs: Array[Double]) = {
  46.       val n = xs.length max 1
  47.       val sum = xs.sum
  48.       val sumsq = xs.map(x => x*x).sum
  49.       new ErrEst(sum/n, math.sqrt((sumsq/n - (sum/n)*(sum/n))/n))
  50.     }
  51.   }
  52.  
  53.  
  54.   /***** Timing/benchmark utilities *****/
  55.  
  56.   // How long does something take, in seconds?
  57.   def time[A](a: => A) = {
  58.     var t0 = System.nanoTime
  59.     val ans = a
  60.     (ans , 1e-9*(System.nanoTime - t0))
  61.   }
  62.  
  63.   // How many iterations do we need to exceed a particular target time?
  64.   @tailrec def timeTarget[A](target: Double, n: Int = 1)(f: () => A): Int = {
  65.     val (_, elapsed) = time{
  66.       val a = Box[A]()
  67.       var i = 0
  68.       while (i<n) {
  69.         a() = f()
  70.         i += 1
  71.       }
  72.       a()
  73.     }
  74.     if (elapsed < target) timeTarget(target, math.ceil(n*math.sqrt(2)).toInt)(f)
  75.     else if (elapsed > 10*target) throw new Exception("Please subdivide the work into smaller units--target time exceeded by more than ten")
  76.     else n
  77.   }
  78.  
  79.   var maxUID = 0
  80.   case class Benchable(name: String, len: Int, items: Int, alg: String, op: () => Bool, reps: Int = 1, uid: Int = { maxUID += 1; maxUID-1 }) {
  81.     def label = "%-8s %6d".format(name,len)
  82.   }
  83.  
  84.   // Semi-robust sampling; pick 5th-25th percentile tail as most representative
  85.   def printedBench[A](target: Double = 0.1, samplesize: Int = 100, verbose: Boolean = true)(bs: Seq[Benchable]) {
  86.     if (samplesize/4 == 0) throw new IllegalArgumentException("Can't get statistics off of n="+samplesize)
  87.    
  88.     if (verbose) println("Warming up.")
  89.     bs.foreach{ b => for (i <- 1 to 10) b.op() }
  90.    
  91.     if (verbose) println("Estimating needed number of iterations")    
  92.     val nbs = bs.grouped(2).flatMap{ gr =>
  93.       val n = gr.map(b => timeTarget(target)(b.op)).max
  94.       gr.map(b =>b.copy(reps = n))
  95.     }.toIndexedSeq
  96.    
  97.     if (verbose) println("Creating work")
  98.     val many = Vector.fill(samplesize)(nbs).flatten.map(b => (b,scala.util.Random.nextInt)).sortBy(_._2).map(_._1)
  99.     val results = nbs.map(b => b -> Array.fill(samplesize)(0.0)).toMap
  100.    
  101.     if (verbose) print("Working (not in parallel!): ")
  102.     var i = 0
  103.     var x: Bool = F
  104.     many.foreach{ b =>
  105.       i += 1
  106.       if (verbose && (i%bs.length)==0) print(".")
  107.       val (_,t) = time {
  108.         var i = 0
  109.         while (i < b.reps) {
  110.           x = x ^ b.op()
  111.           i += 1
  112.         }
  113.         x
  114.       }
  115.       val ts = results(b)
  116.       var j = 0
  117.       while (ts(j)!=0.0) j += 1
  118.       ts(j) = t/(b.items*b.reps)
  119.     }
  120.     println
  121.    
  122.     if (verbose) println("Computing statistics and printing results")
  123.     val stats = results.mapValues(ar => ErrEst(ar.sorted.drop(samplesize/20).take(samplesize/4)))
  124.     Seq(false,true).map{ showTimes =>
  125.       stats.groupBy(_._1.label).toSeq.sortBy(_._1).map(_._2).foreach{ bees =>
  126.         val sorted = bees.toList.sortBy(_._1.alg(1))  // Foreaches first, iterators after
  127.         val missing = ErrEst(Double.NaN, Double.NaN)
  128.         val byAlg = "mfr".toList.map{ c => val x = sorted.filter(_._1.alg(0)==c); if (x.length>0) x.take(2).map(_._2).toList else List(missing,missing) }
  129.         if (byAlg.exists(!_.forall(_.lo.isNaN))) {
  130.           if (showTimes) {
  131.             val List(List(mf,mi), List(ff,fi), List(rf,ri)) = byAlg.map(_.map(_ scale 1e9))
  132.             printf("T %-16s Map:%6.1f/%-6.1f  Filter:%6.1f/%-6.1f  Fold:%6.1f/%-6.1f\n",
  133.                   sorted.head._1.label, mf.center, mi.center, ff.center, fi.center, rf.center, ri.center)
  134.           }
  135.           else {
  136.             val List(mrat, frat, rrat) = byAlg.collect{ case List(fe,it) => fe/it }
  137.             printf("R %-16s Map:%6.3f-%-6.3f  Filter:%6.3f-%-6.3f  Fold:%6.3f-%-6.3f\n",
  138.                   sorted.head._1.label, mrat.lo, mrat.hi, frat.lo, frat.hi, rrat.lo, rrat.hi)
  139.           }
  140.         }
  141.       }
  142.     }
  143.   }
  144.  
  145.  
  146.   /***** Tests of map and filter methods using iterator vs. foreach *****/
  147.   /*** WARNING -- serious code duplication ahead!  (Necessary for benchmarking!) ***/
  148.  
  149.   def mkRng = new scala.util.Random(42)  // This one gives true, then false as first two booleans.  Good for two-element collections.
  150.  
  151.   // Standard six methods with List
  152.   def reverseMapListForeach[Q](xs: List[Q])(f: Q => Q) = {
  153.     var ys = List[Q]()
  154.     xs.foreach{x => ys = f(x) :: ys}
  155.     ys
  156.   }
  157.   def reverseMapListIterator[Q](xs: List[Q])(f: Q => Q) = {
  158.     var ys = List[Q]()
  159.     val xi = xs.iterator
  160.     while (xi.hasNext) { ys = f(xi.next) :: ys }
  161.     ys
  162.   }
  163.   def reverseFilterListForeach[Q](xs: List[Q])(f: Q => Boolean) = {
  164.     var ys = List[Q]()
  165.     xs.foreach{ x => if (f(x)) ys = x :: ys }
  166.     ys
  167.   }
  168.   def reverseFilterListIterator[Q](xs: List[Q])(f: Q => Boolean) = {
  169.     var ys = List[Q]()
  170.     val xi = xs.iterator
  171.     while (xi.hasNext) {
  172.       val x = xi.next
  173.       if (f(x)) ys = x :: ys
  174.     }
  175.     ys
  176.   }
  177.   def foldListForeach[Q](xs: List[Q])(zero: Q)(f: (Q,Q) => Q) = {
  178.     var i = zero
  179.     xs.foreach{ x => i = f(i,x) }
  180.     i
  181.   }
  182.   def foldListIterator[Q](xs: List[Q])(zero: Q)(f: (Q,Q) => Q) = {
  183.     var i = zero
  184.     var xi = xs.iterator
  185.     while (xi.hasNext) { i = f(i,xi.next) }
  186.     i
  187.   }
  188.   def testLists(len: Int): List[Benchable] = {
  189.     val rng = mkRng
  190.     val xs: List[Bool] = List.fill(len){ if (rng.nextBoolean) T else F }
  191.     val N = (if (len/1000 >= 10) 1 else if (len/1000 > 1) 10 else if (len/100 > 1) 100 else 1000)
  192.     val base = Benchable("List",len,len*N,"",()=>T)
  193.    
  194.     base.copy(alg="mf", op = () => { var ys = xs; var i=0; while (i<N) { ys = reverseMapListForeach(ys)(_.flip); i += 1 }; ys.head }) ::
  195.     base.copy(alg="mi", op = () => { var ys = xs; var i=0; while (i<N) { ys = reverseMapListIterator(ys)(_.flip); i += 1 }; ys.head }) ::
  196.     base.copy(alg="ff", op = () => { var ys = List[Bool](); var i=0; while (i<N) { ys = reverseFilterListForeach(xs)(_ eq F); i += 1 }; ys.head }) ::
  197.     base.copy(alg="fi", op = () => { var ys = List[Bool](); var i=0; while (i<N) { ys = reverseFilterListIterator(xs)(_ eq F); i += 1 }; ys.head }) ::
  198.     base.copy(alg="rf", op = () => { var y: Bool = F; var i=0; while (i<N) { y = foldListForeach(xs)(y)(_ ^ _); i += 1 }; y }) ::
  199.     base.copy(alg="ri", op = () => { var y: Bool = F; var i=0; while (i<N) { y = foldListIterator(xs)(y)(_ ^ _); i += 1 }; y }) ::
  200.     Nil
  201.   }
  202.  
  203.   // Standard six methods with Vector
  204.   def mapVectorForeach[Q](xs: Vector[Q])(f: Q => Q) = {
  205.     var yb = Vector.newBuilder[Q]
  206.     xs.foreach{x => yb += f(x) }
  207.     yb.result
  208.   }
  209.   def mapVectorIterator[Q](xs: Vector[Q])(f: Q => Q) = {
  210.     var yb = Vector.newBuilder[Q]
  211.     val xi = xs.iterator
  212.     while (xi.hasNext) { yb += f(xi.next) }
  213.     yb.result
  214.   }
  215.   def filterVectorForeach[Q](xs: Vector[Q])(f: Q => Boolean) = {
  216.     var yb = Vector.newBuilder[Q]
  217.     xs.foreach{ x => if (f(x)) yb += x }
  218.     yb.result
  219.   }
  220.   def filterVectorIterator[Q](xs: Vector[Q])(f: Q => Boolean) = {
  221.     var yb = Vector.newBuilder[Q]
  222.     val xi = xs.iterator
  223.     while (xi.hasNext) {
  224.       val x = xi.next
  225.       if (f(x)) yb += x
  226.     }
  227.     yb.result
  228.   }
  229.   def foldVectorForeach[Q](xs: Vector[Q])(zero: Q)(f: (Q,Q) => Q) = {
  230.     var i = zero
  231.     xs.foreach{ x => i = f(i,x) }
  232.     i
  233.   }
  234.   def foldVectorIterator[Q](xs: Vector[Q])(zero: Q)(f: (Q,Q) => Q) = {
  235.     var i = zero
  236.     var xi = xs.iterator
  237.     while (xi.hasNext) { i = f(i,xi.next) }
  238.     i
  239.   }
  240.   def testVectors(len: Int): List[Benchable] = {
  241.     val rng = mkRng
  242.     val xs: Vector[Bool] = Vector.fill(len){ if (rng.nextBoolean) T else F }
  243.     val N = (if (len/1000 >= 10) 1 else if (len/1000 > 1) 10 else if (len/100 > 1) 100 else 1000)
  244.     val base = Benchable("Vector",len,len*N,"",()=>T)
  245.    
  246.     base.copy(alg="mf", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapVectorForeach(ys)(_.flip); i += 1 }; ys.head }) ::
  247.     base.copy(alg="mi", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapVectorIterator(ys)(_.flip); i += 1 }; ys.head }) ::
  248.     base.copy(alg="ff", op = () => { var ys = Vector[Bool](); var i=0; while (i<N) { ys = filterVectorForeach(xs)(_ eq F); i += 1 }; ys.head }) ::
  249.     base.copy(alg="fi", op = () => { var ys = Vector[Bool](); var i=0; while (i<N) { ys = filterVectorIterator(xs)(_ eq F); i += 1 }; ys.head }) ::
  250.     base.copy(alg="rf", op = () => { var y: Bool = F; var i=0; while (i<N) { y = foldVectorForeach(xs)(y)(_ ^ _); i += 1 }; y }) ::
  251.     base.copy(alg="ri", op = () => { var y: Bool = F; var i=0; while (i<N) { y = foldVectorIterator(xs)(y)(_ ^ _); i += 1 }; y }) ::
  252.     Nil
  253.   }
  254.  
  255.   // Standard six methods with Set
  256.   def mapSetForeach[Q](xs: Set[Q])(f: Q => Q) = {
  257.     var yb = Set.newBuilder[Q]
  258.     xs.foreach{x => yb += f(x) }
  259.     yb.result
  260.   }
  261.   def mapSetIterator[Q](xs: Set[Q])(f: Q => Q) = {
  262.     var yb = Set.newBuilder[Q]
  263.     val xi = xs.iterator
  264.     while (xi.hasNext) { yb += f(xi.next) }
  265.     yb.result
  266.   }
  267.   def filterSetForeach[Q](xs: Set[Q])(f: Q => Boolean) = {
  268.     var yb = Set.newBuilder[Q]
  269.     xs.foreach{ x => if (f(x)) yb += x }
  270.     yb.result
  271.   }
  272.   def filterSetIterator[Q](xs: Set[Q])(f: Q => Boolean) = {
  273.     var yb = Set.newBuilder[Q]
  274.     val xi = xs.iterator
  275.     while (xi.hasNext) {
  276.       val x = xi.next
  277.       if (f(x)) yb += x
  278.     }
  279.     yb.result
  280.   }
  281.   def foldSetForeach[Q](xs: Set[Q])(zero: Q)(f: (Q,Q) => Q) = {
  282.     var i = zero
  283.     xs.foreach{ x => i = f(i,x) }
  284.     i
  285.   }
  286.   def foldSetIterator[Q](xs: Set[Q])(zero: Q)(f: (Q,Q) => Q) = {
  287.     var i = zero
  288.     var xi = xs.iterator
  289.     while (xi.hasNext) { i = f(i,xi.next) }
  290.     i
  291.   }
  292.   def testSets(len: Int): List[Benchable] = {
  293.     val rng = mkRng
  294.     val xs: Set[Int] = List.fill(len){ rng.nextInt }.toSet
  295.     val N = (if (len/1000 >= 10) 1 else if (len/1000 > 1) 10 else if (len/100 > 1) 100 else 1000)
  296.     val base = Benchable("Set",len,len*N,"",()=>T)
  297.    
  298.     base.copy(alg="mf", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapSetForeach(ys)(_+1); i += 1 }; Bool(ys.head) }) ::
  299.     base.copy(alg="mi", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapSetIterator(ys)(_+1); i += 1 }; Bool(ys.head) }) ::
  300.     base.copy(alg="ff", op = () => { var ys = Set[Int](); var i=0; while (i<N) { ys = filterSetForeach(xs)(_ >= 0); i += 1 }; Bool(ys.head) }) ::
  301.     base.copy(alg="fi", op = () => { var ys = Set[Int](); var i=0; while (i<N) { ys = filterSetIterator(xs)(_ >= 0); i += 1 }; Bool(ys.head) }) ::
  302.     base.copy(alg="rf", op = () => { var y: Int = Int.MaxValue; var i=0; while (i<N) { y = foldSetForeach(xs)(y)((a,b) => math.min(a,b)); i += 1 }; Bool(y) }) ::
  303.     base.copy(alg="ri", op = () => { var y: Int = Int.MaxValue; var i=0; while (i<N) { y = foldSetIterator(xs)(y)((a,b) => math.min(a,b)); i += 1 }; Bool(y) }) ::
  304.     Nil
  305.   }
  306.  
  307.   // Standard six methods with Map
  308.   def mapMapForeach[Q,Z](xs: Map[Q,Z])(f: ((Q,Z)) => (Q,Z)) = {
  309.     var yb = Map.newBuilder[Q,Z]
  310.     xs.foreach{x => yb += f(x) }
  311.     yb.result
  312.   }
  313.   def mapMapIterator[Q,Z](xs: Map[Q,Z])(f: ((Q,Z)) => (Q,Z)) = {
  314.     var yb = Map.newBuilder[Q,Z]
  315.     val xi = xs.iterator
  316.     while (xi.hasNext) { yb += f(xi.next) }
  317.     yb.result
  318.   }
  319.   def filterMapForeach[Q,Z](xs: Map[Q,Z])(f: ((Q,Z)) => Boolean) = {
  320.     var yb = Map.newBuilder[Q,Z]
  321.     xs.foreach{ x => if (f(x)) yb += x }
  322.     yb.result
  323.   }
  324.   def filterMapIterator[Q,Z](xs: Map[Q,Z])(f: ((Q,Z)) => Boolean) = {
  325.     var yb = Map.newBuilder[Q,Z]
  326.     val xi = xs.iterator
  327.     while (xi.hasNext) {
  328.       val x = xi.next
  329.       if (f(x)) yb += x
  330.     }
  331.     yb.result
  332.   }
  333.   def foldMapForeach[Q,Z,J](xs: Map[Q,Z])(zero: J)(f: (J,(Q,Z)) => J) = {
  334.     var i = zero
  335.     xs.foreach{ x => i = f(i,x) }
  336.     i
  337.   }
  338.   def foldMapIterator[Q,Z,J](xs: Map[Q,Z])(zero: J)(f: (J,(Q,Z)) => J) = {
  339.     var i = zero
  340.     var xi = xs.iterator
  341.     while (xi.hasNext) { i = f(i,xi.next) }
  342.     i
  343.   }
  344.   def testMaps(len: Int): List[Benchable] = {
  345.     val rng = mkRng
  346.     val xs: Map[Int,Int] = List.fill(len){ rng.nextInt -> rng.nextInt }.toMap
  347.     val N = (if (len/1000 >= 10) 1 else if (len/1000 > 1) 10 else if (len/100 > 1) 100 else 1000)
  348.     val base = Benchable("Map",len,len*N,"",()=>T)
  349.    
  350.     base.copy(alg="mf", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapMapForeach(ys)(_.swap); i += 1 }; Bool(ys.head._1 ^ ys.head._2) }) ::
  351.     base.copy(alg="mi", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapMapIterator(ys)(_.swap); i += 1 }; Bool(ys.head._1 ^ ys.head._2) }) ::
  352.     base.copy(alg="ff", op = () => { var ys = Map[Int,Int](); var i=0; while (i<N) { ys = filterMapForeach(xs)(x => x._1 < x._2); i += 1 }; Bool(ys.head._1 ^ ys.head._2) }) ::
  353.     base.copy(alg="fi", op = () => { var ys = Map[Int,Int](); var i=0; while (i<N) { ys = filterMapIterator(xs)(x => x._1 < x._2); i += 1 }; Bool(ys.head._1 ^ ys.head._2) }) ::
  354.     base.copy(alg="rf", op = () => { var y: Int = Int.MaxValue; var i=0; while (i<N) { y = foldMapForeach(xs)(y)((a,b) => math.min(a,b._1+b._2)); i += 1 }; Bool(y) }) ::
  355.     base.copy(alg="ri", op = () => { var y: Int = Int.MaxValue; var i=0; while (i<N) { y = foldMapIterator(xs)(y)((a,b) => math.min(a,b._1+b._2)); i += 1 }; Bool(y) }) ::
  356.     Nil
  357.   }
  358.  
  359.   // Standard six methods with Array
  360.   def mapArrayForeach[Q: ClassManifest](xs: Array[Q])(f: Q => Q) = {
  361.     var yb = Array.newBuilder[Q]
  362.     xs.foreach{x => yb += f(x) }
  363.     yb.result
  364.   }
  365.   def mapArrayIterator[Q: ClassManifest](xs: Array[Q])(f: Q => Q) = {
  366.     var yb = Array.newBuilder[Q]
  367.     val xi = xs.iterator
  368.     while (xi.hasNext) { yb += f(xi.next) }
  369.     yb.result
  370.   }
  371.   def filterArrayForeach[Q: ClassManifest](xs: Array[Q])(f: Q => Boolean) = {
  372.     var yb = Array.newBuilder[Q]
  373.     xs.foreach{ x => if (f(x)) yb += x }
  374.     yb.result
  375.   }
  376.   def filterArrayIterator[Q: ClassManifest](xs: Array[Q])(f: Q => Boolean) = {
  377.     var yb = Array.newBuilder[Q]
  378.     val xi = xs.iterator
  379.     while (xi.hasNext) {
  380.       val x = xi.next
  381.       if (f(x)) yb += x
  382.     }
  383.     yb.result
  384.   }
  385.   def foldArrayForeach[Q](xs: Array[Q])(zero: Q)(f: (Q,Q) => Q) = {
  386.     var i = zero
  387.     xs.foreach{ x => i = f(i,x) }
  388.     i
  389.   }
  390.   def foldArrayIterator[Q](xs: Array[Q])(zero: Q)(f: (Q,Q) => Q) = {
  391.     var i = zero
  392.     var xi = xs.iterator
  393.     while (xi.hasNext) { i = f(i,xi.next) }
  394.     i
  395.   }
  396.   def testArrays(len: Int): List[Benchable] = {
  397.     val rng = mkRng
  398.     val xs: Array[Bool] = Array.fill(len){ if (rng.nextBoolean) T else F }
  399.     val N = (if (len/1000 >= 10) 1 else if (len/1000 > 1) 10 else if (len/100 > 1) 100 else 1000)
  400.     val base = Benchable("Array",len,len*N,"",()=>T)
  401.    
  402.     base.copy(alg="mf", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapArrayForeach(ys)(_.flip); i += 1 }; ys.head }) ::
  403.     base.copy(alg="mi", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapArrayIterator(ys)(_.flip); i += 1 }; ys.head }) ::
  404.     base.copy(alg="ff", op = () => { var ys = Array[Bool](); var i=0; while (i<N) { ys = filterArrayForeach(xs)(_ eq F); i += 1 }; ys.head }) ::
  405.     base.copy(alg="fi", op = () => { var ys = Array[Bool](); var i=0; while (i<N) { ys = filterArrayIterator(xs)(_ eq F); i += 1 }; ys.head }) ::
  406.     base.copy(alg="rf", op = () => { var y: Bool = F; var i=0; while (i<N) { y = foldArrayForeach(xs)(y)(_ ^ _); i += 1 }; y }) ::
  407.     base.copy(alg="ri", op = () => { var y: Bool = F; var i=0; while (i<N) { y = foldArrayIterator(xs)(y)(_ ^ _); i += 1 }; y }) ::
  408.     Nil
  409.   }
  410.  
  411.   // Standard six methods with TreeSet
  412.   import scala.collection.immutable.TreeSet
  413.   def mapTreeSetForeach[Q: Ordering](xs: TreeSet[Q])(f: Q => Q) = {
  414.     var yb = TreeSet.newBuilder[Q]
  415.     xs.foreach{x => yb += f(x) }
  416.     yb.result
  417.   }
  418.   def mapTreeSetIterator[Q: Ordering](xs: TreeSet[Q])(f: Q => Q) = {
  419.     var yb = TreeSet.newBuilder[Q]
  420.     val xi = xs.iterator
  421.     while (xi.hasNext) { yb += f(xi.next) }
  422.     yb.result
  423.   }
  424.   def filterTreeSetForeach[Q: Ordering](xs: TreeSet[Q])(f: Q => Boolean) = {
  425.     var yb = TreeSet.newBuilder[Q]
  426.     xs.foreach{ x => if (f(x)) yb += x }
  427.     yb.result
  428.   }
  429.   def filterTreeSetIterator[Q: Ordering](xs: TreeSet[Q])(f: Q => Boolean) = {
  430.     var yb = TreeSet.newBuilder[Q]
  431.     val xi = xs.iterator
  432.     while (xi.hasNext) {
  433.       val x = xi.next
  434.       if (f(x)) yb += x
  435.     }
  436.     yb.result
  437.   }
  438.   def foldTreeSetForeach[Q](xs: TreeSet[Q])(zero: Q)(f: (Q,Q) => Q) = {
  439.     var i = zero
  440.     xs.foreach{ x => i = f(i,x) }
  441.     i
  442.   }
  443.   def foldTreeSetIterator[Q](xs: TreeSet[Q])(zero: Q)(f: (Q,Q) => Q) = {
  444.     var i = zero
  445.     var xi = xs.iterator
  446.     while (xi.hasNext) { i = f(i,xi.next) }
  447.     i
  448.   }
  449.   def testTreeSets(len: Int): List[Benchable] = {
  450.     val rng = mkRng
  451.     val xs: TreeSet[Int] = TreeSet[Int]() ++ List.fill(len){ rng.nextInt }
  452.     val N = (if (len/1000 >= 10) 1 else if (len/1000 > 1) 10 else if (len/100 > 1) 100 else 1000)
  453.     val base = Benchable("TreeSet",len,len*N,"",()=>T)
  454.    
  455.     base.copy(alg="mf", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapTreeSetForeach(ys)(_+1); i += 1 }; Bool(ys.head) }) ::
  456.     base.copy(alg="mi", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapTreeSetIterator(ys)(_+1); i += 1 }; Bool(ys.head) }) ::
  457.     base.copy(alg="ff", op = () => { var ys = TreeSet[Int](); var i=0; while (i<N) { ys = filterTreeSetForeach(xs)(_ >= 0); i += 1 }; Bool(ys.head) }) ::
  458.     base.copy(alg="fi", op = () => { var ys = TreeSet[Int](); var i=0; while (i<N) { ys = filterTreeSetIterator(xs)(_ >= 0); i += 1 }; Bool(ys.head) }) ::
  459.     base.copy(alg="rf", op = () => { var y: Int = Int.MaxValue; var i=0; while (i<N) { y = foldTreeSetForeach(xs)(y)((a,b) => math.min(a,b)); i += 1 }; Bool(y) }) ::
  460.     base.copy(alg="ri", op = () => { var y: Int = Int.MaxValue; var i=0; while (i<N) { y = foldTreeSetIterator(xs)(y)((a,b) => math.min(a,b)); i += 1 }; Bool(y) }) ::
  461.     Nil
  462.   }
  463.  
  464.   // Standard six methods with mutable.HashMap
  465.   import scala.collection.mutable.HashMap
  466.   def mapHashMapForeach[Q,Z](xs: HashMap[Q,Z])(f: ((Q,Z)) => (Q,Z)) = {
  467.     var yb = HashMap.newBuilder[Q,Z]
  468.     xs.foreach{x => yb += f(x) }
  469.     yb.result
  470.   }
  471.   def mapHashMapIterator[Q,Z](xs: HashMap[Q,Z])(f: ((Q,Z)) => (Q,Z)) = {
  472.     var yb = HashMap.newBuilder[Q,Z]
  473.     val xi = xs.iterator
  474.     while (xi.hasNext) { yb += f(xi.next) }
  475.     yb.result
  476.   }
  477.   def filterHashMapForeach[Q,Z](xs: HashMap[Q,Z])(f: ((Q,Z)) => Boolean) = {
  478.     var yb = HashMap.newBuilder[Q,Z]
  479.     xs.foreach{ x => if (f(x)) yb += x }
  480.     yb.result
  481.   }
  482.   def filterHashMapIterator[Q,Z](xs: HashMap[Q,Z])(f: ((Q,Z)) => Boolean) = {
  483.     var yb = HashMap.newBuilder[Q,Z]
  484.     val xi = xs.iterator
  485.     while (xi.hasNext) {
  486.       val x = xi.next
  487.       if (f(x)) yb += x
  488.     }
  489.     yb.result
  490.   }
  491.   def foldHashMapForeach[Q,Z,J](xs: HashMap[Q,Z])(zero: J)(f: (J,(Q,Z)) => J) = {
  492.     var i = zero
  493.     xs.foreach{ x => i = f(i,x) }
  494.     i
  495.   }
  496.   def foldHashMapIterator[Q,Z,J](xs: HashMap[Q,Z])(zero: J)(f: (J,(Q,Z)) => J) = {
  497.     var i = zero
  498.     var xi = xs.iterator
  499.     while (xi.hasNext) { i = f(i,xi.next) }
  500.     i
  501.   }
  502.   def testHashMaps(len: Int): List[Benchable] = {
  503.     val rng = mkRng
  504.     val xs: HashMap[Int,Int] = HashMap[Int,Int]() ++ List.fill(len){ rng.nextInt -> rng.nextInt }
  505.     val N = (if (len/1000 >= 10) 1 else if (len/1000 > 1) 10 else if (len/100 > 1) 100 else 1000)
  506.     val base = Benchable("mHashMap",len,len*N,"",()=>T)
  507.    
  508.     base.copy(alg="mf", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapHashMapForeach(ys)(_.swap); i += 1 }; Bool(ys.head._1 ^ ys.head._2) }) ::
  509.     base.copy(alg="mi", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapHashMapIterator(ys)(_.swap); i += 1 }; Bool(ys.head._1 ^ ys.head._2) }) ::
  510.     base.copy(alg="ff", op = () => { var ys = HashMap[Int,Int](); var i=0; while (i<N) { ys = filterHashMapForeach(xs)(x => x._1 < x._2); i += 1 }; Bool(ys.head._1 ^ ys.head._2) }) ::
  511.     base.copy(alg="fi", op = () => { var ys = HashMap[Int,Int](); var i=0; while (i<N) { ys = filterHashMapIterator(xs)(x => x._1 < x._2); i += 1 }; Bool(ys.head._1 ^ ys.head._2) }) ::
  512.     base.copy(alg="rf", op = () => { var y: Int = Int.MaxValue; var i=0; while (i<N) { y = foldHashMapForeach(xs)(y)((a,b) => math.min(a,b._1+b._2)); i += 1 }; Bool(y) }) ::
  513.     base.copy(alg="ri", op = () => { var y: Int = Int.MaxValue; var i=0; while (i<N) { y = foldHashMapIterator(xs)(y)((a,b) => math.min(a,b._1+b._2)); i += 1 }; Bool(y) }) ::
  514.     Nil
  515.   }
  516.  
  517.   // Standard six methods with ArrayBuffer
  518.   import scala.collection.mutable.{ArrayBuffer => ArrayBuf}
  519.   def mapArrayBufForeach[Q](xs: ArrayBuf[Q])(f: Q => Q) = {
  520.     var yb = ArrayBuf.newBuilder[Q]
  521.     xs.foreach{x => yb += f(x) }
  522.     yb.result
  523.   }
  524.   def mapArrayBufIterator[Q](xs: ArrayBuf[Q])(f: Q => Q) = {
  525.     var yb = ArrayBuf.newBuilder[Q]
  526.     val xi = xs.iterator
  527.     while (xi.hasNext) { yb += f(xi.next) }
  528.     yb.result
  529.   }
  530.   def filterArrayBufForeach[Q](xs: ArrayBuf[Q])(f: Q => Boolean) = {
  531.     var yb = ArrayBuf.newBuilder[Q]
  532.     xs.foreach{ x => if (f(x)) yb += x }
  533.     yb.result
  534.   }
  535.   def filterArrayBufIterator[Q](xs: ArrayBuf[Q])(f: Q => Boolean) = {
  536.     var yb = ArrayBuf.newBuilder[Q]
  537.     val xi = xs.iterator
  538.     while (xi.hasNext) {
  539.       val x = xi.next
  540.       if (f(x)) yb += x
  541.     }
  542.     yb.result
  543.   }
  544.   def foldArrayBufForeach[Q](xs: ArrayBuf[Q])(zero: Q)(f: (Q,Q) => Q) = {
  545.     var i = zero
  546.     xs.foreach{ x => i = f(i,x) }
  547.     i
  548.   }
  549.   def foldArrayBufIterator[Q](xs: ArrayBuf[Q])(zero: Q)(f: (Q,Q) => Q) = {
  550.     var i = zero
  551.     var xi = xs.iterator
  552.     while (xi.hasNext) { i = f(i,xi.next) }
  553.     i
  554.   }
  555.   def testArrayBufs(len: Int): List[Benchable] = {
  556.     val rng = mkRng
  557.     val xs: ArrayBuf[Bool] = ArrayBuf.fill(len){ if (rng.nextBoolean) T else F }
  558.     val N = (if (len/1000 >= 10) 1 else if (len/1000 > 1) 10 else if (len/100 > 1) 100 else 1000)
  559.     val base = Benchable("ArrayBuf",len,len*N,"",()=>T)
  560.    
  561.     base.copy(alg="mf", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapArrayBufForeach(ys)(_.flip); i += 1 }; ys.head }) ::
  562.     base.copy(alg="mi", op = () => { var ys = xs; var i=0; while (i<N) { ys = mapArrayBufIterator(ys)(_.flip); i += 1 }; ys.head }) ::
  563.     base.copy(alg="ff", op = () => { var ys = ArrayBuf[Bool](); var i=0; while (i<N) { ys = filterArrayBufForeach(xs)(_ eq F); i += 1 }; ys.head }) ::
  564.     base.copy(alg="fi", op = () => { var ys = ArrayBuf[Bool](); var i=0; while (i<N) { ys = filterArrayBufIterator(xs)(_ eq F); i += 1 }; ys.head }) ::
  565.     base.copy(alg="rf", op = () => { var y: Bool = F; var i=0; while (i<N) { y = foldArrayBufForeach(xs)(y)(_ ^ _); i += 1 }; y }) ::
  566.     base.copy(alg="ri", op = () => { var y: Bool = F; var i=0; while (i<N) { y = foldArrayBufIterator(xs)(y)(_ ^ _); i += 1 }; y }) ::
  567.     Nil
  568.   }
  569.  
  570.   // Standard six methods with Range
  571.   def mapRangeForeach(xs: Range)(f: Int => Int) = {
  572.     var yb = ArrayBuf[Int]()
  573.     xs.foreach{x => yb += f(x) }
  574.     yb.result
  575.   }
  576.   def mapRangeIterator(xs: Range)(f: Int => Int) = {
  577.     var yb = ArrayBuf[Int]()
  578.     val xi = xs.iterator
  579.     while (xi.hasNext) { yb += f(xi.next) }
  580.     yb.result
  581.   }
  582.   def filterRangeForeach(xs: Range)(f: Int => Boolean) = {
  583.     var yb = ArrayBuf[Int]()
  584.     xs.foreach{ x => if (f(x)) yb += x }
  585.     yb.result
  586.   }
  587.   def filterRangeIterator(xs: Range)(f: Int => Boolean) = {
  588.     var yb = ArrayBuf[Int]()
  589.     val xi = xs.iterator
  590.     while (xi.hasNext) {
  591.       val x = xi.next
  592.       if (f(x)) yb += x
  593.     }
  594.     yb.result
  595.   }
  596.   def foldRangeForeach(xs: Range)(zero: Int)(f: (Int,Int) => Int) = {
  597.     var i = zero
  598.     xs.foreach{ x => i = f(i,x) }
  599.     i
  600.   }
  601.   def foldRangeIterator(xs: Range)(zero: Int)(f: (Int,Int) => Int) = {
  602.     var i = zero
  603.     var xi = xs.iterator
  604.     while (xi.hasNext) { i = f(i,xi.next) }
  605.     i
  606.   }
  607.   def testRanges(len: Int): List[Benchable] = {
  608.     val rng = mkRng
  609.     val xs: Range = Range(0,len)
  610.     val N = (if (len/1000 >= 100) 1 else if (len/1000 > 10) 10 else if (len/1000 > 1) 100 else if (len/100>1) 1000 else 10000)
  611.     val base = Benchable("Range",len,len*N,"",()=>T)
  612.    
  613.     base.copy(alg="mf", op = () => { var ys = ArrayBuf[Int](); var i=0; while (i<N) { ys = mapRangeForeach(xs)(_+1); i += 1 }; Bool(ys.head) }) ::
  614.     base.copy(alg="mi", op = () => { var ys = ArrayBuf[Int](); var i=0; while (i<N) { ys = mapRangeIterator(xs)(_+1); i += 1 }; Bool(ys.head) }) ::
  615.     base.copy(alg="ff", op = () => { var ys = ArrayBuf[Int](); var i=0; while (i<N) { ys = filterRangeForeach(xs)(_ >= 0); i += 1 }; Bool(ys.head) }) ::
  616.     base.copy(alg="fi", op = () => { var ys = ArrayBuf[Int](); var i=0; while (i<N) { ys = filterRangeIterator(xs)(_ >= 0); i += 1 }; Bool(ys.head) }) ::
  617.     base.copy(alg="rf", op = () => { var y = 0; var i=0; while (i<N) { y = foldRangeForeach(xs)(y)((a,b) => a + b); i += 1 }; Bool(y) }) ::
  618.     base.copy(alg="ri", op = () => { var y = 0; var i=0; while (i<N) { y = foldRangeIterator(xs)(y)((a,b) => a + b); i += 1 }; Bool(y) }) ::
  619.     Nil
  620.   }
  621.  
  622.  
  623.   /***** Main *****/
  624.  
  625.   val availableCollections = Array("List","Vector","Set","Array","TreeSet","Map","mHashMap","ArrayBuf","Range")
  626.   val defaultSizes = Seq(2,50,1250,31250)
  627.  
  628.   // Run this in the REPL to run the collections and sizes one at a time.
  629.   // Put a link in the current directory to the Scala version you want to use.
  630.   def scriptMe = {
  631.     for (cc <- availableCollections.sorted; sz <- defaultSizes.sorted) println("./scala -J-Xmx6G ForeachIteratorShootout -quiet -collections="+cc+" -n="+sz)
  632.   }
  633.  
  634.   def main(args: Array[String]) { for (i <- 1 to 2) {
  635.     val isQuiet = args.contains("-quiet")
  636.     val numbers = args.find(_.startsWith("-n=")).map(_.drop(3).split(",").map(_.toInt).toSeq).getOrElse(defaultSizes)
  637.     val algs = args.find(_.startsWith("-alg=")).map(_.drop(5)).getOrElse("mfr").map(_.toString).toSet
  638.     val colls = args.find(_.startsWith("-collections=")).map(_.drop(13).split(",")).getOrElse(availableCollections).toSet
  639.     printedBench(0.05, 40, !isQuiet){
  640.       numbers.flatMap(n => testLists(n) ++ testVectors(n) ++ testSets(n) ++ testArrays(n) ++ testTreeSets(n) ++ testMaps(n) ++ testHashMaps(n) ++ testArrayBufs(n) ++ testRanges(n)).
  641.       filter(colls contains _.name).filter(algs contains _.alg.take(1))
  642.     }
  643.   }}
  644. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement