Skip to content

Instantly share code, notes, and snippets.

@meritozh
Forked from sumtec/CorrectnessTester.cs
Last active August 29, 2015 14:21
Show Gist options
  • Save meritozh/b7a593dac2f05d20df49 to your computer and use it in GitHub Desktop.
Save meritozh/b7a593dac2f05d20df49 to your computer and use it in GitHub Desktop.
using System;
using System.Globalization;
using System.IO;
namespace TestStringFormatPerformance
{
public class CorrectnessTester<T> where T : ITextWriterUtils, new()
{
public void Test()
{
Test(0);
Test(int.MinValue);
Test(int.MaxValue);
Test("1234567890", 1);
Test("-1234567890", 2);
}
private void Test(string test, int startFrom)
{
for (var i = startFrom; i < test.Length; i++)
{
Test(int.Parse(test.Substring(0, i)));
}
}
public void Test(int number)
{
var correctString = number.ToString(CultureInfo.InvariantCulture);
var writer = new StringWriter();
var writerAdapter = new TextWriterAdapter(writer);
var util = new T();
util.Write(writerAdapter, number);
var utilString = writer.ToString();
var correct = correctString == utilString;
Console.WriteLine(
"[" + typeof(T).Name + "] " + correctString + " is " +
(correct
? "correct"
: ("in correct (" + utilString + ")")
)
);
}
}
}
using System;
using System.Globalization;
using System.IO;
using System.Linq;
namespace TestStringFormatPerformance
{
public class ExtremeTextWriterUtils : ITextWriterUtils
{
private static readonly string[] _zeroPaddingStrings;
private static readonly string[] _nonZeroPaddingStrings;
private static readonly string _minString;
static ExtremeTextWriterUtils()
{
_zeroPaddingStrings = Enumerable.Range(0, 10000).Select(i => i.ToString("0000", CultureInfo.InvariantCulture)).ToArray();
_nonZeroPaddingStrings = Enumerable.Range(0, 10000).Select(i => i.ToString(CultureInfo.InvariantCulture)).ToArray();
_minString = int.MinValue.ToString(CultureInfo.InvariantCulture);
}
[ThreadStatic]
private static char[] _buffer;
private static char[] GetBuffer()
{
if (_buffer == null)
{
_buffer = new char[11];
_buffer[0] = '-';
}
return _buffer;
}
private static void WriteCore(ITextWriter writer, int start, int value)
{
var buffer = GetBuffer();
var high = value / 100000000;
int offset;
if (high > 0)
{
offset = CopyToBuffer(buffer, 1, _nonZeroPaddingStrings[high]);
value -= high * 100000000;
high = value / 10000;
offset = CopyToBuffer(buffer, offset, _zeroPaddingStrings[high]);
value -= high * 10000;
offset = CopyToBuffer(buffer, offset, _zeroPaddingStrings[value]);
}
else
{
high = value / 10000;
if (high > 0)
{
offset = CopyToBuffer(buffer, 1, _nonZeroPaddingStrings[high]);
value -= high * 10000;
offset = CopyToBuffer(buffer, offset, _zeroPaddingStrings[value]);
}
else
{
offset = CopyToBuffer(buffer, 1, _nonZeroPaddingStrings[value]);
}
}
writer.Write(buffer, start, offset - start);
}
private static int CopyToBuffer(char[] buffer, int offset, string s)
{
for (int i = 0; i < s.Length; i++)
{
buffer[offset++] = s[i];
}
return offset;
}
public void Write(ITextWriter writer, int value)
{
if (value == int.MinValue) { writer.Write(_minString); return; }
if (value < 0) { WriteCore(writer, 0, -value); return; }
if (value <= 9999)
{
writer.Write(_nonZeroPaddingStrings[value]);
return;
}
WriteCore(writer, 1, value);
}
}
}
using System;
namespace TestStringFormatPerformance
{
public class HentaiTextWriterUtils : ITextWriterUtils
{
private readonly static char[] Map = new[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
public void Write(ITextWriter writer, int value)
{
var i = value;
var result = new char[11];
var p = 10;
var neg = value < 0;
do
{
var q = 0;
i = Math.DivRem(i, 10, out q);
result[p--] = neg ? Map[-q] : Map[q];
} while (i != 0);
if (neg)
result[p--] = '-';
writer.Write(result, p + 1, 10 - p);
}
}
}
namespace TestStringFormatPerformance
{
public interface ITextWriter
{
void Write(string text);
void Write(string text, int startIndex, int count);
void Write(char[] chars);
void Write(char[] chars, int startIndex, int count);
}
}
namespace TestStringFormatPerformance
{
public interface ITextWriterUtils
{
void Write(ITextWriter writer, int value);
}
}
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestStringFormatPerformance
{
public class MTRSBTester<T> : MultiThreadRandomPerformanceTester<T> where T : ITextWriterUtils, new()
{
public MTRSBTester(RandomSet randomSet) : base(randomSet) { }
private const int MAX_ROUND = 1000000;
private ConcurrentBag<StringBuilder> _stringBuilders = new ConcurrentBag<StringBuilder>();
public override void Test(int round)
{
GC.Collect(2, GCCollectionMode.Forced);
GC.WaitForFullGCComplete();
for (int i = 0; i < Environment.ProcessorCount; i++)
{
_stringBuilders.Add(new StringBuilder(800000));
}
base.Test(round);
GC.Collect(2, GCCollectionMode.Forced);
GC.WaitForFullGCComplete();
}
protected override string ExtraInfo
{
get
{
return ", sb, " + _randomSet.Name;
}
}
protected override void TestCore()
{
StringBuilder stringBuilder;
_stringBuilders.TryTake(out stringBuilder);
var writer = new TextWriterAdapter(new StringWriter(stringBuilder));
var util = new T();
int end = _round / _threads.Length;
for (int i = 0; i < end;)
{
util.Write(writer, _randomSet.Get(i));
i++;
if ((i & 0xFFFF) == 0) stringBuilder.Length = 0;
}
}
}
}
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
namespace TestStringFormatPerformance
{
public class MultiThreadPerformanceTester<T> where T : ITextWriterUtils, new()
{
private const int _testValue = -1234567890;
protected Thread[] _threads = new Thread[Environment.ProcessorCount];
protected int _round;
protected virtual string ExtraInfo { get { return null; } }
public virtual void Test(int round)
{
_round = round;
for (int i = 0; i < _threads.Length; i++)
{
_threads[i] = new Thread(TestCore);
}
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < _threads.Length; i++)
{
_threads[i].Start();
}
for (int i = 0; i < _threads.Length; i++)
{
_threads[i].Join();
}
watch.Stop();
Console.WriteLine((round / watch.Elapsed.TotalSeconds) + " op/s [" + typeof(T).Name + "] Multi thread" + ExtraInfo);
}
protected virtual void TestCore()
{
var writer = new TextWriterAdapter(TextWriter.Null);
var util = new T();
int end = _round / _threads.Length;
for (int i = 0; i < end; i++)
{
util.Write(writer, _testValue);
}
}
}
}
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
namespace TestStringFormatPerformance
{
public class MultiThreadRandomPerformanceTester<T> : MultiThreadPerformanceTester<T> where T : ITextWriterUtils, new()
{
public MultiThreadRandomPerformanceTester(RandomSet randomSet)
{
_randomSet = randomSet;
}
protected readonly RandomSet _randomSet;
protected override void TestCore()
{
var writer = new TextWriterAdapter(TextWriter.Null);
var util = new T();
int end = _round / _threads.Length;
for (int i = 0; i < end ; i++)
{
util.Write(writer, _randomSet.Get(i));
}
}
protected override string ExtraInfo
{
get
{
return ", " + _randomSet.Name ;
}
}
}
}
using System;
namespace TestStringFormatPerformance
{
class Program
{
static void Main(string[] args)
{
new CorrectnessTester<SampletTextWriterUtils>().Test();
new CorrectnessTester<ThreadStaticTextWriterUtils>().Test();
new CorrectnessTester<HentaiTextWriterUtils>().Test();
new CorrectnessTester<ExtremeTextWriterUtils>().Test();
int round = 10000000;
new SingleThreadPerformanceTester<SampletTextWriterUtils>().Test(round);
new SingleThreadPerformanceTester<ThreadStaticTextWriterUtils>().Test(round);
new SingleThreadPerformanceTester<HentaiTextWriterUtils>().Test(round);
new SingleThreadPerformanceTester<ExtremeTextWriterUtils>().Test(round);
Console.WriteLine("-------\n");
new MultiThreadPerformanceTester<SampletTextWriterUtils>().Test(round);
new MultiThreadPerformanceTester<ThreadStaticTextWriterUtils>().Test(round);
new MultiThreadPerformanceTester<HentaiTextWriterUtils>().Test(round);
new MultiThreadPerformanceTester<ExtremeTextWriterUtils>().Test(round);
Console.WriteLine("-------\n");
Test(round, RandomSet.SmallNumbers);
Test(round, RandomSet.LargeNumbers);
Console.WriteLine("DONE!");
Console.ReadKey();
}
private static void Test(int round, RandomSet randomSet)
{
new SingleThreadRandomPerformanceTester<SampletTextWriterUtils>().Test(round, randomSet);
new SingleThreadRandomPerformanceTester<ThreadStaticTextWriterUtils>().Test(round, randomSet);
new SingleThreadRandomPerformanceTester<HentaiTextWriterUtils>().Test(round, randomSet);
new SingleThreadRandomPerformanceTester<ExtremeTextWriterUtils>().Test(round, randomSet);
Console.WriteLine("-------\n");
new MultiThreadRandomPerformanceTester<SampletTextWriterUtils>(randomSet).Test(round);
new MultiThreadRandomPerformanceTester<ThreadStaticTextWriterUtils>(randomSet).Test(round);
new MultiThreadRandomPerformanceTester<HentaiTextWriterUtils>(randomSet).Test(round);
new MultiThreadRandomPerformanceTester<ExtremeTextWriterUtils>(randomSet).Test(round);
Console.WriteLine("-------\n");
new MTRSBTester<SampletTextWriterUtils>(randomSet).Test(round);
new MTRSBTester<ThreadStaticTextWriterUtils>(randomSet).Test(round);
new MTRSBTester<HentaiTextWriterUtils>(randomSet).Test(round);
new MTRSBTester<ExtremeTextWriterUtils>(randomSet).Test(round);
Console.WriteLine("-------\n");
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestStringFormatPerformance
{
public class RandomSet
{
static RandomSet()
{
LargeNumbers = new RandomSet(int.MinValue, int.MaxValue, "largeRnd");
SmallNumbers = new RandomSet(-200000, 200000, "smallRnd");
}
public RandomSet(int min, int max, string name)
{
Name = name;
var rnd = new Random();
_numbers = Enumerable.Repeat(0, 2<<20).Select(i => rnd.Next(min, max)).ToArray();
}
private readonly int[] _numbers;
public int Get(int i)
{
return _numbers[i & 0xFFFFF];
}
public static RandomSet LargeNumbers{get;private set;}
public static RandomSet SmallNumbers { get; private set; }
public string Name { get; private set; }
}
}
[SampletTextWriterUtils] 0 is correct
[SampletTextWriterUtils] -2147483648 is correct
[SampletTextWriterUtils] 2147483647 is correct
[SampletTextWriterUtils] 1 is correct
[SampletTextWriterUtils] 12 is correct
[SampletTextWriterUtils] 123 is correct
[SampletTextWriterUtils] 1234 is correct
[SampletTextWriterUtils] 12345 is correct
[SampletTextWriterUtils] 123456 is correct
[SampletTextWriterUtils] 1234567 is correct
[SampletTextWriterUtils] 12345678 is correct
[SampletTextWriterUtils] 123456789 is correct
[SampletTextWriterUtils] -1 is correct
[SampletTextWriterUtils] -12 is correct
[SampletTextWriterUtils] -123 is correct
[SampletTextWriterUtils] -1234 is correct
[SampletTextWriterUtils] -12345 is correct
[SampletTextWriterUtils] -123456 is correct
[SampletTextWriterUtils] -1234567 is correct
[SampletTextWriterUtils] -12345678 is correct
[SampletTextWriterUtils] -123456789 is correct
[ThreadStaticTextWriterUtils] 0 is correct
[ThreadStaticTextWriterUtils] -2147483648 is correct
[ThreadStaticTextWriterUtils] 2147483647 is correct
[ThreadStaticTextWriterUtils] 1 is correct
[ThreadStaticTextWriterUtils] 12 is correct
[ThreadStaticTextWriterUtils] 123 is correct
[ThreadStaticTextWriterUtils] 1234 is correct
[ThreadStaticTextWriterUtils] 12345 is correct
[ThreadStaticTextWriterUtils] 123456 is correct
[ThreadStaticTextWriterUtils] 1234567 is correct
[ThreadStaticTextWriterUtils] 12345678 is correct
[ThreadStaticTextWriterUtils] 123456789 is correct
[ThreadStaticTextWriterUtils] -1 is correct
[ThreadStaticTextWriterUtils] -12 is correct
[ThreadStaticTextWriterUtils] -123 is correct
[ThreadStaticTextWriterUtils] -1234 is correct
[ThreadStaticTextWriterUtils] -12345 is correct
[ThreadStaticTextWriterUtils] -123456 is correct
[ThreadStaticTextWriterUtils] -1234567 is correct
[ThreadStaticTextWriterUtils] -12345678 is correct
[ThreadStaticTextWriterUtils] -123456789 is correct
[HentaiTextWriterUtils] 0 is correct
[HentaiTextWriterUtils] -2147483648 is correct
[HentaiTextWriterUtils] 2147483647 is correct
[HentaiTextWriterUtils] 1 is correct
[HentaiTextWriterUtils] 12 is correct
[HentaiTextWriterUtils] 123 is correct
[HentaiTextWriterUtils] 1234 is correct
[HentaiTextWriterUtils] 12345 is correct
[HentaiTextWriterUtils] 123456 is correct
[HentaiTextWriterUtils] 1234567 is correct
[HentaiTextWriterUtils] 12345678 is correct
[HentaiTextWriterUtils] 123456789 is correct
[HentaiTextWriterUtils] -1 is correct
[HentaiTextWriterUtils] -12 is correct
[HentaiTextWriterUtils] -123 is correct
[HentaiTextWriterUtils] -1234 is correct
[HentaiTextWriterUtils] -12345 is correct
[HentaiTextWriterUtils] -123456 is correct
[HentaiTextWriterUtils] -1234567 is correct
[HentaiTextWriterUtils] -12345678 is correct
[HentaiTextWriterUtils] -123456789 is correct
[ExtremeTextWriterUtils] 0 is correct
[ExtremeTextWriterUtils] -2147483648 is correct
[ExtremeTextWriterUtils] 2147483647 is correct
[ExtremeTextWriterUtils] 1 is correct
[ExtremeTextWriterUtils] 12 is correct
[ExtremeTextWriterUtils] 123 is correct
[ExtremeTextWriterUtils] 1234 is correct
[ExtremeTextWriterUtils] 12345 is correct
[ExtremeTextWriterUtils] 123456 is correct
[ExtremeTextWriterUtils] 1234567 is correct
[ExtremeTextWriterUtils] 12345678 is correct
[ExtremeTextWriterUtils] 123456789 is correct
[ExtremeTextWriterUtils] -1 is correct
[ExtremeTextWriterUtils] -12 is correct
[ExtremeTextWriterUtils] -123 is correct
[ExtremeTextWriterUtils] -1234 is correct
[ExtremeTextWriterUtils] -12345 is correct
[ExtremeTextWriterUtils] -123456 is correct
[ExtremeTextWriterUtils] -1234567 is correct
[ExtremeTextWriterUtils] -12345678 is correct
[ExtremeTextWriterUtils] -123456789 is correct
6605147.64255345 op/s [SampletTextWriterUtils] Single thread
8903163.23157404 op/s [ThreadStaticTextWriterUtils] Single thread
8716228.53672304 op/s [HentaiTextWriterUtils] Single thread
19648805.1168632 op/s [ExtremeTextWriterUtils] Single thread
-------
30720173.0160144 op/s [SampletTextWriterUtils] Multi thread
47360885.686451 op/s [ThreadStaticTextWriterUtils] Multi thread
44341080.4591075 op/s [HentaiTextWriterUtils] Multi thread
80020869.4427507 op/s [ExtremeTextWriterUtils] Multi thread
-------
7904069.88462429 op/s [SampletTextWriterUtils] Single thread, smallRnd
12246765.9658945 op/s [ThreadStaticTextWriterUtils] Single thread, smallRnd
13137032.7830712 op/s [HentaiTextWriterUtils] Single thread, smallRnd
17222609.6352579 op/s [ExtremeTextWriterUtils] Single thread, smallRnd
-------
33681850.6694941 op/s [SampletTextWriterUtils] Multi thread, smallRnd
63245346.4074113 op/s [ThreadStaticTextWriterUtils] Multi thread, smallRnd
60807055.5642712 op/s [HentaiTextWriterUtils] Multi thread, smallRnd
83077178.6990114 op/s [ExtremeTextWriterUtils] Multi thread, smallRnd
-------
27854183.3501619 op/s [SampletTextWriterUtils] Multi thread, sb, smallRnd
40513221.4898332 op/s [ThreadStaticTextWriterUtils] Multi thread, sb, smallRnd
37577018.7971521 op/s [HentaiTextWriterUtils] Multi thread, sb, smallRnd
47022289.9761174 op/s [ExtremeTextWriterUtils] Multi thread, sb, smallRnd
-------
6187943.818668 op/s [SampletTextWriterUtils] Single thread, largeRnd
7710310.08014328 op/s [ThreadStaticTextWriterUtils] Single thread, largeRnd
8233501.44222128 op/s [HentaiTextWriterUtils] Single thread, largeRnd
13942371.4384386 op/s [ExtremeTextWriterUtils] Single thread, largeRnd
-------
29246342.2330928 op/s [SampletTextWriterUtils] Multi thread, largeRnd
45563774.2479016 op/s [ThreadStaticTextWriterUtils] Multi thread, largeRnd
43212111.8364024 op/s [HentaiTextWriterUtils] Multi thread, largeRnd
62966661.6713115 op/s [ExtremeTextWriterUtils] Multi thread, largeRnd
-------
23357969.762641 op/s [SampletTextWriterUtils] Multi thread, sb, largeRnd
32218197.0954651 op/s [ThreadStaticTextWriterUtils] Multi thread, sb, largeRnd
30974971.2939454 op/s [HentaiTextWriterUtils] Multi thread, sb, largeRnd
40769267.1479615 op/s [ExtremeTextWriterUtils] Multi thread, sb, largeRnd
-------
DONE!
using System.Globalization;
namespace TestStringFormatPerformance
{
public class SampletTextWriterUtils : ITextWriterUtils
{
public void Write(ITextWriter writer, int value)
{
writer.Write(value.ToString(CultureInfo.InvariantCulture));
}
}
}
using System;
using System.Diagnostics;
using System.IO;
namespace TestStringFormatPerformance
{
public class SingleThreadPerformanceTester<T> where T : ITextWriterUtils, new()
{
private const int _testValue = -1234567890;
public void Test(int round)
{
var writer = new TextWriterAdapter(TextWriter.Null);
var util = new T();
// Cold start;
util.Write(writer, _testValue);
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < round; i++)
{
util.Write(writer, _testValue);
}
watch.Stop();
Console.WriteLine((round / watch.Elapsed.TotalSeconds) + " op/s [" + typeof(T).Name + "] Single thread");
}
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestStringFormatPerformance
{
public class SingleThreadRandomPerformanceTester<T> where T : ITextWriterUtils, new()
{
public void Test(int round, RandomSet randomSet)
{
var writer = new TextWriterAdapter(TextWriter.Null);
var util = new T();
// Cold start;
util.Write(writer, 0);
var watch = new Stopwatch();
watch.Start();
for (int i = 0; i < round; i++)
{
util.Write(writer, randomSet.Get(i));
}
watch.Stop();
Console.WriteLine((round / watch.Elapsed.TotalSeconds) + " op/s [" + typeof(T).Name + "] Single thread, " + randomSet.Name);
}
}
}
using System.IO;
namespace TestStringFormatPerformance
{
public class TextWriterAdapter : ITextWriter
{
public TextWriterAdapter(TextWriter writer)
{
_writer = writer;
}
private TextWriter _writer;
public void Write(char[] chars)
{
_writer.Write(chars);
}
public void Write(string text)
{
_writer.Write(text);
}
public void Write(char[] chars, int startIndex, int count)
{
_writer.Write(chars, startIndex, count);
}
public void Write(string text, int startIndex, int count)
{
_writer.Write(text.Substring(startIndex, count));
}
}
}
using System;
using System.Globalization;
namespace TestStringFormatPerformance
{
public class ThreadStaticTextWriterUtils :ITextWriterUtils
{
[ThreadStatic]
private static char[] _buffer;
private static readonly string _intMinString = int.MinValue.ToString(CultureInfo.InvariantCulture);
public void Write(ITextWriter writer, int value)
{
char[] buffer = GetBuffer();
if (value == 0) { writer.Write("0"); return; }
if (value == int.MinValue) { writer.Write(_intMinString); return; }
bool negative = value < 0;
if (negative) value = -value;
int i = 11;
while (value != 0)
{
i--;
buffer[i] = (char)((value % 10) + '0');
value /= 10;
}
if (negative)
{
buffer[--i] = '-';
}
writer.Write(buffer, i, 11 - i);
}
private char[] GetBuffer()
{
if (_buffer == null)
{
_buffer = new char[11];
}
return _buffer;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment