Skip to content

Instantly share code, notes, and snippets.

@sumtec
Last active August 29, 2015 14:21
Show Gist options
  • Save sumtec/611680a87984269af0cd to your computer and use it in GitHub Desktop.
Save sumtec/611680a87984269af0cd to your computer and use it in GitHub Desktop.
JeffreyZhao's gist. Check ExtremeTextWriterUtils's result.
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.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TestStringFormatPerformance
{
public static class MagicSequence
{
static MagicSequence()
{
//Initialize();
}
public static void Initialize()
{
var bits = GenerateBits();
//Count(bits);
var context = new Context { Heading = 9, Normal = 9999, Reversed = 9999 };
context.Builder.Append(99999);
_created++;
_remain--;
bits[99999] = false;
Stopwatch watch = new Stopwatch();
watch.Start();
while (GenerateOne(bits, context))
{
//if ((_created % 10000) == 0)
//{
// watch.Stop();
// Console.WriteLine("T:{0}, C:{1}, R:{2} (S:{3:0.000}s)", _total, _created, _remain, watch.Elapsed.TotalSeconds);
// watch.Start();
//}
}
watch.Stop();
Console.WriteLine("T:{0}, C:{1}, R:{2} (S:{3:0.000}s)", _total, _created, _remain, watch.Elapsed.TotalSeconds);
}
private const string TEMPLATE = @"
namespace TestStringFormatPerformance
{
public class SmartCopyBase
{
protected const string Sequence = ""{1}"";
protected static readonly int[] Pointers =
{2};
}
}";
private static bool GenerateOne(bool[] bits, Context context)
{
for (int level = 10; level <= 100000; level *= 10)
{
context.Heading = (context.Reversed / (level / 10)) % 10;
//if (TryNormalPart(bits, context, level)) return true;
if (TryMixPart(bits, context, level)) return true;
///if (TryReversePart(bits, context, level)) return true;
}
//Dump(bits);
//StringBuilder builder = new StringBuilder(",");
//for (int i = 0; i < bits.Length; i++)
//{
// if (bits[i] == false) continue;
// builder.Append(i.ToString("00000") + ",");
//}
//String x = builder.ToString();
//string n = context.Normal.ToString("0000");
//string r = context.Reversed.ToString("0000");
//for (int i = 1; i <= 4; i++)
//{
// if (x.Contains("," + n.Substring(4 - i)) ||
// x.Contains(r.Substring(0, i) + ","))
// {
// Console.WriteLine("!" + n + "," + r + ":" + i);
// }
//}
//context.Heading.ToString()
//Count(bits);
//for (int i = 9, h = 90000; i >= 0; i--, h -= 10000)
//{
// for (int j = 9990; j >= 0; j -= 10)
// {
// if (TryNormal(bits, context, 100000, h + j, h + j)) return true;
// for (int k = 9; k >= i; k--)
// {
// if (TryNormal(bits, context, 100000, h + j + k, h + j + k)) return true;
// }
// }
//}
//Console.WriteLine("H:{0}, N:{1}, R:{2}", context.Heading, context.Normal, context.Reversed);
//Dump(bits);
return false;
}
private static void Count(bool[] bits)
{
Console.WriteLine(bits.Count(item => item));
}
private static void Dump(bool[] bits)
{
int cnt = 0;
//for (int i = 0, h = 0; i <= 9; i++, h += 10000)
//{
// for (int j = 0; j <= 9990; j += 10)
// {
// if (bits[i + j]) { Console.Write((i + j) + ","); cnt++; if ((cnt & 7) == 0) Console.WriteLine(); }
// for (int k = i; k <= 9; k++)
// {
// if (bits[i + j + k]) { Console.Write((i + j + k) + ","); cnt++; if ((cnt & 7) == 0) Console.WriteLine(); }
// }
// }
//}
for (int i = 0; i < 100000; i++)
{
if (bits[i]) { Console.Write((i) + ","); cnt++; if ((cnt & 7) == 0) Console.WriteLine(); }
}
Console.WriteLine();
}
private static bool TryMixPart(bool[] bits, Context context, int level)
{
var enumeratorNormal = TryNormalPartMix(bits, context, level).GetEnumerator();
var normalHasNext = enumeratorNormal.MoveNext();
var lastNormal = enumeratorNormal.Current;
var enumeratorReversed = TryReversePartMix(bits, context, level).GetEnumerator();
var reversedHasNext = enumeratorReversed.MoveNext();
var lastReversed = enumeratorReversed.Current;
while (normalHasNext || reversedHasNext)
{
if (!normalHasNext)
{
if (TryReverse(bits, context, level, lastReversed.Value, lastReversed.AppendingValue)) return true;
reversedHasNext = enumeratorReversed.MoveNext();
lastReversed = enumeratorReversed.Current;
continue;
}
if (!reversedHasNext || lastNormal.Value >= lastReversed.Value)
{
if (TryNormal(bits, context, level, lastNormal.Value, lastNormal.AppendingValue)) return true;
normalHasNext = enumeratorNormal.MoveNext();
lastNormal = enumeratorNormal.Current;
if (reversedHasNext && lastNormal.Value == lastReversed.Value)
{
reversedHasNext = enumeratorReversed.MoveNext();
lastReversed = enumeratorReversed.Current;
}
continue;
}
if (TryReverse(bits, context, level, lastReversed.Value, lastReversed.AppendingValue)) return true;
reversedHasNext = enumeratorReversed.MoveNext();
lastReversed = enumeratorReversed.Current;
}
return false;
}
private class MixTesting
{
public int Value;
public int AppendingValue;
}
private static IEnumerable<MixTesting> TryReversePartMix(bool[] bits, Context context, int level)
{
int power = (int)Math.Log10(level);
int midLevel = (int)Math.Pow(10, 5 - power);
int currentTail = context.Reversed * 10 / level;
for (int head = (context.Heading == 0 ? 9 : context.Heading) * 10000; head >= 0; head -= 10000)
{
for (int mid = (level / 10 - 1) * midLevel; mid >= 0; mid -= midLevel)
{
int h = head + mid;
yield return new MixTesting { Value = h + currentTail, AppendingValue = h };
}
}
}
private static IEnumerable<MixTesting> TryNormalPartMix(bool[] bits, Context context, int level)
{
int currentHead = (context.Normal * level) % 100000;
for (int mid = level - 10; mid >= 0; mid -= 10)
{
for (int tail = 9; tail >= context.Heading; tail--)
{
int t = mid + tail;
yield return new MixTesting { Value = currentHead + t, AppendingValue = t };
}
yield return new MixTesting { Value = currentHead + mid, AppendingValue = mid };
}
}
//private static bool TryReversePart(bool[] bits, Context context, int level)
//{
// int power = (int)Math.Log10(level);
// int midLevel = (int)Math.Pow(10, 5 - power);
// int currentTail = context.Reversed % midLevel;
// for (int head = (context.Heading - 1) * 10000; head >= 0; head -= 10000)
// {
// for (int mid = (level / 10 - 1) * midLevel; mid >= 0; mid -= midLevel)
// {
// int h = head + mid;
// int v = h + currentTail;
// if (TryReverse(bits, context, level, v, h)) return true;
// }
// }
// return false;
//}
//private static bool TryNormalPart(bool[] bits, Context context, int level)
//{
// if (context.Heading == 9) return false;
// int currentHead = (context.Normal * level) % 100000;
// for (int mid = level - 10; mid >= 0; mid -= 10)
// {
// for (int tail = 9; tail > context.Heading; tail--)
// {
// int t = mid + tail;
// int v = currentHead + t;
// if (TryNormal(bits, context, level, v, t)) return true;
// }
// if (TryNormal(bits, context, level, currentHead + mid, mid)) return true;
// }
// return false;
//}
private static bool TryNormal(bool[] bits, Context context, int level, int v, int t)
{
if (bits[v] == false) return false;
bits[v] = false;
context.Builder.Append(t.ToString(level.ToString().Substring(1)));
context.Normal = v % 10000;
//context.Heading = context.Normal / 1000;
context.Reversed = Reverse(context.Normal);
_remain--;
_created++;
return true;
}
private static bool TryReverse(bool[] bits, Context context, int level, int v, int h)
{
if (bits[v] == false) return false;
bits[v] = false;
context.Builder.Append(Reverse(h).ToString(level.ToString().Substring(1)));
context.Reversed = v / 10;
//context.Heading = context.Reversed % 10;
context.Normal = Reverse(context.Reversed);
_remain--;
_created++;
return true;
}
private static int Reverse(int value)
{
int result = 0;
for (int i = 0; i < 4; i++)
{
result *= 10;
//if (value == 0) continue;
int next = value / 10;
result += value - next * 10;
value = next;
}
return result;
}
private static bool[] GenerateBits()
{
var bits = new bool[100000];
for (int i = 0, h = 0; i <= 9; i++, h += 10000)
{
for (int j = 0; j <= 9990; j += 10)
{
if (i != 0)
{
bits[h + j] = true;
_total++;
}
for (int k = i; k <= 9; k++)
{
bits[h + j + k] = true;
_total++;
}
}
}
_remain = _total;
return bits;
}
private static int ToPointer(int currentPosition, bool reverse, int value)
{
int size = value == 0 ? 1 : (int)Math.Log10(value) + 1;
if (reverse == false) currentPosition -= 5;
return ((int)(reverse ? 0x80000000 : 0)) | (currentPosition << 3) | size;
}
public static string Sequence { get; private set; }
private static int _total;
private static int _remain;
private static int _created;
/*
63157 -> [N:3157, R:7513]
3157 [H:3, V: 3157] 31577-9 : 31578 -> [N:1578(H:1,V:1578), R:8751 -> (H:1,V:8751)
7513 [H:3, V: 7513] 1-37513 : 27513 -> [N:1572(H:1,V:1572), R:2751 -> (H:1,V:2751)
*/
private class Context
{
//public readonly char[] Buffer = new char[98304];
//private int Offset;
//public void Write(int value, int length)
//{
// Buffer
//}
public StringBuilder Builder = new StringBuilder(200000);
public int[] Pointers = new int[100000];
public int Heading;
public int Normal;
public int Reversed;
}
}
}
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