Adding the new fastest mandelbrot implementation to benchmarks-game.
authorTanner Gooding <tagoo@outlook.com>
Mon, 2 Oct 2017 21:09:24 +0000 (14:09 -0700)
committerTanner Gooding <tagoo@outlook.com>
Sat, 7 Oct 2017 20:18:39 +0000 (13:18 -0700)
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-7.cs [new file with mode: 0644]
tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-7.csproj [new file with mode: 0644]

diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-7.cs b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-7.cs
new file mode 100644 (file)
index 0000000..00469e1
--- /dev/null
@@ -0,0 +1,208 @@
+// 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 #7 program
+// http://benchmarksgame.alioth.debian.org/u64q/program.php?test=mandelbrot&lang=csharpcore&id=7
+// aka (as of 2017-10-02) rev 1.2 of https://alioth.debian.org/scm/viewvc.php/benchmarksgame/bench/mandelbrot/mandelbrot.csharp-7.csharp?root=benchmarksgame&view=log
+// Best-scoring C# .NET Core version as of 2017-10-02
+
+/* 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
+   simplified to compute Cib alongside Crb by Tanner Gooding
+   optimized to use Vector<double> by Tanner Gooding
+*/
+
+using System;
+using System.IO;
+using System.Numerics;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography;
+using System.Threading.Tasks;
+using Microsoft.Xunit.Performance;
+using Xunit;
+
+[assembly: OptimizeForBenchmarks]
+
+namespace BenchmarksGame
+{
+    public class MandelBrot_7
+    {
+        // Vector<double>.Count is treated as a constant by the JIT, don't bother
+        // storing it in a temporary variable anywhere below.
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static unsafe byte GetByte(double* pCrb, double Ciby, int x, int y)
+        {
+            // This currently does not do anything special for 'Count > 2'
+
+            var res = 0;
+
+            for (var i = 0; i < 8; i += 2)
+            {
+                var Crbx = Unsafe.Read<Vector<double>>(pCrb + x + i);
+                var Zr = Crbx;
+                var vCiby = new Vector<double>(Ciby);
+                var Zi = vCiby;
+
+                var b = 0;
+                var j = 49;
+
+                do
+                {
+                    var nZr = Zr * Zr - Zi * Zi + Crbx;
+                    Zi = Zr * Zi + Zr * Zi + vCiby;
+                    Zr = nZr;
+
+                    var t = Zr * Zr + Zi * Zi;
+
+                    if (t[0] > 4)
+                    {
+                        b |= 2;
+
+                        if (b == 3)
+                        {
+                            break;
+                        }
+                    }
+
+                    if (t[1] > 4)
+                    {
+                        b |= 1;
+
+                        if (b == 3)
+                        {
+                            break;
+                        }
+                    }
+
+                } while (--j > 0);
+
+                res = (res << 2) + b;
+            }
+
+            return (byte)(res ^ -1);
+        }
+
+        public static int Main(string[] args)
+        {
+            var size = (args.Length > 0) ? int.Parse(args[0]) : 80;
+            var lineLength = size >> 3;
+
+            var data = DoBench(size, lineLength);
+            var dataLength = size * lineLength;
+
+            Console.Out.Write("P4\n{0} {0}\n", size);
+            Console.OpenStandardOutput().Write(data, 0, dataLength);
+
+            return MatchesChecksum(data, dataLength, "3B-EF-65-05-1D-39-7F-9B-96-8D-EF-98-BF-06-CE-74") ? 100 : -1;
+        }
+
+        // Commented out data left in source to provide checksums for each case
+
+        [Benchmark(InnerIterationCount = 7)]
+        //[InlineData(1000, 125, "B2-13-51-CE-B0-29-2C-4E-75-5E-91-19-18-E4-0C-D9")]
+        //[InlineData(2000, 250, "5A-21-55-9B-7B-18-2F-34-9B-33-C5-F9-B5-2C-40-56")]
+        //[InlineData(3000, 375, "E5-82-85-0A-3C-89-69-B1-A8-21-63-52-75-B3-C8-33")]
+        [InlineData(4000, 500, "C7-E6-66-43-66-73-F8-A8-D3-B4-D7-97-2F-FC-A1-D3")]
+        //[InlineData(5000, 625, "6D-36-F1-F6-37-8F-34-EB-52-F9-2D-11-89-12-B2-2F")]
+        //[InlineData(6000, 750, "8B-05-78-EB-2E-0E-98-F2-C7-39-76-ED-0F-A9-D2-B8")]
+        //[InlineData(7000, 875, "01-F8-F2-2A-AB-70-C7-BA-E3-64-19-E7-D2-84-DF-57")]
+        //[InlineData(8000, 1000, "C8-ED-D7-FB-65-66-3A-D9-C6-04-9E-96-E8-CA-4F-2C")]
+        public static void Bench(int size, int lineLength, string checksum)
+        {
+            byte[] bytes = null;
+
+            Benchmark.Iterate(() => {
+                bytes = DoBench(size, lineLength);
+            });
+
+            Assert.True(MatchesChecksum(bytes, size * lineLength, checksum));
+        }
+
+        static bool MatchesChecksum(byte[] bytes, int length, string checksum)
+        {
+            using (var md5 = MD5.Create())
+            {
+                byte[] hash = md5.ComputeHash(bytes, 0, length);
+                return (checksum == BitConverter.ToString(hash));
+            }
+        }
+
+        static unsafe byte[] DoBench(int size, int lineLength)
+        {
+            var adjustedSize = size + (Vector<double>.Count * 8);
+            adjustedSize &= ~(Vector<double>.Count * 8);
+
+            var Crb = new double[adjustedSize];
+            var Cib = new double[adjustedSize];
+
+            fixed (double* pCrb = &Crb[0])
+            fixed (double* pCib = &Cib[0])
+            {
+                var invN = new Vector<double>(2.0 / size);
+
+                var onePtFive = new Vector<double>(1.5);
+                var step = new Vector<double>(Vector<double>.Count);
+
+                Vector<double> value;
+
+                if (Vector<double>.Count == 2)
+                {
+                    // Software implementation should hit this path too
+
+                    value = new Vector<double>(new double[] {
+                        0, 1
+                    });
+                }
+                else if (Vector<double>.Count == 4)
+                {
+                    value = new Vector<double>(new double[] {
+                        0, 1, 2, 3
+                    });
+                }
+                else
+                {
+                    // No hardware supports about 'Count == 8' today
+
+                    value = new Vector<double>(new double[] {
+                        0, 1, 2, 3, 4, 5, 6, 7
+                    });
+                }
+
+                for (var i = 0; i < size; i += Vector<double>.Count)
+                {
+                    var t = value * invN;
+
+                    Unsafe.Write(pCrb + i, t - onePtFive);
+                    Unsafe.Write(pCib + i, t - Vector<double>.One);
+
+                    value += step;
+                }
+            }
+
+            var data = new byte[adjustedSize * lineLength];
+
+            fixed (double* pCrb = &Crb[0])
+            {
+                // C# doesn't let us pass a pinned variable to a lambda directly
+                var _Crb = pCrb;
+
+                Parallel.For(0, size, y => {
+                    var offset = y * lineLength;
+
+                    for (var x = 0; x < lineLength; x++)
+                    {
+                        data[offset + x] = GetByte(_Crb, Cib[y], x * 8, y);
+                    }
+                });
+            }
+
+            return data;
+        }
+    }
+}
diff --git a/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-7.csproj b/tests/src/JIT/Performance/CodeQuality/BenchmarksGame/mandelbrot/mandelbrot-7.csproj
new file mode 100644 (file)
index 0000000..7a1b3a2
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{42E452A1-BB95-4236-A70E-03A8F89CCD70}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+    <NuGetTargetMoniker>.NETStandard,Version=v1.4</NuGetTargetMoniker>
+    <NuGetTargetMonikerShort>netstandard1.4</NuGetTargetMonikerShort>
+    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+  </PropertyGroup>
+  <!-- Default configurations to help VS understand the configurations -->
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' " />
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+  <PropertyGroup>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+      <Visible>False</Visible>
+    </CodeAnalysisDependentAssemblyPaths>
+  </ItemGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="$(MSBuildProjectName).cs" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+  <PropertyGroup>
+    <ProjectAssetsFile>$(JitPackagesConfigFileDirectory)benchmark\obj\project.assets.json</ProjectAssetsFile>
+  </PropertyGroup>
+</Project>