summaryrefslogtreecommitdiff
path: root/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-best.cs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-best.cs')
-rw-r--r--tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-best.cs217
1 files changed, 217 insertions, 0 deletions
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
index 0000000000..8cd35688ac
--- /dev/null
+++ b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/reverse-complement/reverse-complement-best.cs
@@ -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();
+ }
+}