import x10.util.Random; import x10.util.Timer; import x10.util.concurrent.AtomicInteger; public class Count3s { private static abstract class Version { static val NUM_TRIALS = 5; static val ARRAY_LENGTH = 100000000; static val MAX_VALUE = 20; static val MAX_ASYNCS = 64; val rand = new Random(System.nanoTime()); def check(arr:Array[Int]{self.rank==1}, x:Int) { var ans:Int = 0; for (var i:Int = 0; i < arr.size; i++) if (arr(i) == 3) ans++; if (x != ans) throw new Exception("Incorrect result!"); } def array():Array[Int]{self.rank==1} { return (new Array[Int](ARRAY_LENGTH, (p:Int) => rand.nextInt(MAX_VALUE))); } abstract def count(arr:Array[Int]{self.rank==1}, n:Int):Int; def time(arr:Array[Int]{self.rank==1}, numAsyncs:Int):Long { val start = Timer.milliTime(); val c = count(arr, numAsyncs); val end = Timer.milliTime(); //check(arr,c); // TURN THIS OFF TO SAVE TIME IF SURE CODE IS FUNCTIONING //Console.OUT.println("time="+(end-start)); return (end-start); } def times(numAsyncs:Int):Array[Long]{self.rank==1} { val arr = array(); return (new Array[Long](NUM_TRIALS,(p:Int) => time(arr,numAsyncs))); } def avg(arr:Array[Long]{self.rank==1}):Float { val sum = arr.reduce((a:Long,b:Long)=>a+b,0L); return (sum/arr.size); } def asyncs():Array[Int]{self.rank==1} { val n = Math.log2(MAX_ASYNCS)+1; return (new Array[Int](n, (p:Int) => Math.pow2(p))); } abstract def description():String; def pretty(x:Float):String{ return String.format("%.2f", new Array[Any](1, x)); } def run() { Console.OUT.println("============== " + description() + " =============="); Console.OUT.println("asyncs\tspeedup\ttime\ttimes"); var b:Float = 0; // Deliberately trigger a divide by 0 if baseline not overwritten for (var n:Int = 1; n <= MAX_ASYNCS; n = n*2) { val t = times(n); val v = avg(t); if (n == 1) b = v; val s = b/v; Console.OUT.println(n + "\t" + pretty(s) + "\t" + pretty(v) + "\t" + t); } } } private static class Par1 extends Version { def description():String { return "first parallel impl"; } def count(arr:Array[Int]{self.rank==1}, n:Int):Int { var count:Int = 0; if (n > arr.size) throw new Exception("About to inf loop!"); val step = arr.size/n; finish for (var lower:Int = 0; lower < arr.size; lower+=step) { val upper = (lower+step >= arr.size) ? arr.size : lower+step; val l = lower; async for (var i:Int = l; i < upper; i++) { if (arr(i) == 3) atomic { count++; } } } return count; } } private static class Par2 extends Version { def description():String { return "second parallel impl (AtomicInteger, local counter)"; } def count(arr:Array[Int]{self.rank==1}, n:Int):Int { var count:AtomicInteger = new AtomicInteger(0); if (n > arr.size) throw new Exception("About to inf loop!"); val step = arr.size/n; finish for (var lower:Int = 0; lower < arr.size; lower+=step) { val upper = (lower+step >= arr.size) ? arr.size : lower+step; val l = lower; async { var local:Int = 0; for (var i:Int = l; i < upper; i++) { if (arr(i) == 3) local++; } count.addAndGet(local); } } return count.get(); } } private static class SerialPrim extends Version { def description():String { return "serial, using primitives"; } def count(arr:Array[Int]{self.rank==1}, n:Int):Int { var x:Int = 0; for (var i:Int = 0; i < arr.size; i++) if (arr(i) == 3) x++; return x; } } private static class SerialFu extends Version { def description():String { return "serial, using X10-fu"; } def count(arr:Array[Int]{self.rank==1}, n:Int):Int { return arr.reduce((a:Int,s:Int)=>(a==3)?s+1:s,0); } } public static def main(Array[String]) { var v:Version; v = new Count3s.SerialPrim(); v.run(); v = new Count3s.SerialFu(); v.run(); v = new Count3s.Par1(); v.run(); v = new Count3s.Par2(); v.run(); } }