Update BenchmarksGame benchmarks to latest
authorJoseph Tremoulet <jotrem@microsoft.com>
Thu, 31 Aug 2017 18:32:57 +0000 (14:32 -0400)
committerJoseph Tremoulet <jotrem@microsoft.com>
Fri, 15 Sep 2017 17:28:10 +0000 (13:28 -0400)
For each benchmark, grab the current best C# .NET entry, and also grab
the current best serial implementation (since these are easier to work
with from the benchmarking perspective).

29 files changed:
.gitattributes
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/binarytrees/binarytrees-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/binarytrees/binarytrees-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fannkuch-redux/fannkuch-redux-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fannkuch-redux/fannkuch-redux-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fasta/fasta-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fasta/fasta-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fastaredux/fastaredux-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/k-nucleotide-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/k-nucleotide-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/n-body/n-body-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/n-body/n-body-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/n-body/n-body.csproj [moved from tests/src/JIT/Performance/CodeQuality/BenchmarksGame/nbody/nbody.csproj with 100% similarity]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/n-body/nbody.csharp-3.cs [moved from tests/src/JIT/Performance/CodeQuality/BenchmarksGame/nbody/nbody.csharp-3.cs with 100% similarity]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/pidigits/pidigits-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/pidigits/pidigits-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regex-redux/regex-redux-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regex-redux/regex-redux-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regexdna/regexdna-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/revcomp-input25.txt [moved from tests/src/JIT/Performance/CodeQuality/BenchmarksGame/revcomp/revcomp-input25.txt with 100% similarity]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/revcomp-input25000.txt [moved from tests/src/JIT/Performance/CodeQuality/BenchmarksGame/revcomp/revcomp-input25000.txt with 100% similarity]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/revcomp.csharp-1.cs [moved from tests/src/JIT/Performance/CodeQuality/BenchmarksGame/revcomp/revcomp.csharp-1.cs with 100% similarity]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-serial.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement.csproj [moved from tests/src/JIT/Performance/CodeQuality/BenchmarksGame/revcomp/revcomp.csproj with 100% similarity]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/spectralnorm/spectralnorm-best.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/spectralnorm/spectralnorm-serial.cs [new file with mode: 0644]

index 519ecbb..add8434 100644 (file)
@@ -69,8 +69,8 @@ src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt text eol=lf
 
 tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regexdna/regexdna-input25.txt text eol=lf
 tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regexdna/regexdna-input25000.txt text eol=lf
