using System; using System.Buffers; using System.Collections.Generic; using System.Net.Sockets; using DotRecast.Core.Buffers; using DotRecast.Core.Collections; using NUnit.Framework; namespace DotRecast.Core.Test; public class RcArrayBenchmarkTests { private const int StepLength = 512; private const int RandomLoop = 1000; private readonly RcRand _rand = new RcRand(); private (string title, long ticks) Bench(string title, Action source) { var begin = RcFrequency.Ticks; for (int step = StepLength; step > 0; --step) { for (int i = 0; i < RandomLoop; ++i) { source.Invoke(step); } } var end = RcFrequency.Ticks - begin; return (title, end); } private void RoundForArray(int len) { var array = new int[len]; for (int ii = 0; ii < len; ++ii) { array[ii] = _rand.NextInt32(); } } private void RoundForPureRentArray(int len) { var array = ArrayPool.Shared.Rent(len); for (int ii = 0; ii < array.Length; ++ii) { array[ii] = _rand.NextInt32(); } ArrayPool.Shared.Return(array); } private void RoundForRcRentedArray(int len) { using var rentedArray = RcRentedArray.Rent(len); var array = rentedArray.AsArray(); for (int i = 0; i < rentedArray.Length; ++i) { array[i] = _rand.NextInt32(); } } private void RoundForRcStackArray(int len) { var array = new RcStackArray512(); for (int ii = 0; ii < len; ++ii) { array[ii] = _rand.NextInt32(); } } private void RoundForStackalloc(int len) { Span array = stackalloc int[len]; for (int ii = 0; ii < len; ++ii) { array[ii] = _rand.NextInt32(); } } [Test] public void TestBenchmarkArrays() { var results = new List<(string title, long ticks)>(); results.Add(Bench("new int[len]", RoundForArray)); results.Add(Bench("ArrayPool.Shared.Rent(len)", RoundForPureRentArray)); results.Add(Bench("RcRentedArray.Rent(len)", RoundForRcRentedArray)); results.Add(Bench("new RcStackArray512()", RoundForRcStackArray)); results.Add(Bench("stackalloc int[len]", RoundForStackalloc)); results.Sort((x, y) => x.ticks.CompareTo(y.ticks)); foreach (var t in results) { Console.WriteLine($"{t.title} {t.ticks / (double)TimeSpan.TicksPerMillisecond} ms"); } } [Test] public void TestSpanVsArray() { var r = new RcRand(); var list = new List<(long[] src, long[] dest)>(); for (int i = 0; i < 14; ++i) { var s = new long[(int)Math.Pow(2, i + 1)]; var d = new long[(int)Math.Pow(2, i + 1)]; for (int ii = 0; ii < s.Length; ++ii) { s[ii] = r.NextInt32(); } list.Add((s, d)); } var results = new List<(string title, long ticks)>(); for (int i = 0; i < list.Count; ++i) { var seq = i; Array.Fill(list[seq].dest, 0); var resultLong = Bench($"long[{list[seq].src.Length}]", _ => { var v = list[seq]; RcArrays.Copy(v.src, 0, v.dest, 0, v.src.Length); }); Array.Fill(list[seq].dest, 0); var resultSpan = Bench($"Span", _ => { var v = list[seq]; RcSpans.Copy(v.src, 0, v.dest, 0, v.src.Length); }); results.Add(resultLong); results.Add(resultSpan); } int newLine = 0; foreach (var t in results) { Console.WriteLine($"{t.title}: {t.ticks / (double)TimeSpan.TicksPerMillisecond} ms"); newLine += 1; if (0 == (newLine % 2)) { Console.WriteLine(""); } } } }