-tests/src/JIT/Performance/CodeQuality/BenchmarksGame/revcomp/revcomp-input25.txt text eol=lf
-tests/src/JIT/Performance/CodeQuality/BenchmarksGame/revcomp/revcomp-input25000.txt text eol=lf
+tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/revcomp-input25.txt text eol=lf
+tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/revcomp-input25000.txt text eol=lf
 tests/src/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/knucleotide-input.txt text eol=lf
 tests/src/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/knucleotide-input-big.txt text eol=lf
 
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/binarytrees/binarytrees-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/binarytrees/binarytrees-best.cs
new file mode 100644 (file)
index 0000000..f559a51
--- /dev/null
@@ -0,0 +1,105 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from binary-trees C# .NET Core #5 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=binarytrees&lang=csharpcore&id=5
+// Best-scoring C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/ 
+
+   contributed by Marek Safar  
+   *reset*
+   concurrency added by Peperud
+   minor improvements by Alex Yakunin
+*/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Threading.Tasks;
+
+public sealed class BinaryTrees
+{
+    public const int MinDepth = 4;
+
+    public static void Main(string[] args)
+    {
+        var n = args.Length == 0 ? 0 : int.Parse(args[0]);
+        var maxDepth = n < (MinDepth + 2) ? MinDepth + 2 : n;
+        var stretchDepth = maxDepth + 1;
+
+        var stretchDepthTask = Task.Run(() => TreeNode.CreateTree(stretchDepth).CountNodes());
+        var maxDepthTask = Task.Run(() => TreeNode.CreateTree(maxDepth).CountNodes());
+
+        var tasks = new Task<string>[(maxDepth - MinDepth) / 2 + 1];
+        for (int depth = MinDepth, ti = 0; depth <= maxDepth; depth += 2, ti++) {
+            var iterationCount = 1 << (maxDepth - depth + MinDepth);
+            var depthCopy = depth; // To make sure closure value doesn't change
+            tasks[ti] = Task.Run(() => {
+                var count = 0;
+                if (depthCopy >= 17) {
+                    // Parallelized computation for relatively large tasks
+                    var miniTasks = new Task<int>[iterationCount];
+                    for (var i = 0; i < iterationCount; i++)
+                        miniTasks[i] = Task.Run(() => TreeNode.CreateTree(depthCopy).CountNodes());
+                    Task.WaitAll(miniTasks);
+                    for (var i = 0; i < iterationCount; i++)
+                        count += miniTasks[i].Result;
+                }
+                else {
+                    // Sequential computation for smaller tasks
+                    for (var i = 0; i < iterationCount; i++)
+                        count += TreeNode.CreateTree(depthCopy).CountNodes();
+                }
+                return $"{iterationCount}\t trees of depth {depthCopy}\t check: {count}";
+            });
+        }
+        Task.WaitAll(tasks);
+
+        Console.WriteLine("stretch tree of depth {0}\t check: {1}",
+            stretchDepth, stretchDepthTask.Result);
+        foreach (var task in tasks)
+            Console.WriteLine(task.Result);
+        Console.WriteLine("long lived tree of depth {0}\t check: {1}",
+            maxDepth, maxDepthTask.Result);
+    }
+}
+
+public struct TreeNode
+{
+    public sealed class NodeData
+    {
+        public TreeNode Left, Right;
+
+        public NodeData(TreeNode left, TreeNode right)
+        {
+            Left = left;
+            Right = right;
+        }
+    }
+
+    public NodeData Data;
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public TreeNode(TreeNode left, TreeNode right)
+    {
+        Data = new NodeData(left, right);
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public static TreeNode CreateTree(int depth)
+    {
+        return depth <= 0
+            ? default(TreeNode)
+            : new TreeNode(CreateTree(depth - 1), CreateTree(depth - 1));
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    public int CountNodes()
+    {
+        if (ReferenceEquals(Data, null))
+            return 1;
+        return 1 + Data.Left.CountNodes() + Data.Right.CountNodes();
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/binarytrees/binarytrees-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/binarytrees/binarytrees-serial.cs
new file mode 100644 (file)
index 0000000..95732c6
--- /dev/null
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from binary-trees C# .NET Core #2 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=binarytrees&lang=csharpcore&id=2
+// Best-scoring single-threaded C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/ 
+
+   contributed by Marek Safar 
+   *reset* 
+*/
+
+using System;
+
+class BinaryTrees
+{
+   const int minDepth = 4;
+
+   public static void Main(String[] args)
+   {
+      int n = 0;
+      if (args.Length > 0) n = Int32.Parse(args[0]);
+
+      int maxDepth = Math.Max(minDepth + 2, n);
+      int stretchDepth = maxDepth + 1;
+
+      int check = (TreeNode.bottomUpTree(stretchDepth)).itemCheck();
+      Console.WriteLine("stretch tree of depth {0}\t check: {1}", stretchDepth, check);
+
+      TreeNode longLivedTree = TreeNode.bottomUpTree(maxDepth);
+
+      for (int depth=minDepth; depth<=maxDepth; depth+=2){
+         int iterations = 1 << (maxDepth - depth + minDepth);
+
+         check = 0;
+         for (int i=1; i<=iterations; i++)
+         {
+            check += (TreeNode.bottomUpTree(depth)).itemCheck();
+         }
+
+         Console.WriteLine("{0}\t trees of depth {1}\t check: {2}",
+            iterations, depth, check);
+      }
+
+      Console.WriteLine("long lived tree of depth {0}\t check: {1}",
+         maxDepth, longLivedTree.itemCheck());
+   }
+
+
+   struct TreeNode
+   {
+      class Next
+         {
+             public TreeNode left, right;
+      }
+       
+      private Next next;
+
+      internal static TreeNode bottomUpTree(int depth){
+         if (depth>0){
+            return new TreeNode(
+                 bottomUpTree(depth-1)
+               , bottomUpTree(depth-1)
+               );
+         }
+         else {
+            return new TreeNode();
+         }
+      }
+
+      TreeNode(TreeNode left, TreeNode right){
+        this.next = new Next ();
+         this.next.left = left;
+         this.next.right = right;
+      }
+
+      internal int itemCheck(){
+         // if necessary deallocate here
+         if (next==null) return 1;
+         else return 1 + next.left.itemCheck() + next.right.itemCheck();
+      }
+   }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fannkuch-redux/fannkuch-redux-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fannkuch-redux/fannkuch-redux-best.cs
new file mode 100644 (file)
index 0000000..470b67b
--- /dev/null
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from fannkuch-redux C# .NET Core #5 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=fannkuchredux&lang=csharpcore&id=5
+// Best-scoring C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+
+   contributed by Isaac Gouy, transliterated from Oleg Mazurov's Java program
+   concurrency fix and minor improvements by Peperud
+   parallel and small optimisations by Anthony Lloyd
+*/
+
+using System;
+using System.Threading;
+using System.Runtime.CompilerServices;
+
+public static class FannkuchRedux
+{
+    static int[] fact, chkSums, maxFlips;
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    static void firstPermutation(int[] p, int[] pp, int[] count, int idx)
+    {
+        for (int i = 0; i < p.Length; ++i) p[i] = i;
+        for (int i = count.Length - 1; i > 0; --i)
+        {
+            int d = idx / fact[i];
+            count[i] = d;
+            if (d > 0)
+            {
+                idx = idx % fact[i];
+                for (int j = i; j >= 0; --j) pp[j] = p[j];
+                for (int j = 0; j <= i; ++j) p[j] = pp[(j + d) % (i + 1)];
+            }
+        }
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    static int nextPermutation(int[] p, int[] count)
+    {
+        int first = p[1];
+        p[1] = p[0];
+        p[0] = first;
+        int i = 1;
+        while (++count[i] > i)
+        {
+            count[i++] = 0;
+            int next = p[1];
+            p[0] = next;
+            for (int j = 1; j < i;) p[j] = p[++j];
+            p[i] = first;
+            first = next;
+        }
+        return first;
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    static int countFlips(int first, int[] p, int[] pp)
+    {
+        if (first == 0) return 0;
+        if (p[first] == 0) return 1;
+        for (int i = 0; i < pp.Length; i++) pp[i] = p[i];
+        int flips = 2;
+        while (true)
+        {
+            for (int lo = 1, hi = first - 1; lo < hi; lo++, hi--)
+            {
+                int t = pp[lo];
+                pp[lo] = pp[hi];
+                pp[hi] = t;
+            }
+            int tp = pp[first];
+            if (pp[tp] == 0) return flips;
+            pp[first] = first;
+            first = tp;
+            flips++;
+        }
+    }
+
+    static void run(int n, int taskId, int taskSize)
+    {
+        int[] p = new int[n], pp = new int[n], count = new int[n];
+        firstPermutation(p, pp, count, taskId * taskSize);
+        int chksum = countFlips(p[0], p, pp);
+        int maxflips = chksum;
+        while (--taskSize > 0)
+        {
+            var flips = countFlips(nextPermutation(p, count), p, pp);
+            chksum += (1 - (taskSize % 2) * 2) * flips;
+            if (flips > maxflips) maxflips = flips;
+        }
+        chkSums[taskId] = chksum;
+        maxFlips[taskId] = maxflips;
+    }
+
+    public static void Main(string[] args)
+    {
+        int n = args.Length > 0 ? int.Parse(args[0]) : 7;
+        fact = new int[n + 1];
+        fact[0] = 1;
+        var factn = 1;
+        for (int i = 1; i < fact.Length; i++) { fact[i] = factn *= i; }
+
+        int nTasks = Environment.ProcessorCount;
+        chkSums = new int[nTasks];
+        maxFlips = new int[nTasks];
+        int taskSize = factn / nTasks;
+        var threads = new Thread[nTasks];
+        for (int i = 1; i < nTasks; i++)
+        {
+            int j = i;
+            (threads[j] = new Thread(() => run(n, j, taskSize))).Start();
+        }
+        run(n, 0, taskSize);
+        int chksum = chkSums[0], maxflips = maxFlips[0];
+        for (int i = 1; i < threads.Length; i++)
+        {
+            threads[i].Join();
+            chksum += chkSums[i];
+            if (maxFlips[i] > maxflips) maxflips = maxFlips[i];
+        }
+        Console.Out.WriteLineAsync(chksum + "\nPfannkuchen(" + n + ") = " + maxflips);
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fannkuch-redux/fannkuch-redux-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fannkuch-redux/fannkuch-redux-serial.cs
new file mode 100644 (file)
index 0000000..646b68d
--- /dev/null
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from fannkuch-redux C# .NET Core #2 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=fannkuchredux&lang=csharpcore&id=2
+// Best-scoring single-threaded C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+
+   contributed by Isaac Gouy, transliterated from Mike Pall's Lua program 
+*/
+
+using System;
+
+class FannkuchRedux
+{
+   public static int[] fannkuch(int n) {
+      int[] p = new int[n], q = new int[n], s = new int[n]; 
+      int sign = 1, maxflips = 0, sum = 0, m = n-1;
+      for(int i=0; i<n; i++){ p[i] = i; q[i] = i; s[i] = i; }      
+      do {
+         // Copy and flip.
+         var q0 = p[0];                                     // Cache 0th element.
+         if (q0 != 0){
+            for(int i=1; i<n; i++) q[i] = p[i];             // Work on a copy.
+            var flips = 1;
+            do { 
+               var qq = q[q0]; 
+               if (qq == 0){                                // ... until 0th element is 0.
+                  sum += sign*flips;
+                 if (flips > maxflips) maxflips = flips;   // New maximum?
+                  break; 
+               } 
+              q[q0] = q0; 
+              if (q0 >= 3){
+                 int i = 1, j = q0 - 1, t;
+                  do { t = q[i]; q[i] = q[j]; q[j] = t; i++; j--; } while (i < j); 
+               }
+              q0 = qq; flips++;
+            } while (true); 
+         }
+         // Permute.
+         if (sign == 1){
+            var t = p[1]; p[1] = p[0]; p[0] = t; sign = -1; // Rotate 0<-1.
+         } else { 
+            var t = p[1]; p[1] = p[2]; p[2] = t; sign = 1;  // Rotate 0<-1 and 0<-1<-2.
+            for(int i=2; i<n; i++){ 
+              var sx = s[i];
+              if (sx != 0){ s[i] = sx-1; break; }
+              if (i == m) return new int[]{sum,maxflips};  // Out of permutations.
+              s[i] = i;
+              // Rotate 0<-...<-i+1.
+              t = p[0]; for(int j=0; j<=i; j++){ p[j] = p[j+1]; } p[i+1] = t;
+            }
+         }
+      } while (true);
+   }
+
+   static void Main(string[] args){
+      int n = (args.Length > 0) ? Int32.Parse(args[0]) : 7;
+      var pf = fannkuch(n);
+      Console.Write("{0}\nPfannkuchen({1}) = {2}\n", pf[0], n, pf[1]);
+   }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fasta/fasta-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fasta/fasta-best.cs
new file mode 100644 (file)
index 0000000..3430c37
--- /dev/null
@@ -0,0 +1,288 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from fasta C# .NET Core program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=fasta&lang=csharpcore&id=1
+// Best-scoring C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+  http://benchmarksgame.alioth.debian.org/
+
+  contributed by Serge Smith
+  further optimized (rewrote threading, random generation loop) by Jan de Vaan
+  modified by Josh Goldfoot (fasta-repeat buffering)
+*/
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+class Fasta
+{
+    const int LineLength = 60;
+
+    const int IM = 139968;
+    const int IA = 3877;
+    const int IC = 29573;
+    static int seed = 42;
+
+    public static void Main(string[] args)
+    {
+        int n = args.Length > 0 ? Int32.Parse(args[0]) : 1000;
+
+        MakeCumulative(IUB);
+        MakeCumulative(HomoSapiens);
+
+        using (var s = Console.OpenStandardOutput())
+        {
+            MakeRepeatFasta("ONE", "Homo sapiens alu", Encoding.ASCII.GetBytes(ALU), n * 2, s);
+            MakeRandomFasta("TWO", "IUB ambiguity codes", IUB, n * 3, s);
+            MakeRandomFasta("THREE", "Homo sapiens frequency", HomoSapiens, n * 5, s);
+        }
+    }
+
+
+
+    public static IEnumerable<R> TransformQueue<T, R>(BlockingCollection<T> queue,
+        Func<T, R> transform, int threadCount)
+    {
+        var tasks = new Task<R>[threadCount];
+
+        for (int i = 0; i < threadCount; ++i)
+        {
+            T input;
+            if (!queue.TryTake(out input, Timeout.Infinite))
+                break;
+
+            tasks[i] = Task.Run(() => transform(input));
+        }
+
+        int pos = 0;
+        while (true)
+        {
+            if (tasks[pos] == null)
+                break;
+
+            yield return tasks[pos].Result;
+
+            T input;
+            tasks[pos] = queue.TryTake(out input, Timeout.Infinite)
+                ? Task.Run(() => transform(input))
+                : null;
+
+            pos = (pos + 1) % threadCount;
+        }
+    }
+
+
+
+    static void MakeRandomFasta(string id, string desc,
+                                Frequency[] a, int n, Stream s)
+    {
+        var queue = new BlockingCollection<int[]>(2);
+
+        var bufferCount = Environment.ProcessorCount + 4;
+
+        Task.Run(() =>
+        {
+            var len = LineLength * 40;
+            var buffers = Enumerable.Range(0, bufferCount)
+            .Select(i => new int[len]).ToArray();
+            var index = 0;
+            for (var i = 0; i < n; i += len)
+            {
+                var buffer = n - i < len
+                    ? new int[n - i]
+                    : buffers[index++ % buffers.Length];
+
+                FillRandom(buffer);
+                queue.Add(buffer);
+            }
+            queue.CompleteAdding();
+        });
+
+        byte[] descStr = Encoding.ASCII.GetBytes(">" + id + " " + desc + "\n");
+        s.Write(descStr, 0, descStr.Length);
+
+        foreach (var r in TransformQueue(queue,
+            rnd => SelectNucleotides(a, rnd), Environment.ProcessorCount))
+        {
+            s.Write(r, 0, r.Length);
+        }
+
+    }
+
+    private static byte[] SelectNucleotides(Frequency[] a, int[] rnd)
+    {
+        var resLength = (rnd.Length / LineLength) * (LineLength + 1);
+        if (rnd.Length % LineLength != 0)
+        {
+            resLength += rnd.Length % LineLength + 1;
+        }
+
+        var buf = new byte[resLength];
+        var index = 0;
+        for (var i = 0; i < rnd.Length; i += LineLength)
+        {
+            var len = Math.Min(LineLength, rnd.Length - i);
+            for (var j = 0; j < len; ++j)
+                buf[index++] = SelectRandom(a, (int)rnd[i + j]);
+            buf[index++] = (byte)'\n';
+        }
+        return buf;
+    }
+
+    static void MakeRepeatFasta(string id, string desc,
+                                byte[] alu, int n, Stream s)
+    {
+        byte[] descStr = Encoding.ASCII.GetBytes(">" + id + " " + desc + "\n");
+        s.Write(descStr, 0, descStr.Length);
+
+        /* JG: fasta_repeat repeats every len(alu) * line-length = 287 * 61 = 17507 characters.
+              So, calculate this once, then just print that buffer over and over. */
+
+        byte[] sequence;
+        int sequenceLength;
+        using (var unstandardOut = new MemoryStream(alu.Length * (LineLength + 1) + 1))
+        {
+            MakeRepeatFastaBuffer(alu, alu.Length * LineLength, unstandardOut);
+            sequenceLength = (int)unstandardOut.Length;
+            sequence = new byte[sequenceLength];
+            unstandardOut.Seek(0, SeekOrigin.Begin);
+            unstandardOut.Read(sequence, 0, sequenceLength);
+        }
+        int outputBytes = n + n / 60;
+        while (outputBytes >= sequenceLength)
+        {
+            s.Write(sequence, 0, sequenceLength);
+            outputBytes -= sequenceLength;
+        }
+        if (outputBytes > 0)
+        {
+            s.Write(sequence, 0, outputBytes);
+            s.WriteByte((byte)'\n');
+        }
+    }
+
+    static void MakeRepeatFastaBuffer(byte[] alu, int n, Stream s)
+    {
+        var index = 0;
+        int m = 0;
+        int k = 0;
+        int kn = alu.Length;
+        var buf = new byte[1024];
+
+        while (n > 0)
+        {
+            m = n < LineLength ? n : LineLength;
+
+            if (buf.Length - index < m)
+            {
+                s.Write(buf, 0, index);
+                index = 0;
+            }
+
+            for (int i = 0; i < m; i++)
+            {
+                if (k == kn)
+                    k = 0;
+
+                buf[index++] = alu[k];
+                k++;
+            }
+
+            buf[index++] = (byte)'\n';
+            n -= LineLength;
+        }
+
+        if (index != 0)
+            s.Write(buf, 0, index);
+    }
+
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    static byte SelectRandom(Frequency[] a, int r)
+    {
+        for (int i = 0; i < a.Length - 1; i++)
+            if (r < a[i].p)
+                return a[i].c;
+
+        return a[a.Length - 1].c;
+    }
+
+    static void MakeCumulative(Frequency[] a)
+    {
+        double cp = 0;
+        for (int i = 0; i < a.Length; i++)
+        {
+            cp += a[i].p;
+            a[i].p = cp;
+        }
+    }
+
+    static string ALU =
+      "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
+      "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" +
+      "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" +
+      "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
+      "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
+      "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
+      "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
+
+    struct Frequency
+    {
+        public readonly byte c;
+        public double p;
+
+        public Frequency(char c, double p)
+        {
+            this.c = (byte)c;
+            this.p = (p * IM);
+        }
+    }
+
+    static Frequency[] IUB = {
+    new Frequency ('a', 0.27)
+        ,new Frequency ('c', 0.12)
+        ,new Frequency ('g', 0.12)
+        ,new Frequency ('t', 0.27)
+
+        ,new Frequency ('B', 0.02)
+        ,new Frequency ('D', 0.02)
+        ,new Frequency ('H', 0.02)
+        ,new Frequency ('K', 0.02)
+        ,new Frequency ('M', 0.02)
+        ,new Frequency ('N', 0.02)
+        ,new Frequency ('R', 0.02)
+        ,new Frequency ('S', 0.02)
+        ,new Frequency ('V', 0.02)
+        ,new Frequency ('W', 0.02)
+        ,new Frequency ('Y', 0.02)
+};
+
+    static Frequency[] HomoSapiens = {
+    new Frequency ('a', 0.3029549426680)
+        ,new Frequency ('c', 0.1979883004921)
+        ,new Frequency ('g', 0.1975473066391)
+        ,new Frequency ('t', 0.3015094502008)
+};
+
+
+    private static void FillRandom(int[] result)
+    {
+        var s = seed;
+        for (var i = 0; i < result.Length; i++)
+        {
+            s = (s * IA + IC) % IM;
+            result[i] = s;
+        }
+        seed = s;
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fasta/fasta-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fasta/fasta-serial.cs
new file mode 100644 (file)
index 0000000..e91c6f8
--- /dev/null
@@ -0,0 +1,176 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from fasta C# .NET Core #2 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=fasta&lang=csharpcore&id=2
+// Best-scoring single-threaded C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+
+   contributed by Isaac Gouy
+   optimizations by Alp Toker <alp@atoker.com>
+*/
+
+using System;
+using System.IO;
+using System.Text;
+
+class Fasta
+{
+       static void Main (string[] args) {
+               MakeCumulative (HomoSapiens);
+               MakeCumulative (IUB);
+
+               int n = args.Length > 0 ? Int32.Parse (args[0]) : 1000;
+
+               using (Stream s = Console.OpenStandardOutput ()) {
+                       MakeRepeatFasta ("ONE", "Homo sapiens alu", Encoding.ASCII.GetBytes (ALU), n*2, s);
+                       MakeRandomFasta ("TWO", "IUB ambiguity codes", IUB, n*3, s);
+                       MakeRandomFasta ("THREE", "Homo sapiens frequency", HomoSapiens, n*5, s);
+               }
+       }
+
+       // The usual pseudo-random number generator
+
+       const int IM = 139968;
+       const int IA = 3877;
+       const int IC = 29573;
+       static int seed = 42;
+
+       static double random (double max)
+       {
+               return max * ((seed = (seed * IA + IC) % IM) * (1.0 / IM));
+       }
+
+       // Weighted selection from alphabet
+
+       static string ALU =
+               "GGCCGGGCGCGGTGGCTCACGCCTGTAATCCCAGCACTTTGG" +
+               "GAGGCCGAGGCGGGCGGATCACCTGAGGTCAGGAGTTCGAGA" +
+               "CCAGCCTGGCCAACATGGTGAAACCCCGTCTCTACTAAAAAT" +
+               "ACAAAAATTAGCCGGGCGTGGTGGCGCGCGCCTGTAATCCCA" +
+               "GCTACTCGGGAGGCTGAGGCAGGAGAATCGCTTGAACCCGGG" +
+               "AGGCGGAGGTTGCAGTGAGCCGAGATCGCGCCACTGCACTCC" +
+               "AGCCTGGGCGACAGAGCGAGACTCCGTCTCAAAAA";
+
+       class Frequency {
+               public byte c;
+               public double p;
+
+               public Frequency (char c, double p) {
+                       this.c = (byte)c;
+                       this.p = p;
+               }
+       }
+
+       static Frequency[] IUB = {
+               new Frequency ('a', 0.27)
+                       ,new Frequency ('c', 0.12)
+                       ,new Frequency ('g', 0.12)
+                       ,new Frequency ('t', 0.27)
+
+                       ,new Frequency ('B', 0.02)
+                       ,new Frequency ('D', 0.02)
+                       ,new Frequency ('H', 0.02)
+                       ,new Frequency ('K', 0.02)
+                       ,new Frequency ('M', 0.02)
+                       ,new Frequency ('N', 0.02)
+                       ,new Frequency ('R', 0.02)
+                       ,new Frequency ('S', 0.02)
+                       ,new Frequency ('V', 0.02)
+                       ,new Frequency ('W', 0.02)
+                       ,new Frequency ('Y', 0.02)
+       };
+
+       static Frequency[] HomoSapiens = {
+               new Frequency ('a', 0.3029549426680)
+                       ,new Frequency ('c', 0.1979883004921)
+                       ,new Frequency ('g', 0.1975473066391)
+                       ,new Frequency ('t', 0.3015094502008)
+       };
+
+       static void MakeCumulative (Frequency[] a) {
+               double cp = 0.0;
+               for (int i=0; i < a.Length; i++) {
+                       cp += a[i].p;
+                       a[i].p = cp;
+               }
+       }
+
+       // naive
+       static byte SelectRandom (Frequency[] a) {
+               double r = random (1.0);
+
+               for (int i=0 ; i < a.Length ; i++)
+                       if (r < a[i].p)
+                               return a[i].c;
+
+               return a[a.Length-1].c;
+       }
+
+       const int LineLength = 60;
+       static int index = 0;
+       static byte[] buf = new byte[1024];
+
+       static void MakeRandomFasta (string id, string desc, Frequency[] a, int n, Stream s) {
+               index = 0;
+               int m = 0;
+
+               byte[] descStr = Encoding.ASCII.GetBytes (">" + id + " " + desc + "\n");
+               s.Write (descStr, 0, descStr.Length);
+
+               while (n > 0) {
+                       m = n < LineLength ? n : LineLength;
+
+                       if (buf.Length - index < m) {
+                               s.Write (buf, 0, index);
+                               index = 0;
+                       }
+
+                       for (int i = 0 ; i < m ; i++) {
+                               buf[index++] = SelectRandom (a);
+                       }
+
+                       buf[index++] = (byte)'\n';
+                       n -= LineLength;
+               }
+
+               if (index != 0)
+                       s.Write (buf, 0, index);
+       }
+
+       static void MakeRepeatFasta (string id, string desc, byte[] alu, int n, Stream s) {
+               index = 0;
+               int m = 0;
+               int k = 0;
+               int kn = alu.Length;
+
+               byte[] descStr = Encoding.ASCII.GetBytes (">" + id + " " + desc + "\n");
+               s.Write (descStr, 0, descStr.Length);
+
+               while (n > 0) {
+                       m = n < LineLength ? n : LineLength;
+
+                       if (buf.Length - index < m) {
+                               s.Write (buf, 0, index);
+                               index = 0;
+                       }
+
+                       for (int i = 0; i < m ; i++) {
+                               if (k == kn)
+                                       k = 0;
+
+                               buf[index++] = alu[k];
+                               k++;
+                       }
+
+                       buf[index++] = (byte)'\n';
+                       n -= LineLength;
+               }
+
+               if (index != 0)
+                       s.Write (buf, 0, index);
+       }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fastaredux/fastaredux-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/fastaredux/fastaredux-best.cs
new file mode 100644 (file)
index 0000000..691fde3
--- /dev/null
@@ -0,0 +1 @@
+// no longer up on site
\ No newline at end of file
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/k-nucleotide-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/k-nucleotide-best.cs
new file mode 100644 (file)
index 0000000..2b648dd
--- /dev/null
@@ -0,0 +1,282 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from k-nucleotide C# .NET Core #9 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=knucleotide&lang=csharpcore&id=9
+// Best-scoring C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+   submitted by Josh Goldfoot
+   Modified to reduce memory and do more in parallel by Anthony Lloyd
+ */
+
+using System;
+using System.IO;
+using System.Text;
+using System.Linq;
+using System.Collections.Generic;
+using System.Threading.Tasks;
+using System.Runtime.CompilerServices;
+
+class Wrapper { public int v=1; }
+public static class KNucleotide
+{
+    const int BLOCK_SIZE = 1024 * 1024 * 8;
+    static List<byte[]> threeBlocks = new List<byte[]>();
+    static int threeStart, threeEnd;
+    static byte[] tonum = new byte[256];
+    static char[] tochar = new char[] {'A', 'C', 'G', 'T'};
+
+    static int read(Stream stream, byte[] buffer, int offset, int count)
+    {
+        var bytesRead = stream.Read(buffer, offset, count);
+        return bytesRead==count ? offset+count
+             : bytesRead==0 ? offset
+             : read(stream, buffer, offset+bytesRead, count-bytesRead);
+    }
+    
+    static int find(byte[] buffer, byte[] toFind, int i, ref int matchIndex)
+    {
+        if(matchIndex==0)
+        {
+            i = Array.IndexOf(buffer, toFind[0], i);
+            if(i==-1) return -1;
+            matchIndex = 1;
+            return find(buffer, toFind, i+1, ref matchIndex);
+        }
+        else
+        {
+            int bl = buffer.Length, fl = toFind.Length;
+            while(i<bl && matchIndex<fl)
+            {
+                if(buffer[i++]!=toFind[matchIndex++])
+                {
+                    matchIndex = 0;
+                    return find(buffer, toFind, i, ref matchIndex);
+                }
+            }
+            return matchIndex==fl ? i : -1;
+        }
+    }
+
+    static void loadThreeData()
+    {
+        var stream = Console.OpenStandardInput();
+        
+        // find three sequence
+        int matchIndex = 0;
+        var toFind = new [] {(byte)'>', (byte)'T', (byte)'H', (byte)'R', (byte)'E', (byte)'E'};
+        var buffer = new byte[BLOCK_SIZE];
+        do
+        {
+            threeEnd = read(stream, buffer, 0, BLOCK_SIZE);
+            threeStart = find(buffer, toFind, 0, ref matchIndex);
+        } while (threeStart==-1);
+        
+        // Skip to end of line
+        matchIndex = 0;
+        toFind = new [] {(byte)'\n'};
+        threeStart = find(buffer, toFind, threeStart, ref matchIndex);
+        while(threeStart==-1)
+        {
+            threeEnd = read(stream, buffer, 0, BLOCK_SIZE);
+            threeStart = find(buffer, toFind, 0, ref matchIndex);
+        }
+        threeBlocks.Add(buffer);
+        
+        if(threeEnd!=BLOCK_SIZE) // Needs to be at least 2 blocks
+        {
+            var bytes = threeBlocks[0];
+            for(int i=threeEnd; i<bytes.Length; i++)
+                bytes[i] = 255;
+            threeEnd = 0;
+            threeBlocks.Add(Array.Empty<byte>());
+            return;
+        }
+
+        // find next seq or end of input
+        matchIndex = 0;
+        toFind = new [] {(byte)'>'};
+        threeEnd = find(buffer, toFind, threeStart, ref matchIndex);
+        while(threeEnd==-1)
+        {
+            buffer = new byte[BLOCK_SIZE];
+            var bytesRead = read(stream, buffer, 0, BLOCK_SIZE);
+            threeEnd = bytesRead==BLOCK_SIZE ? find(buffer, toFind, 0, ref matchIndex)
+                        : bytesRead;
+            threeBlocks.Add(buffer);
+        }
+
+        if(threeStart+18>BLOCK_SIZE) // Key needs to be in the first block
+        {
+            byte[] block0 = threeBlocks[0], block1 = threeBlocks[1];
+            Buffer.BlockCopy(block0, threeStart, block0, threeStart-18, BLOCK_SIZE-threeStart);
+            Buffer.BlockCopy(block1, 0, block0, BLOCK_SIZE-18, 18);
+            for(int i=0; i<18; i++) block1[i] = 255;
+        }
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    static void check(Dictionary<long, Wrapper> dict, ref long rollingKey, byte nb, long mask)
+    {
+        if(nb==255) return;
+        rollingKey = ((rollingKey & mask) << 2) | nb;
+        Wrapper w;
+        if (dict.TryGetValue(rollingKey, out w))
+            w.v++;
+        else
+            dict[rollingKey] = new Wrapper();
+    }
+
+    [MethodImpl(MethodImplOptions.AggressiveInlining)]
+    static void checkEnding(Dictionary<long, Wrapper> dict, ref long rollingKey, byte b, byte nb, long mask)
+    {
+        if(nb==b)
+        {
+            Wrapper w;
+            if (dict.TryGetValue(rollingKey, out w))
+                w.v++;
+            else
+                dict[rollingKey] = new Wrapper();
+            rollingKey = ((rollingKey << 2) | nb) & mask;
+        }
+        else if(nb!=255)
+        {
+            rollingKey = ((rollingKey << 2) | nb) & mask;
+        }
+    }
+
+    static Task<string> count(int l, long mask, Func<Dictionary<long,Wrapper>,string> summary)
+    {
+        return Task.Run(() =>
+        {
+            long rollingKey = 0;
+            var firstBlock = threeBlocks[0];
+            var start = threeStart;
+            while(--l>0) rollingKey = (rollingKey<<2) | firstBlock[start++];
+            var dict = new Dictionary<long,Wrapper>();
+            for(int i=start; i<firstBlock.Length; i++)
+                check(dict, ref rollingKey, firstBlock[i], mask);
+
+            int lastBlockId = threeBlocks.Count-1; 
+            for(int bl=1; bl<lastBlockId; bl++)
+            {
+                var bytes = threeBlocks[bl];
+                for(int i=0; i<bytes.Length; i++)
+                    check(dict, ref rollingKey, bytes[i], mask);
+            }
+
+            var lastBlock = threeBlocks[lastBlockId];
+            for(int i=0; i<threeEnd; i++)
+                check(dict, ref rollingKey, lastBlock[i], mask);
+            return summary(dict);
+        });
+    }
+
+    static Dictionary<long,Wrapper> countEnding(int l, long mask, byte b)
+    {
+        long rollingKey = 0;
+        var firstBlock = threeBlocks[0];
+        var start = threeStart;
+        while(--l>0) rollingKey = (rollingKey<<2) | firstBlock[start++];
+        var dict = new Dictionary<long,Wrapper>();
+        for(int i=start; i<firstBlock.Length; i++)
+            checkEnding(dict, ref rollingKey, b, firstBlock[i], mask);
+
+        int lastBlockId = threeBlocks.Count-1; 
+        for(int bl=1; bl<lastBlockId; bl++)
+        {
+            var bytes = threeBlocks[bl];
+            for(int i=0; i<bytes.Length; i++)
+                checkEnding(dict, ref rollingKey, b, bytes[i], mask);
+        }
+
+        var lastBlock = threeBlocks[lastBlockId];
+        for(int i=0; i<threeEnd; i++)
+            checkEnding(dict, ref rollingKey, b, lastBlock[i], mask);
+        return dict;
+    }
+
+    static Task<string> count4(int l, long mask, Func<Dictionary<long,Wrapper>,string> summary)
+    {
+        return Task.Factory.ContinueWhenAll(
+            new [] {
+                Task.Run(() => countEnding(l, mask, 0)),
+                Task.Run(() => countEnding(l, mask, 1)),
+                Task.Run(() => countEnding(l, mask, 2)),
+                Task.Run(() => countEnding(l, mask, 3))
+            }
+            , dicts => {
+                var d = new Dictionary<long,Wrapper>(dicts.Sum(i => i.Result.Count));
+                for(int i=0; i<dicts.Length; i++)
+                    foreach(var kv in dicts[i].Result)
+                        d[(kv.Key << 2) | (long)i] = kv.Value;
+                return summary(d);
+            });
+    }
+
+    static string writeFrequencies(Dictionary<long,Wrapper> freq, int fragmentLength)
+    {
+        var sb = new StringBuilder();
+        double percent = 100.0 / freq.Values.Sum(i => i.v);
+        foreach(var kv in freq.OrderByDescending(i => i.Value.v))
+        {
+            var keyChars = new char[fragmentLength];
+            var key = kv.Key;
+            for (int i=keyChars.Length-1; i>=0; --i)
+            {
+                keyChars[i] = tochar[key & 0x3];
+                key >>= 2;
+            }
+            sb.Append(keyChars);   
+            sb.Append(" ");
+            sb.AppendLine((kv.Value.v * percent).ToString("F3"));
+        }
+        return sb.ToString();
+    }
+
+    static string writeCount(Dictionary<long,Wrapper> dictionary, string fragment)
+    {
+        long key = 0;
+        for (int i=0; i<fragment.Length; ++i)
+            key = (key << 2) | tonum[fragment[i]];
+        Wrapper w;
+        var n = dictionary.TryGetValue(key, out w) ? w.v : 0;
+        return string.Concat(n.ToString(), "\t", fragment);
+    }
+
+    public static void Main(string[] args)
+    {
+        tonum['c'] = 1; tonum['C'] = 1;
+        tonum['g'] = 2; tonum['G'] = 2;
+        tonum['t'] = 3; tonum['T'] = 3;
+        tonum['\n'] = 255; tonum['>'] = 255; tonum[255] = 255;
+
+        loadThreeData();
+
+        Parallel.ForEach(threeBlocks, bytes =>
+        {
+            for(int i=0; i<bytes.Length; i++)
+                bytes[i] = tonum[bytes[i]];
+        });
+
+        var task18 = count4(18, 34359738367, d => writeCount(d, "GGTATTTTAATTTATAGT"));
+        var task12 = count4(12, 8388607, d => writeCount(d, "GGTATTTTAATT"));
+        var task6 = count(6, 0b1111111111, d => writeCount(d, "GGTATT"));
+        var task4 = count(4, 0b111111, d => writeCount(d, "GGTA"));
+        var task3 = count(3, 0b1111, d => writeCount(d, "GGT"));
+        var task2 = count(2, 0b11, d => writeFrequencies(d, 2));
+        var task1 = count(1, 0, d => writeFrequencies(d, 1));
+
+        Console.Out.WriteLineAsync(task1.Result);
+        Console.Out.WriteLineAsync(task2.Result);
+        Console.Out.WriteLineAsync(task3.Result);
+        Console.Out.WriteLineAsync(task4.Result);
+        Console.Out.WriteLineAsync(task6.Result);
+        Console.Out.WriteLineAsync(task12.Result);
+        Console.Out.WriteLineAsync(task18.Result);
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/k-nucleotide-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/k-nucleotide/k-nucleotide-serial.cs
new file mode 100644 (file)
index 0000000..b5add5f
--- /dev/null
@@ -0,0 +1,165 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from k-nucleotide C# .NET Core program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=knucleotide&lang=csharpcore&id=1
+// Best-scoring single-threaded C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+ *
+ * byte processing version using C# *3.0 idioms by Robert F. Tobler
+ */
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Text;
+
+public struct ByteString : IEquatable<ByteString>
+{
+    public byte[] Array;
+    public int Start;
+    public int Length;
+
+    public ByteString(byte[] array, int start, int length)
+    {
+        Array = array; Start = start; Length = length;
+    }
+    
+    public ByteString(string text)
+    {
+        Start = 0; Length = text.Length;
+        Array = Encoding.ASCII.GetBytes(text);
+    }
+    
+    public override int GetHashCode()
+    {
+        if (Length < 1) return 0;
+        int hc = Length ^ (Array[Start] << 24); if (Length < 2) return hc;
+        hc ^= Array[Start+Length-1] << 20;      if (Length < 3) return hc;
+        for (int c = Length-2; c > 0; c--)
+            hc ^= Array[Start + c] << (c & 0xf);
+        return hc;
+    }
+
+    public bool Equals(ByteString other)
+    {
+        if (Length != other.Length) return false;
+        for (int i = 0; i < Length; i++)
+            if (Array[Start+i] != other.Array[other.Start+i]) return false;
+        return true;
+    }
+    
+    public override string ToString()
+    {
+        return Encoding.ASCII.GetString(Array, Start, Length);
+    }
+}
+
+public static class Extensions
+{
+    public static byte[] GetBytes(this List<string> input)
+    {
+        int count = 0;
+        for (int i = 0; i < input.Count; i++) count += input[i].Length;        
+        var byteArray = new byte[count];
+        count = 0;
+        for (int i = 0; i < input.Count; i++)
+        {
+            string line = input[i];
+            Encoding.ASCII.GetBytes(line, 0, line.Length, byteArray, count);
+            count += line.Length;
+        }
+        return byteArray;
+    }
+}
+
+public class program {
+
+
+    public static void Main(string[] args) {
+        string line;
+        StreamReader source = new StreamReader(Console.OpenStandardInput());
+        var input = new List<string>();
+    
+        while ( (line = source.ReadLine() ) != null )
+            if (line[0] == '>' && line.Substring(1, 5) == "THREE")
+                break;
+    
+        while ( (line = source.ReadLine()) != null ) {
+            char c = line[0];
+            if (c == '>') break;
+            if (c != ';') input.Add(line.ToUpper());
+        }
+    
+        KNucleotide kn = new KNucleotide(input.GetBytes());
+        input = null;
+        for (int f = 1; f < 3; f++) kn.WriteFrequencies(f);
+        foreach (var seq in
+                 new[] { "GGT", "GGTA", "GGTATT", "GGTATTTTAATT",
+                         "GGTATTTTAATTTATAGT"})
+            kn.WriteCount(seq);
+
+    }
+}
+
+public class KNucleotide {
+
+    private class Count {
+          public int V;
+          public Count(int v) { V = v; }
+    }
+
+    private Dictionary<ByteString, Count> frequencies
+        = new Dictionary<ByteString, Count>();
+    private byte[] sequence;
+
+    public KNucleotide(byte[] s) { sequence = s; }
+
+    public void WriteFrequencies(int length) {
+        GenerateFrequencies(length);
+        var items = new List<KeyValuePair<ByteString, Count>>(frequencies);
+        items.Sort(SortByFrequencyAndCode);    
+        double percent = 100.0 / (sequence.Length - length + 1);
+        foreach (var item in items)
+            Console.WriteLine("{0} {1:f3}",
+                        item.Key.ToString(), item.Value.V * percent);
+        Console.WriteLine();
+    }
+
+    public void WriteCount(string fragment) {
+        GenerateFrequencies(fragment.Length);
+        Count count;
+        if (!frequencies.TryGetValue(new ByteString(fragment), out count))
+            count = new Count(0);
+        Console.WriteLine("{0}\t{1}", count.V, fragment);
+    }
+
+    private void GenerateFrequencies(int length) {
+        frequencies.Clear();
+        for (int frame = 0; frame < length; frame++)
+            KFrequency(frame, length);
+    }
+
+    private void KFrequency(int frame, int k) {
+        int n = sequence.Length - k + 1;
+        for (int i = frame; i < n; i += k) {
+            var key = new ByteString(sequence, i, k);
+            Count count;
+            if (frequencies.TryGetValue(key, out count))
+                count.V++;
+            else
+                frequencies[key] = new Count(1);
+        }
+    }
+
+    int SortByFrequencyAndCode(
+            KeyValuePair<ByteString, Count> i0,
+            KeyValuePair<ByteString, Count> i1) {
+        int order = i1.Value.V.CompareTo(i0.Value.V);
+        if (order != 0) return order;
+        return i0.Key.ToString().CompareTo(i1.Key.ToString());
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-best.cs
new file mode 100644 (file)
index 0000000..9e6912a
--- /dev/null
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from mandelbrot C# .NET Core #4 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=mandelbrot&lang=csharpcore&id=4
+// Best-scoring C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+    
+   started with Java #2 program (Krause/Whipkey/Bennet/AhnTran/Enotus/Stalcup)
+   adapted for C# by Jan de Vaan
+   simplified and optimised to use TPL by Anthony Lloyd
+*/
+
+using System;
+using System.Threading.Tasks;
+using System.IO;
+using System.Runtime.CompilerServices;
+
+public class MandelBrot
+{
+     [MethodImpl(MethodImplOptions.AggressiveInlining)]
+     static byte getByte(double[] Crb, double Ciby, int x, int y)
+     {
+        int res=0;
+        for(int i=0;i<8;i+=2)
+        {
+            double Crbx=Crb[x+i], Crbx1=Crb[x+i+1]; 
+            double Zr1=Crbx, Zr2=Crbx1;
+            double Zi1=Ciby, Zi2=Ciby;
+
+            int b=0;
+            int j=49;
+            do
+            {
+                double nZr1=Zr1*Zr1-Zi1*Zi1+Crbx;
+                Zi1=Zr1*Zi1+Zr1*Zi1+Ciby;
+                Zr1=nZr1;
+
+                double nZr2=Zr2*Zr2-Zi2*Zi2+Crbx1;
+                Zi2=Zr2*Zi2+Zr2*Zi2+Ciby;
+                Zr2=nZr2;
+
+                if(Zr1*Zr1+Zi1*Zi1>4){b|=2;if(b==3)break;}
+                if(Zr2*Zr2+Zi2*Zi2>4){b|=1;if(b==3)break;}
+            } while(--j>0);
+            res=(res<<2)+b;
+        }
+        return (byte)(res^-1);
+    }
+
+    public static void Main (String[] args)
+    {
+        var n = args.Length > 0 ? Int32.Parse(args[0]) : 200;
+        double invN=2.0/n;
+        var Crb = new double[n+7];
+        for(int i=0;i<n;i++){ Crb[i]=i*invN-1.5; }
+        int lineLen = (n-1)/8 + 1;
+        var data = new byte[n*lineLen];
+        Parallel.For(0, n, y =>
+        {
+            var Ciby = y*invN-1.0;
+            var offset = y*lineLen;
+            for(int x=0; x<lineLen; x++)
+                data[offset+x] = getByte(Crb, Ciby, x*8, y);
+        });
+        Console.Out.WriteLine("P4\n{0} {0}", n);        
+        Console.OpenStandardOutput().Write(data, 0, data.Length);        
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-serial.cs
new file mode 100644 (file)
index 0000000..66748b3
--- /dev/null
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from mandelbrot C# .NET Core #2 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=mandelbrot&lang=csharpcore&id=2
+// Best-scoring single-threaded C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+ *
+ * Adapted by Antti Lankila from the earlier Isaac Gouy's implementation
+ */
+
+using System;
+using System.IO;
+
+class Mandelbrot {
+
+   public static void Main(String[] args) {
+
+      int width = 100;
+      if (args.Length > 0)
+        width = Int32.Parse(args[0]);
+
+      int height = width;
+      int maxiter = 50;
+      double limit = 4.0;
+
+      Console.WriteLine("P4");
+      Console.WriteLine("{0} {1}", width,height);
+      Stream s = Console.OpenStandardOutput(1024);
+
+      for (int y = 0; y < height; y++) {
+        int bits = 0;
+        int xcounter = 0;
+        double Ci = 2.0*y/height - 1.0;
+
+         for (int x = 0; x < width; x++){
+           double Zr = 0.0;
+           double Zi = 0.0;
+           double Cr = 2.0*x/width - 1.5;
+            int i = maxiter;
+
+            bits = bits << 1;
+            do {
+               double Tr = Zr*Zr - Zi*Zi + Cr;
+               Zi = 2.0*Zr*Zi + Ci;
+               Zr = Tr;
+               if (Zr*Zr + Zi*Zi > limit) {
+                 bits |= 1;
+                 break;
+              }
+            } while (--i > 0);
+
+            if (++xcounter == 8) {
+              s.WriteByte((byte) (bits ^ 0xff));
+              bits = 0;
+              xcounter = 0;
+            }
+         }
+         if (xcounter != 0)
+           s.WriteByte((byte) ((bits << (8 - xcounter)) ^ 0xff));
+      }
+   }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/n-body/n-body-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/n-body/n-body-best.cs
new file mode 100644 (file)
index 0000000..2d5ec96
--- /dev/null
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from n-body C# .NET Core #3 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=nbody&lang=csharpcore&id=3
+// Best-scoring C# .NET Core version as of 2017-09-01
+// (also best-scoring single-threaded C# .NET Core version as of 2017-09-01)
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+
+   contributed by Isaac Gouy, optimization and use of more C# idioms by Robert F. Tobler
+*/
+
+using System;
+
+class NBody {
+    public static void Main(String[] args) {
+        int n = args.Length > 0 ? Int32.Parse(args[0]) : 10000;
+        NBodySystem bodies = new NBodySystem();
+        Console.WriteLine("{0:f9}", bodies.Energy());
+        for (int i = 0; i < n; i++) bodies.Advance(0.01);
+        Console.WriteLine("{0:f9}", bodies.Energy());
+    }
+}
+
+class Body { public double x, y, z, vx, vy, vz, mass; }
+class Pair { public Body bi, bj; }
+
+class NBodySystem {
+    private Body[] bodies;
+    private Pair[] pairs;
+
+    const double Pi = 3.141592653589793;
+    const double Solarmass = 4 * Pi * Pi;
+    const double DaysPeryear = 365.24;
+
+    public NBodySystem() {
+        bodies = new Body[] {
+            new Body() { // Sun
+                mass = Solarmass,
+            },
+            new Body() { // Jupiter
+                x = 4.84143144246472090e+00,
+                y = -1.16032004402742839e+00,
+                z = -1.03622044471123109e-01,
+                vx = 1.66007664274403694e-03 * DaysPeryear,
+                vy = 7.69901118419740425e-03 * DaysPeryear,
+                vz = -6.90460016972063023e-05 * DaysPeryear,
+                mass = 9.54791938424326609e-04 * Solarmass,
+            },
+            new Body() { // Saturn
+                x = 8.34336671824457987e+00,
+                y = 4.12479856412430479e+00,
+                z = -4.03523417114321381e-01,
+                vx = -2.76742510726862411e-03 * DaysPeryear,
+                vy = 4.99852801234917238e-03 * DaysPeryear,
+                vz = 2.30417297573763929e-05 * DaysPeryear,
+                mass = 2.85885980666130812e-04 * Solarmass,
+            },
+            new Body() { // Uranus
+                x = 1.28943695621391310e+01,
+                y = -1.51111514016986312e+01,
+                z = -2.23307578892655734e-01,
+                vx = 2.96460137564761618e-03 * DaysPeryear,
+                vy = 2.37847173959480950e-03 * DaysPeryear,
+                vz = -2.96589568540237556e-05 * DaysPeryear,
+                mass = 4.36624404335156298e-05 * Solarmass,
+            },
+            new Body() { // Neptune
+                x = 1.53796971148509165e+01,
+                y = -2.59193146099879641e+01,
+                z = 1.79258772950371181e-01,
+                vx = 2.68067772490389322e-03 * DaysPeryear,
+                vy = 1.62824170038242295e-03 * DaysPeryear,
+                vz = -9.51592254519715870e-05 * DaysPeryear,
+                mass = 5.15138902046611451e-05 * Solarmass,
+            },
+        };
+        
+        pairs = new Pair[bodies.Length * (bodies.Length-1)/2];        
+        int pi = 0;
+        for (int i = 0; i < bodies.Length-1; i++)
+            for (int j = i+1; j < bodies.Length; j++)
+                pairs[pi++] = new Pair() { bi = bodies[i], bj = bodies[j] };        
+
+        double px = 0.0, py = 0.0, pz = 0.0;
+        foreach (var b in bodies) {
+            px += b.vx * b.mass; py += b.vy * b.mass; pz += b.vz * b.mass;
+        }
+        var sol = bodies[0];
+        sol.vx = -px/Solarmass; sol.vy = -py/Solarmass; sol.vz = -pz/Solarmass;
+    }
+
+    public void Advance(double dt) {
+        foreach (var p in pairs) {
+            Body bi = p.bi, bj = p.bj;
+            double dx = bi.x - bj.x, dy = bi.y - bj.y, dz = bi.z - bj.z;
+            double d2 = dx * dx + dy * dy + dz * dz;
+            double mag = dt / (d2 * Math.Sqrt(d2));
+            bi.vx -= dx * bj.mass * mag; bj.vx += dx * bi.mass * mag;
+            bi.vy -= dy * bj.mass * mag; bj.vy += dy * bi.mass * mag;
+            bi.vz -= dz * bj.mass * mag; bj.vz += dz * bi.mass * mag;
+        }
+        foreach (var b in bodies) {
+            b.x += dt * b.vx; b.y += dt * b.vy; b.z += dt * b.vz;
+        }
+    }
+
+    public double Energy() {
+        double e = 0.0;
+        for (int i = 0; i < bodies.Length; i++) {
+            var bi = bodies[i];
+            e += 0.5 * bi.mass * (bi.vx*bi.vx + bi.vy*bi.vy + bi.vz*bi.vz);
+            for (int j = i+1; j < bodies.Length; j++) {
+                var bj = bodies[j];
+                double dx = bi.x - bj.x, dy = bi.y - bj.y, dz = bi.z - bj.z;
+                e -= (bi.mass * bj.mass) / Math.Sqrt(dx*dx + dy*dy + dz*dz);
+            }
+        }
+        return e;
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/n-body/n-body-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/n-body/n-body-serial.cs
new file mode 100644 (file)
index 0000000..6d7970d
--- /dev/null
@@ -0,0 +1,2 @@
+// best is serial
+
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/pidigits/pidigits-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/pidigits/pidigits-best.cs
new file mode 100644 (file)
index 0000000..f9078e5
--- /dev/null
@@ -0,0 +1,172 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from pidigits C# .NET Core #3 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=pidigits&lang=csharpcore&id=3
+// Best-scoring C# .NET Core version as of 2017-09-01
+// (also best-scoring single-threaded C# .NET Core version as of 2017-09-01)
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+ *
+ * Port of the Java port that uses native GMP to use native GMP with C#
+ * contributed by Miguel de Icaza, based on the Java version, that was:
+ *     contributed by Mike Pall
+ *     java port by Stefan Krause
+*/
+using System;
+using System.Text;
+using System.Runtime.InteropServices;
+
+public class pidigits {
+
+   GmpInteger q = new GmpInteger(), r = new GmpInteger(), s = new GmpInteger(), t = new GmpInteger();
+   GmpInteger u = new GmpInteger(), v = new GmpInteger(), w = new GmpInteger();
+
+   int i;
+   StringBuilder strBuf = new StringBuilder (40);
+   int n;
+
+   pidigits (int n)
+   {
+      this.n=n;
+   }
+
+   private void compose_r(int bq, int br, int bs, int bt)
+   {
+     u.mul(r, bs);
+     r.mul(r, bq);
+     v.mul(t, br);
+     r.add(r, v);
+     t.mul(t, bt);
+     t.add(t, u);
+     s.mul(s, bt);
+     u.mul(q, bs);
+     s.add(s, u);
+     q.mul(q, bq);
+   }
+
+   /* Compose matrix with numbers on the left. */
+   private void compose_l(int bq, int br, int bs, int bt)
+   {
+     r.mul(r, bt);
+     u.mul(q, br);
+     r.add(r, u);
+     u.mul(t, bs);
+     t.mul(t, bt);
+     v.mul(s, br);
+     t.add(t, v);
+     s.mul(s, bq);
+     s.add(s, u);
+     q.mul(q, bq);
+   }
+
+   /* Extract one digit. */
+   private int extract(int j)
+   {
+     u.mul(q, j);
+     u.add(u, r);
+     v.mul(s, j);
+     v.add(v, t);
+     w.div(u, v);
+     return w.intValue();
+   }
+
+   /* Print one digit. Returns 1 for the last digit. */
+   private bool prdigit(int y)
+   {
+      strBuf.Append(y);
+      if (++i % 10 == 0 || i == n) {
+         if (i%10!=0) for (int j=10-(i%10);j>0;j--) { strBuf.Append(" "); }
+         strBuf.Append("\t:");
+         strBuf.Append(i);
+         Console.WriteLine(strBuf);
+         strBuf = new StringBuilder(40);
+      }
+      return i == n;
+   }
+
+   /* Generate successive digits of PI. */
+   void Run()
+   {
+     int k = 1;
+     i = 0;
+     q.set(1);
+     r.set(0);
+     s.set(0);
+     t.set(1);
+     for (;;) {
+       int y = extract(3);
+       if (y == extract(4)) {
+         if (prdigit(y)) return;
+         compose_r(10, -10*y, 0, 1);
+       } else {
+         compose_l(k, 4*k+2, 0, 2*k+1);
+         k++;
+       }
+     }
+   }
+
+   public static void Main(String[] args) {
+       pidigits m = new pidigits(Int32.Parse (args[0]));
+       m.Run();
+   }
+}
+
+[StructLayout (LayoutKind.Sequential)]
+struct mpz_t {
+    public int _mp_alloc;
+    public int _mp_size;
+    public IntPtr ptr;
+}
+
+class GmpInteger {
+
+   // Public methods
+
+   public GmpInteger() {
+      mpz_init(ref pointer);
+   }
+
+   public GmpInteger(int value) {
+      mpz_set_si(ref pointer, value);
+   }
+
+   public void set(int value) { mpz_set_si(ref pointer, value); }
+
+   public void mul(GmpInteger src, int val) { mpz_mul_si(ref pointer, ref src.pointer, val); }
+
+   public void add(GmpInteger op1, GmpInteger op2) { mpz_add(ref pointer, ref op1.pointer, ref op2.pointer); }
+
+   public void div(GmpInteger op1, GmpInteger op2) { mpz_tdiv_q(ref pointer, ref op1.pointer, ref op2.pointer); }
+
+   public int intValue() { return mpz_get_si(ref pointer); }
+
+   public double doubleValue() { return mpz_get_d(ref pointer); }
+
+   // Non public stuff
+
+   mpz_t pointer;
+
+    [DllImport ("gmp", EntryPoint="__gmpz_init")]
+    extern static void mpz_init(ref mpz_t value);
+
+    [DllImport ("gmp", EntryPoint="__gmpz_mul_si")]
+    extern static void mpz_mul_si(ref mpz_t dest, ref mpz_t src, int val);
+
+    [DllImport ("gmp", EntryPoint="__gmpz_add")]
+    extern static void mpz_add(ref mpz_t dest, ref mpz_t src, ref mpz_t src2);
+
+    [DllImport ("gmp", EntryPoint="__gmpz_tdiv_q")]
+    extern static void mpz_tdiv_q(ref mpz_t dest, ref mpz_t src, ref mpz_t src2);
+
+    [DllImport ("gmp", EntryPoint="__gmpz_set_si")]
+    extern static void mpz_set_si(ref mpz_t src, int value);
+
+    [DllImport ("gmp", EntryPoint="__gmpz_get_si")]
+    extern static int mpz_get_si(ref mpz_t src);
+
+    [DllImport ("gmp", EntryPoint="__gmpz_get_d")]
+    extern static double mpz_get_d(ref mpz_t src);
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/pidigits/pidigits-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/pidigits/pidigits-serial.cs
new file mode 100644 (file)
index 0000000..6d7970d
--- /dev/null
@@ -0,0 +1,2 @@
+// best is serial
+
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regex-redux/regex-redux-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regex-redux/regex-redux-best.cs
new file mode 100644 (file)
index 0000000..b945bc3
--- /dev/null
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from regex-redux C# .NET Core #5 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=regexredux&lang=csharpcore&id=5
+// Best-scoring C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+   Regex-Redux by Josh Goldfoot
+   order variants by execution time by Anthony Lloyd
+*/
+
+using System;
+using System.Threading.Tasks;
+using System.Text.RegularExpressions;
+
+public static class regexredux
+{
+    static Regex regex(string re)
+    {
+        // Not compiled on .Net Core, hence poor benchmark results.
+        return new Regex(re, RegexOptions.Compiled);
+    }
+
+    static string regexCount(string s, string r)
+    {
+        int c = 0;
+        var m = regex(r).Match(s);
+        while(m.Success) { c++; m = m.NextMatch(); }
+        return r + " " + c;
+    }
+
+    public static void Main(string[] args)
+    {
+        var sequences = Console.In.ReadToEnd();
+        var initialLength = sequences.Length;
+        sequences = Regex.Replace(sequences, ">.*\n|\n", "");
+        
+        var magicTask = Task.Run(() =>
+        {
+            var newseq = regex("tHa[Nt]").Replace(sequences, "<4>");
+            newseq = regex("aND|caN|Ha[DS]|WaS").Replace(newseq, "<3>");
+            newseq = regex("a[NSt]|BY").Replace(newseq, "<2>");
+            newseq = regex("<[^>]*>").Replace(newseq, "|");
+            newseq = regex("\\|[^|][^|]*\\|").Replace(newseq, "-");
+            return newseq.Length;
+        });
+
+        var variant2 = Task.Run(() => regexCount(sequences, "[cgt]gggtaaa|tttaccc[acg]"));
+        var variant3 = Task.Run(() => regexCount(sequences, "a[act]ggtaaa|tttacc[agt]t"));
+        var variant7 = Task.Run(() => regexCount(sequences, "agggt[cgt]aa|tt[acg]accct"));
+        var variant6 = Task.Run(() => regexCount(sequences, "aggg[acg]aaa|ttt[cgt]ccct"));
+        var variant4 = Task.Run(() => regexCount(sequences, "ag[act]gtaaa|tttac[agt]ct"));
+        var variant5 = Task.Run(() => regexCount(sequences, "agg[act]taaa|ttta[agt]cct"));
+        var variant1 = Task.Run(() => regexCount(sequences, "agggtaaa|tttaccct"));
+        var variant9 = Task.Run(() => regexCount(sequences, "agggtaa[cgt]|[acg]ttaccct"));
+        var variant8 = Task.Run(() => regexCount(sequences, "agggta[cgt]a|t[acg]taccct"));
+
+        Console.Out.WriteLineAsync(variant1.Result);
+        Console.Out.WriteLineAsync(variant2.Result);
+        Console.Out.WriteLineAsync(variant3.Result);
+        Console.Out.WriteLineAsync(variant4.Result);
+        Console.Out.WriteLineAsync(variant5.Result);
+        Console.Out.WriteLineAsync(variant6.Result);
+        Console.Out.WriteLineAsync(variant7.Result);
+        Console.Out.WriteLineAsync(variant8.Result);
+        Console.Out.WriteLineAsync(variant9.Result);
+        Console.Out.WriteLineAsync("\n"+initialLength+"\n"+sequences.Length);
+        Console.Out.WriteLineAsync(magicTask.Result.ToString());
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regex-redux/regex-redux-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regex-redux/regex-redux-serial.cs
new file mode 100644 (file)
index 0000000..12a44b8
--- /dev/null
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from regex-redux C# .NET Core program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=regexredux&lang=csharpcore&id=1
+// Best-scoring single-threaded C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+ * 
+ * regex-dna program contributed by Isaac Gouy 
+ * converted from regex-dna program
+ *
+*/
+
+using System;
+using System.Text.RegularExpressions;
+
+class regexredux
+{
+   static void Main(string[] args){
+                   
+      // read FASTA sequence
+      String sequence = Console.In.ReadToEnd();
+      int initialLength = sequence.Length;
+
+      // remove FASTA sequence descriptions and new-lines
+      Regex r = new Regex(">.*\n|\n", RegexOptions.Compiled);
+      sequence = r.Replace(sequence,"");
+      int codeLength = sequence.Length;
+
+
+      // regex match
+      string[] variants = {
+         "agggtaaa|tttaccct"
+         ,"[cgt]gggtaaa|tttaccc[acg]"
+         ,"a[act]ggtaaa|tttacc[agt]t"
+         ,"ag[act]gtaaa|tttac[agt]ct"
+         ,"agg[act]taaa|ttta[agt]cct"
+         ,"aggg[acg]aaa|ttt[cgt]ccct"
+         ,"agggt[cgt]aa|tt[acg]accct"
+         ,"agggta[cgt]a|t[acg]taccct"
+         ,"agggtaa[cgt]|[acg]ttaccct"
+      }; 
+
+      int count;
+      foreach (string v in variants){
+         count = 0;
+         r = new Regex(v, RegexOptions.Compiled);
+
+         for (Match m = r.Match(sequence); m.Success; m = m.NextMatch()) count++;
+         Console.WriteLine("{0} {1}", v, count);
+      }
+
+
+      // regex substitution
+      IUB[] codes = {
+          new IUB("tHa[Nt]", "<4>")
+         ,new IUB("aND|caN|Ha[DS]|WaS", "<3>")
+         ,new IUB("a[NSt]|BY", "<2>")
+         ,new IUB("<[^>]*>", "|")
+         ,new IUB("\\|[^|][^|]*\\|" , "-")
+      }; 
+
+      foreach (IUB iub in codes) {
+         r = new Regex(iub.code, RegexOptions.Compiled);
+         sequence = r.Replace(sequence,iub.alternatives);
+      }
+      Console.WriteLine("\n{0}\n{1}\n{2}", 
+         initialLength, codeLength, sequence.Length);
+   }
+
+
+   struct IUB 
+   {
+      public string code;
+      public string alternatives;
+
+      public IUB(string code, string alternatives) {
+         this.code = code;
+         this.alternatives = alternatives;
+      }
+   }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regexdna/regexdna-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/regexdna/regexdna-best.cs
new file mode 100644 (file)
index 0000000..d261a0d
--- /dev/null
@@ -0,0 +1 @@
+// no longer up on site
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-best.cs
new file mode 100644 (file)
index 0000000..8cd3568
--- /dev/null
@@ -0,0 +1,217 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from reverse-complement C# .NET Core #6
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=revcomp&lang=csharpcore&id=6
+// Best-scoring C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+
+   Contributed by Peperud
+   Modified to reduce memory use by Anthony Lloyd
+*/
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Threading;
+
+class RevCompSequence { public List<byte[]> Pages; public int StartHeader, EndExclusive; public Thread ReverseThread; }
+
+public static class revcomp
+{
+    const int READER_BUFFER_SIZE = 1024 * 1024;
+    const byte LF = 10, GT = (byte)'>', SP = 32;
+    static BlockingCollection<byte[]> readQue = new BlockingCollection<byte[]>();
+    static BlockingCollection<RevCompSequence> writeQue = new BlockingCollection<RevCompSequence>();
+    static byte[] map;
+    
+    static int read(Stream stream, byte[] buffer, int offset, int count)
+    {
+        var bytesRead = stream.Read(buffer, offset, count);
+        return bytesRead==count ? offset+count
+             : bytesRead==0 ? offset
+             : read(stream, buffer, offset+bytesRead, count-bytesRead);
+    }
+    static void Reader()
+    {
+        using (var stream = Console.OpenStandardInput())
+        {
+            int bytesRead;
+            do
+            {
+                var buffer = new byte[READER_BUFFER_SIZE];
+                bytesRead = read(stream, buffer, 0, READER_BUFFER_SIZE);
+                readQue.Add(buffer);
+            } while(bytesRead==READER_BUFFER_SIZE);
+            readQue.CompleteAdding();
+        }
+    }
+
+    static bool tryTake<T>(BlockingCollection<T> q, out T t) where T : class
+    {
+        t = null;
+        while(!q.IsCompleted && !q.TryTake(out t)) Thread.SpinWait(0);
+        return t!=null;
+    }
+
+    static void Grouper()
+    {
+        // Set up complements map
+        map = new byte[256];
+        for (byte b=0; b<255; b++) map[b]=b;
+        map[(byte)'A'] = (byte)'T';
+        map[(byte)'B'] = (byte)'V';
+        map[(byte)'C'] = (byte)'G';
+        map[(byte)'D'] = (byte)'H';
+        map[(byte)'G'] = (byte)'C';
+        map[(byte)'H'] = (byte)'D';
+        map[(byte)'K'] = (byte)'M';
+        map[(byte)'M'] = (byte)'K';
+        map[(byte)'R'] = (byte)'Y';
+        map[(byte)'T'] = (byte)'A';
+        map[(byte)'V'] = (byte)'B';
+        map[(byte)'Y'] = (byte)'R';
+        map[(byte)'a'] = (byte)'T';
+        map[(byte)'b'] = (byte)'V';
+        map[(byte)'c'] = (byte)'G';
+        map[(byte)'d'] = (byte)'H';
+        map[(byte)'g'] = (byte)'C';
+        map[(byte)'h'] = (byte)'D';
+        map[(byte)'k'] = (byte)'M';
+        map[(byte)'m'] = (byte)'K';
+        map[(byte)'r'] = (byte)'Y';
+        map[(byte)'t'] = (byte)'A';
+        map[(byte)'v'] = (byte)'B';
+        map[(byte)'y'] = (byte)'R';
+
+        var startHeader = 0;
+        var i = 0;
+        bool afterFirst = false;
+        var data = new List<byte[]>();
+        byte[] bytes;
+        while (tryTake(readQue, out bytes))
+        {
+            data.Add(bytes);
+            while((i=Array.IndexOf<byte>(bytes, GT, i+1))!=-1)
+            {
+                var sequence = new RevCompSequence { Pages = data
+                    , StartHeader = startHeader, EndExclusive = i };
+                if(afterFirst)
+                    (sequence.ReverseThread = new Thread(() => Reverse(sequence))).Start();
+                else
+                    afterFirst = true;
+                writeQue.Add(sequence);
+                startHeader = i;
+                data = new List<byte[]> { bytes };
+            }
+        }
+        i = Array.IndexOf<byte>(data[data.Count-1],0,0);
+        var lastSequence = new RevCompSequence { Pages = data
+            , StartHeader = startHeader, EndExclusive = i==-1 ? data[data.Count-1].Length : i };
+        Reverse(lastSequence);
+        writeQue.Add(lastSequence);
+        writeQue.CompleteAdding();
+    }
+
+    static void Reverse(RevCompSequence sequence)
+    {
+        var startPageId = 0;
+        var startBytes = sequence.Pages[0];
+        var startIndex = sequence.StartHeader;
+
+        // Skip header line
+        while((startIndex=Array.IndexOf<byte>(startBytes, LF, startIndex))==-1)
+        {
+            startBytes = sequence.Pages[++startPageId];
+            startIndex = 0;
+        }
+
+        var endPageId = sequence.Pages.Count - 1;
+        var endIndex = sequence.EndExclusive - 1;
+        if(endIndex==-1) endIndex = sequence.Pages[--endPageId].Length-1;
+        var endBytes = sequence.Pages[endPageId];
+        
+        // Swap in place across pages
+        do
+        {
+            var startByte = startBytes[startIndex];
+            if(startByte<SP)
+            {
+                if (++startIndex == startBytes.Length)
+                {
+                    startBytes = sequence.Pages[++startPageId];
+                    startIndex = 0;
+                }
+                if (startIndex == endIndex && startPageId == endPageId) break;
+                startByte = startBytes[startIndex];
+            }
+            var endByte = endBytes[endIndex];
+            if(endByte<SP)
+            {
+                if (--endIndex == -1)
+                {
+                    endBytes = sequence.Pages[--endPageId];
+                    endIndex = endBytes.Length - 1;
+                }
+                if (startIndex == endIndex && startPageId == endPageId) break;
+                endByte = endBytes[endIndex];
+            }
+
+            startBytes[startIndex] = map[endByte];
+            endBytes[endIndex] = map[startByte];
+
+            if (++startIndex == startBytes.Length)
+            {
+                startBytes = sequence.Pages[++startPageId];
+                startIndex = 0;
+            }
+            if (--endIndex == -1)
+            {
+                endBytes = sequence.Pages[--endPageId];
+                endIndex = endBytes.Length - 1;
+            }
+        } while (startPageId < endPageId || (startPageId == endPageId && startIndex < endIndex));
+        if (startIndex == endIndex) startBytes[startIndex] = map[startBytes[startIndex]];
+    }
+
+    static void Writer()
+    {
+        using (var stream = Console.OpenStandardOutput())
+        {
+            bool first = true;
+            RevCompSequence sequence;
+            while (tryTake(writeQue, out sequence))
+            {
+                var startIndex = sequence.StartHeader;
+                var pages = sequence.Pages;
+                if(first)
+                {
+                    Reverse(sequence);
+                    first = false;
+                }
+                else
+                {
+                    sequence.ReverseThread?.Join();
+                }
+                for (int i = 0; i < pages.Count - 1; i++)
+                {
+                    var bytes = pages[i];
+                    stream.Write(bytes, startIndex, bytes.Length - startIndex);
+                    startIndex = 0;
+                }
+                stream.Write(pages[pages.Count-1], startIndex, sequence.EndExclusive - startIndex);
+            }
+        }
+    }
+
+    public static void Main(string[] args)
+    {
+        new Thread(Reader).Start();
+        new Thread(Grouper).Start();
+        Writer();
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-serial.cs
new file mode 100644 (file)
index 0000000..5838e2f
--- /dev/null
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from reverse-complement C# .NET Core program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=revcomp&lang=csharpcore&id=1
+// Best-scoring single-threaded C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+
+   contributed by Robert F. Tobler to process large blocks of byte arrays
+*/
+
+using System;
+using System.IO;
+using System.Collections.Generic;
+
+static class revcomp
+{
+   struct Block {
+      public byte[] Data; public int Count;
+      public int Read(BinaryReader r) {
+         Data = r.ReadBytes(16384); Count++; return Data.Length;
+      }
+      public Index IndexOf(byte b, int o) {
+         return new Index { Block = Count, Pos = Array.IndexOf(Data, b, o) };
+      }
+   }
+
+   struct Index {
+      public int Block; public int Pos;
+      public static readonly Index None = new Index { Block = -1, Pos = -1 };
+      public bool InBlock(Block b) { return Block == b.Count; }
+   }
+
+   const byte Gt = (byte)'>';
+   const byte Lf = (byte)'\n';
+
+   static void Main(string[] args) {
+      InitComplements();
+      var seq = new List<byte[]>();
+      var b = new Block { Count = -1 };
+      Index line = Index.None, start = Index.None, end = Index.None;
+      using (var r = new BinaryReader(Console.OpenStandardInput())) {
+         using (var w = Console.OpenStandardOutput()) {
+            while (b.Read(r) > 0) {
+               seq.Add(b.Data);
+               if (line.Pos < 0) line = b.IndexOf(Gt, 0);
+               while (line.Pos >= 0) {
+                  if (start.Pos < 0) {
+                     var off = line.InBlock(b) ? line.Pos : 0;
+                     start = b.IndexOf(Lf, off);
+                     if (start.Pos < 0) {
+                         w.Write(b.Data, off, b.Data.Length - off);
+                         seq.Clear(); break;
+                     }
+                     w.Write(b.Data, off, start.Pos + 1 - off);
+                  }
+                  if (end.Pos < 0) {
+                     end = b.IndexOf(Gt, start.InBlock(b) ? start.Pos : 0);
+                     if (end.Pos < 0) break;
+                  }
+                  w.Reverse(start.Pos, end.Pos, seq);
+                  if (seq.Count > 1) seq.RemoveRange(0, seq.Count - 1);
+                  line = end; end = Index.None; start = Index.None;
+               }
+            }
+            if (start.Pos >= 0 && end.Pos < 0)
+               w.Reverse(start.Pos, seq[seq.Count -1].Length, seq);
+         }
+      }
+   }
+
+   const string Seq = "ABCDGHKMRTVYabcdghkmrtvy";
+   const string Rev = "TVGHCDMKYABRTVGHCDMKYABR";
+   static byte[] comp = new byte[256];
+
+   static void InitComplements() {
+      for (byte i = 0; i < 255; i++) comp[i] = i;
+      for (int i = 0; i < Seq.Length; i++)
+         comp[(byte)Seq[i]] = (byte)Rev[i];
+      comp[Lf] = 0;  comp[(byte)' '] = 0;
+   }
+
+   const int LineLen = 61;
+   const int BufSize = LineLen * 269;
+   static byte[] buf = new byte[BufSize];
+
+   static void Reverse(this Stream w, int si, int ei, List<byte[]> bl) {
+      int bi = 0, line = LineLen - 1;
+      for (int ri = bl.Count-1; ri >= 0; ri--) {
+         var b = bl[ri]; int off = ri == 0 ? si : 0;
+         for (int i = (ri == bl.Count-1 ? ei : b.Length)-1; i >= off; i--) {
+            var c = comp[b[i]]; if (c > 0) buf[bi++] = c;
+            if (bi == line) {
+               buf[bi++] = Lf; line += LineLen;
+               if (bi == BufSize) {
+                  w.Write(buf, 0, BufSize); bi = 0; line = LineLen - 1;
+               }
+            }
+         }
+      }
+      if (bi > 0) {
+          if (buf[bi-1] != Lf) buf[bi++] = Lf; w.Write(buf, 0, bi);
+      }
+   }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/spectralnorm/spectralnorm-best.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/spectralnorm/spectralnorm-best.cs
new file mode 100644 (file)
index 0000000..c82f002
--- /dev/null
@@ -0,0 +1,153 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from spectral-norm C# .NET Core #3 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=spectralnorm&lang=csharpcore&id=3
+// Best-scoring C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+   contributed by Isaac Gouy 
+   modified by Josh Goldfoot, based on the Java version by The Anh Tran
+*/
+
+using System;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SpectralNorms
+{
+    class SpectralNorm
+    {
+        public static void Main(String[] args)
+        {
+            int n = 100;
+            if (args.Length > 0) n = Int32.Parse(args[0]); 
+
+            Console.WriteLine("{0:f9}", spectralnormGame(n));
+        }
+
+        private static double spectralnormGame(int n)
+        {
+            double[] u = new double[n];
+            double[] v = new double[n];
+            double[] tmp = new double[n];
+
+            // create unit vector
+            for (int i = 0; i < n; i++)
+                u[i] = 1.0;
+
+            int nthread = Environment.ProcessorCount;
+            int chunk = n / nthread;
+            var barrier = new Barrier(nthread);
+            Approximate[] ap = new Approximate[nthread];
+
+            for (int i = 0; i < nthread; i++)
+            {
+                int r1 = i * chunk;
+                int r2 = (i < (nthread - 1)) ? r1 + chunk : n;
+                ap[i] = new Approximate(u, v, tmp, r1, r2, barrier);
+            }
+
+            double vBv = 0, vv = 0;
+            for (int i = 0; i < nthread; i++)
+            {
+                ap[i].t.Wait();
+                vBv += ap[i].m_vBv;
+                vv += ap[i].m_vv;
+            }
+
+            return Math.Sqrt(vBv / vv);
+        }
+
+    }
+
+    public class Approximate
+    {
+        private Barrier barrier;
+        public Task t;
+
+        private double[] _u;
+        private double[] _v;
+        private double[] _tmp;
+
+        private int range_begin, range_end;
+        public double m_vBv, m_vv;
+
+        public Approximate(double[] u, double[] v, double[] tmp, int rbegin, int rend, Barrier b)
+        {
+            m_vBv = 0;
+            m_vv = 0;
+            _u = u;
+            _v = v;
+            _tmp = tmp;
+            range_begin = rbegin;
+            range_end = rend;
+            barrier = b;
+            t = Task.Run(() => run());
+        }
+
+        private void run()
+        {
+            // 20 steps of the power method
+            for (int i = 0; i < 10; i++)
+            {
+                MultiplyAtAv(_u, _tmp, _v);
+                MultiplyAtAv(_v, _tmp, _u);
+            }
+
+            for (int i = range_begin; i < range_end; i++)
+            {
+                m_vBv += _u[i] * _v[i];
+                m_vv += _v[i] * _v[i];
+            }
+        }
+
+        /* return element i,j of infinite matrix A */
+        private double eval_A(int i, int j)
+        {
+            return 1.0 / ((i + j) * (i + j + 1) / 2 + i + 1);
+        }
+
+        /* multiply vector v by matrix A, each thread evaluate its range only */
+        private void MultiplyAv(double[] v, double[] Av)
+        {
+            for (int i = range_begin; i < range_end; i++)
+            {
+                double sum = 0;
+                for (int j = 0; j < v.Length; j++)
+                    sum += eval_A(i, j) * v[j];
+
+                Av[i] = sum;
+            }
+        }
+
+        /* multiply vector v by matrix A transposed */
+        private void MultiplyAtv(double[] v, double[] Atv)
+        {
+            for (int i = range_begin; i < range_end; i++)
+            {
+                double sum = 0;
+                for (int j = 0; j < v.Length; j++)
+                    sum += eval_A(j, i) * v[j];
+
+                Atv[i] = sum;
+            }
+        }
+
+        /* multiply vector v by matrix A and then by matrix A transposed */
+        private void MultiplyAtAv(double[] v, double[] tmp, double[] AtAv)
+        {
+
+            MultiplyAv(v, tmp);
+            // all thread must syn at completion
+            barrier.SignalAndWait();
+            MultiplyAtv(tmp, AtAv);
+            // all thread must syn at completion
+            barrier.SignalAndWait();
+        }
+
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/spectralnorm/spectralnorm-serial.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/spectralnorm/spectralnorm-serial.cs
new file mode 100644 (file)
index 0000000..4ea2585
--- /dev/null
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Adapted from spectral-norm C# .NET Core program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=spectralnorm&lang=csharpcore&id=1
+// Best-scoring single-threaded C# .NET Core version as of 2017-09-01
+
+/* The Computer Language Benchmarks Game
+   http://benchmarksgame.alioth.debian.org/
+   contributed by Isaac Gouy 
+*/
+
+using System;
+
+class SpectralNorm
+{
+   public static void Main(String[] args) {        
+      int n = 100;
+      if (args.Length > 0) n = Int32.Parse(args[0]);
+
+      Console.WriteLine("{0:f9}", new SpectralNorm().Approximate(n));
+   }
+
+   double Approximate(int n) {
+      // create unit vector
+      double[] u = new double[n];       
+      for (int i=0; i<n; i++) u[i] =  1;
+
+      // 20 steps of the power method
+      double[] v = new double[n];  
+      for (int i=0; i<n; i++) v[i] = 0;
+
+      for (int i=0; i<10; i++) {
+         MultiplyAtAv(n,u,v);
+         MultiplyAtAv(n,v,u);
+      }
+
+      // B=AtA         A multiplied by A transposed
+      // v.Bv /(v.v)   eigenvalue of v 
+      double vBv = 0, vv = 0;
+      for (int i=0; i<n; i++) {
+         vBv += u[i]*v[i];
+         vv  += v[i]*v[i];
+      }
+
+      return Math.Sqrt(vBv/vv);
+   }
+
+
+   /* return element i,j of infinite matrix A */
+   double A(int i, int j){
+      return 1.0/((i+j)*(i+j+1)/2 +i+1); 
+   }
+
+   /* multiply vector v by matrix A */
+   void MultiplyAv(int n, double[] v, double[] Av){
+      for (int i=0; i<n; i++){
+         Av[i] = 0;
+         for (int j=0; j<n; j++) Av[i] += A(i,j)*v[j];
+      }
+   }
+
+   /* multiply vector v by matrix A transposed */
+   void MultiplyAtv(int n, double[] v, double[] Atv){
+      for (int i=0;i<n;i++){
+         Atv[i] = 0;
+         for (int j=0; j<n; j++) Atv[i] += A(j,i)*v[j];
+      }
+   }
+
+   /* multiply vector v by matrix A and then by matrix A transposed */
+   void MultiplyAtAv(int n, double[] v, double[] AtAv){
+      double[] u = new double[n];
+      MultiplyAv(n,v,u);
+      MultiplyAtv(n,u,AtAv);
+   }
+}