From 93479cabf38e66c56e08bb0156e132ec809fd1c6 Mon Sep 17 00:00:00 2001 From: Egor Chesakov Date: Tue, 23 Nov 2021 17:19:39 -0800 Subject: [PATCH 1/3] Add benchmarks for InitBlock/CopyBlock operations --- .../micro/runtime/StoreBlock/StoreBlock.cs | 1244 +++++++++++++++++ .../micro/runtime/StoreBlock/StoreBlock.tt | 114 ++ 2 files changed, 1358 insertions(+) create mode 100644 src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs create mode 100644 src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt diff --git a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs new file mode 100644 index 00000000000..6d8627160a7 --- /dev/null +++ b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs @@ -0,0 +1,1244 @@ +// 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. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +[BenchmarkCategory(Categories.Runtime, Categories.JIT)] +public class StoreBlock +{ + const int OperationsPerInvoke = 1000; + + byte[] _srcData = new byte[1024]; + byte[] _dstData = new byte[1024]; + + [GlobalSetup] + public void Setup() + { + for (int i = 0; i < _srcData.Length; i++) + _srcData[i] = (byte)(i % 256); + + for (int i = 0; i < _dstData.Length; i++) + _dstData[i] = (byte)(i % 256); + } + + [StructLayout(LayoutKind.Explicit, Size=8)] + struct Struct8 + { + } + + Struct8 fld8; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap8() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 8); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr8() + { + Struct8 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 8); + } + + fld8 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap8() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 8); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr8() + { + Struct8 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 8); + } + + fld8 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap8() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 8); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr8() + { + Struct8 srcLcl; + Struct8 dstLcl; + + srcLcl = fld8; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 8); + } + + fld8 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=16)] + struct Struct16 + { + } + + Struct16 fld16; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap16() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 16); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr16() + { + Struct16 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 16); + } + + fld16 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap16() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 16); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr16() + { + Struct16 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 16); + } + + fld16 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap16() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 16); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr16() + { + Struct16 srcLcl; + Struct16 dstLcl; + + srcLcl = fld16; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 16); + } + + fld16 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=24)] + struct Struct24 + { + } + + Struct24 fld24; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap24() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 24); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr24() + { + Struct24 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 24); + } + + fld24 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap24() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 24); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr24() + { + Struct24 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 24); + } + + fld24 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap24() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 24); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr24() + { + Struct24 srcLcl; + Struct24 dstLcl; + + srcLcl = fld24; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 24); + } + + fld24 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=32)] + struct Struct32 + { + } + + Struct32 fld32; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap32() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 32); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr32() + { + Struct32 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 32); + } + + fld32 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap32() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 32); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr32() + { + Struct32 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 32); + } + + fld32 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap32() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 32); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr32() + { + Struct32 srcLcl; + Struct32 dstLcl; + + srcLcl = fld32; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 32); + } + + fld32 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=40)] + struct Struct40 + { + } + + Struct40 fld40; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap40() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 40); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr40() + { + Struct40 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 40); + } + + fld40 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap40() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 40); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr40() + { + Struct40 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 40); + } + + fld40 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap40() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 40); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr40() + { + Struct40 srcLcl; + Struct40 dstLcl; + + srcLcl = fld40; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 40); + } + + fld40 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=48)] + struct Struct48 + { + } + + Struct48 fld48; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap48() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 48); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr48() + { + Struct48 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 48); + } + + fld48 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap48() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 48); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr48() + { + Struct48 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 48); + } + + fld48 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap48() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 48); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr48() + { + Struct48 srcLcl; + Struct48 dstLcl; + + srcLcl = fld48; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 48); + } + + fld48 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=56)] + struct Struct56 + { + } + + Struct56 fld56; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap56() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 56); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr56() + { + Struct56 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 56); + } + + fld56 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap56() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 56); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr56() + { + Struct56 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 56); + } + + fld56 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap56() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 56); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr56() + { + Struct56 srcLcl; + Struct56 dstLcl; + + srcLcl = fld56; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 56); + } + + fld56 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=64)] + struct Struct64 + { + } + + Struct64 fld64; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap64() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 64); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr64() + { + Struct64 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 64); + } + + fld64 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap64() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 64); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr64() + { + Struct64 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 64); + } + + fld64 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap64() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 64); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr64() + { + Struct64 srcLcl; + Struct64 dstLcl; + + srcLcl = fld64; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 64); + } + + fld64 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=72)] + struct Struct72 + { + } + + Struct72 fld72; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap72() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 72); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr72() + { + Struct72 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 72); + } + + fld72 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap72() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 72); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr72() + { + Struct72 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 72); + } + + fld72 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap72() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 72); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr72() + { + Struct72 srcLcl; + Struct72 dstLcl; + + srcLcl = fld72; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 72); + } + + fld72 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=80)] + struct Struct80 + { + } + + Struct80 fld80; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap80() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 80); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr80() + { + Struct80 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 80); + } + + fld80 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap80() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 80); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr80() + { + Struct80 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 80); + } + + fld80 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap80() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 80); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr80() + { + Struct80 srcLcl; + Struct80 dstLcl; + + srcLcl = fld80; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 80); + } + + fld80 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=88)] + struct Struct88 + { + } + + Struct88 fld88; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap88() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 88); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr88() + { + Struct88 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 88); + } + + fld88 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap88() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 88); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr88() + { + Struct88 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 88); + } + + fld88 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap88() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 88); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr88() + { + Struct88 srcLcl; + Struct88 dstLcl; + + srcLcl = fld88; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 88); + } + + fld88 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=96)] + struct Struct96 + { + } + + Struct96 fld96; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap96() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 96); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr96() + { + Struct96 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 96); + } + + fld96 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap96() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 96); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr96() + { + Struct96 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 96); + } + + fld96 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap96() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 96); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr96() + { + Struct96 srcLcl; + Struct96 dstLcl; + + srcLcl = fld96; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 96); + } + + fld96 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=104)] + struct Struct104 + { + } + + Struct104 fld104; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap104() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 104); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr104() + { + Struct104 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 104); + } + + fld104 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap104() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 104); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr104() + { + Struct104 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 104); + } + + fld104 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap104() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 104); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr104() + { + Struct104 srcLcl; + Struct104 dstLcl; + + srcLcl = fld104; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 104); + } + + fld104 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=112)] + struct Struct112 + { + } + + Struct112 fld112; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap112() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 112); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr112() + { + Struct112 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 112); + } + + fld112 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap112() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 112); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr112() + { + Struct112 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 112); + } + + fld112 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap112() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 112); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr112() + { + Struct112 srcLcl; + Struct112 dstLcl; + + srcLcl = fld112; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 112); + } + + fld112 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=120)] + struct Struct120 + { + } + + Struct120 fld120; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap120() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 120); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr120() + { + Struct120 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 120); + } + + fld120 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap120() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 120); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr120() + { + Struct120 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 120); + } + + fld120 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap120() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 120); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr120() + { + Struct120 srcLcl; + Struct120 dstLcl; + + srcLcl = fld120; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 120); + } + + fld120 = dstLcl; + } + + [StructLayout(LayoutKind.Explicit, Size=128)] + struct Struct128 + { + } + + Struct128 fld128; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap128() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, 128); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr128() + { + Struct128 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 128); + } + + fld128 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap128() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, 128); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr128() + { + Struct128 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, 128); + } + + fld128 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap128() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 128); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr128() + { + Struct128 srcLcl; + Struct128 dstLcl; + + srcLcl = fld128; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 128); + } + + fld128 = dstLcl; + } +} diff --git a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt new file mode 100644 index 00000000000..35cc1c176d9 --- /dev/null +++ b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt @@ -0,0 +1,114 @@ +<#@ template debug="false" hostspecific="true" language="C#" #> +<#@ output extension=".cs" #> +// 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. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using BenchmarkDotNet.Attributes; +using MicroBenchmarks; + +[BenchmarkCategory(Categories.Runtime, Categories.JIT)] +public class StoreBlock +{ + const int OperationsPerInvoke = 1000; + + byte[] _srcData = new byte[1024]; + byte[] _dstData = new byte[1024]; + + [GlobalSetup] + public void Setup() + { + for (int i = 0; i < _srcData.Length; i++) + _srcData[i] = (byte)(i % 256); + + for (int i = 0; i < _dstData.Length; i++) + _dstData[i] = (byte)(i % 256); + } +<# + for (int byteCount = 8; byteCount <= 128; byteCount += 8) + { +#> + + [StructLayout(LayoutKind.Explicit, Size=<#= byteCount #>)] + struct Struct<#= byteCount #> + { + } + + Struct<#= byteCount #> fld<#= byteCount #>; + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllZerosHeap<#= byteCount #>() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 0, <#= byteCount #>); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZerosLocalAddr<#= byteCount #>() + { + Struct<#= byteCount #> dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, <#= byteCount #>); + } + + fld<#= byteCount #> = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void InitBlockAllOnesHeap<#= byteCount #>() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(ref _dstData[0], 255, <#= byteCount #>); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnesLocalAddr<#= byteCount #>() + { + Struct<#= byteCount #> dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 1, <#= byteCount #>); + } + + fld<#= byteCount #> = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public void CopyBlockHeap<#= byteCount #>() + { + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], <#= byteCount #>); + } + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlockLocalAddr<#= byteCount #>() + { + Struct<#= byteCount #> srcLcl; + Struct<#= byteCount #> dstLcl; + + srcLcl = fld<#= byteCount #>; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, <#= byteCount #>); + } + + fld<#= byteCount #> = dstLcl; + } +<# + } +#> +} +<#+ int[] byteCounts = new int[] { 7, 8, 15, 16, 31, 32, 48, 64, 96, 128 }; #> From 2e808445f4f6e26d7c885fa9d17ac433acb79f15 Mon Sep 17 00:00:00 2001 From: Egor Chesakov Date: Thu, 2 Dec 2021 18:05:48 -0800 Subject: [PATCH 2/3] Address feedback --- .../micro/runtime/StoreBlock/StoreBlock.cs | 1309 +++-------------- .../micro/runtime/StoreBlock/StoreBlock.tt | 152 +- 2 files changed, 288 insertions(+), 1173 deletions(-) diff --git a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs index 6d8627160a7..221d9d1b41d 100644 --- a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs +++ b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs @@ -6,1239 +6,334 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Extensions; using MicroBenchmarks; -[BenchmarkCategory(Categories.Runtime, Categories.JIT)] -public class StoreBlock +namespace StoreBlock { - const int OperationsPerInvoke = 1000; - - byte[] _srcData = new byte[1024]; - byte[] _dstData = new byte[1024]; - - [GlobalSetup] - public void Setup() - { - for (int i = 0; i < _srcData.Length; i++) - _srcData[i] = (byte)(i % 256); - - for (int i = 0; i < _dstData.Length; i++) - _dstData[i] = (byte)(i % 256); - } - - [StructLayout(LayoutKind.Explicit, Size=8)] - struct Struct8 - { - } - - Struct8 fld8; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap8() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 8); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr8() - { - Struct8 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 8); - } - - fld8 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap8() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 8); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr8() - { - Struct8 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 8); - } - - fld8 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap8() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 8); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr8() - { - Struct8 srcLcl; - Struct8 dstLcl; - - srcLcl = fld8; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 8); - } - - fld8 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=16)] - struct Struct16 - { - } - - Struct16 fld16; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap16() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 16); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr16() - { - Struct16 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 16); - } - - fld16 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap16() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 16); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr16() - { - Struct16 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 16); - } - - fld16 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap16() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 16); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr16() - { - Struct16 srcLcl; - Struct16 dstLcl; - - srcLcl = fld16; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 16); - } - - fld16 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=24)] - struct Struct24 - { - } - - Struct24 fld24; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap24() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 24); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr24() - { - Struct24 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 24); - } - - fld24 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap24() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 24); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr24() - { - Struct24 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 24); - } - - fld24 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap24() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 24); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr24() - { - Struct24 srcLcl; - Struct24 dstLcl; - - srcLcl = fld24; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 24); - } - - fld24 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=32)] - struct Struct32 - { - } - - Struct32 fld32; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap32() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 32); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr32() - { - Struct32 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 32); - } - - fld32 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap32() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 32); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr32() - { - Struct32 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 32); - } - - fld32 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap32() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 32); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr32() - { - Struct32 srcLcl; - Struct32 dstLcl; - - srcLcl = fld32; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 32); - } - - fld32 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=40)] - struct Struct40 - { - } - - Struct40 fld40; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap40() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 40); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr40() - { - Struct40 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 40); - } - - fld40 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap40() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 40); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr40() - { - Struct40 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 40); - } - - fld40 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap40() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 40); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr40() - { - Struct40 srcLcl; - Struct40 dstLcl; - - srcLcl = fld40; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 40); - } - - fld40 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=48)] - struct Struct48 - { - } - - Struct48 fld48; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap48() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 48); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr48() - { - Struct48 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 48); - } - - fld48 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap48() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 48); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr48() - { - Struct48 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 48); - } - - fld48 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap48() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 48); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr48() - { - Struct48 srcLcl; - Struct48 dstLcl; - - srcLcl = fld48; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 48); - } - - fld48 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=56)] - struct Struct56 - { - } - - Struct56 fld56; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap56() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 56); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr56() - { - Struct56 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 56); - } - - fld56 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap56() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 56); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr56() - { - Struct56 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 56); - } - - fld56 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap56() + [BenchmarkCategory(Categories.Runtime, Categories.JIT)] + public class AnyLocation { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 56); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr56() - { - Struct56 srcLcl; - Struct56 dstLcl; - - srcLcl = fld56; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 56); - } - - fld56 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=64)] - struct Struct64 - { - } - - Struct64 fld64; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap64() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 64); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr64() - { - Struct64 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 64); - } - - fld64 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap64() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 64); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr64() - { - Struct64 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 64); - } - - fld64 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap64() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 64); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr64() - { - Struct64 srcLcl; - Struct64 dstLcl; - - srcLcl = fld64; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 64); - } - - fld64 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=72)] - struct Struct72 - { - } - - Struct72 fld72; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap72() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 0, 72); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr72() - { - Struct72 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 72); - } - - fld72 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap72() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(ref _dstData[0], 255, 72); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr72() - { - Struct72 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 72); - } - - fld72 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap72() - { - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 72); - } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr72() - { - Struct72 srcLcl; - Struct72 dstLcl; - - srcLcl = fld72; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 72); - } - - fld72 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=80)] - struct Struct80 - { - } + const int Size = 4096; - Struct80 fld80; + byte[] _srcData; + byte[] _dstData; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap80() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [GlobalSetup] + public void Setup() { - Unsafe.InitBlock(ref _dstData[0], 0, 80); + _srcData = ValuesGenerator.Array(Size); + _dstData = ValuesGenerator.Array(Size); } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr80() - { - Struct80 dstLcl; - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 8)] + public void InitBlockAllZeros8() { - Unsafe.InitBlock(&dstLcl, 0, 80); + for (int startOffset = 0; startOffset < Size; startOffset += 8) + { + Unsafe.InitBlock(ref _dstData[startOffset], 0, 8); + } } - fld80 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap80() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 8)] + public void InitBlockAllOnes8() { - Unsafe.InitBlock(ref _dstData[0], 255, 80); + for (int startOffset = 0; startOffset < Size; startOffset += 8) + { + Unsafe.InitBlock(ref _dstData[startOffset], 255, 8); + } } - } - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr80() - { - Struct80 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 8)] + public void CopyBlock8() { - Unsafe.InitBlock(&dstLcl, 1, 80); + for (int startOffset = 0; startOffset < Size; startOffset += 8) + { + Unsafe.CopyBlock(ref _dstData[startOffset], ref _srcData[startOffset], 8); + } } - fld80 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap80() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 16)] + public void InitBlockAllZeros16() { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 80); + for (int startOffset = 0; startOffset < Size; startOffset += 16) + { + Unsafe.InitBlock(ref _dstData[startOffset], 0, 16); + } } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr80() - { - Struct80 srcLcl; - Struct80 dstLcl; - srcLcl = fld80; - - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 16)] + public void InitBlockAllOnes16() { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 80); + for (int startOffset = 0; startOffset < Size; startOffset += 16) + { + Unsafe.InitBlock(ref _dstData[startOffset], 255, 16); + } } - fld80 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=88)] - struct Struct88 - { - } - - Struct88 fld88; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap88() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 16)] + public void CopyBlock16() { - Unsafe.InitBlock(ref _dstData[0], 0, 88); + for (int startOffset = 0; startOffset < Size; startOffset += 16) + { + Unsafe.CopyBlock(ref _dstData[startOffset], ref _srcData[startOffset], 16); + } } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr88() - { - Struct88 dstLcl; - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 32)] + public void InitBlockAllZeros32() { - Unsafe.InitBlock(&dstLcl, 0, 88); + for (int startOffset = 0; startOffset < Size; startOffset += 32) + { + Unsafe.InitBlock(ref _dstData[startOffset], 0, 32); + } } - fld88 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap88() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 32)] + public void InitBlockAllOnes32() { - Unsafe.InitBlock(ref _dstData[0], 255, 88); + for (int startOffset = 0; startOffset < Size; startOffset += 32) + { + Unsafe.InitBlock(ref _dstData[startOffset], 255, 32); + } } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr88() - { - Struct88 dstLcl; - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 32)] + public void CopyBlock32() { - Unsafe.InitBlock(&dstLcl, 1, 88); + for (int startOffset = 0; startOffset < Size; startOffset += 32) + { + Unsafe.CopyBlock(ref _dstData[startOffset], ref _srcData[startOffset], 32); + } } - fld88 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap88() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 64)] + public void InitBlockAllZeros64() { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 88); + for (int startOffset = 0; startOffset < Size; startOffset += 64) + { + Unsafe.InitBlock(ref _dstData[startOffset], 0, 64); + } } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr88() - { - Struct88 srcLcl; - Struct88 dstLcl; - - srcLcl = fld88; - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 64)] + public void InitBlockAllOnes64() { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 88); + for (int startOffset = 0; startOffset < Size; startOffset += 64) + { + Unsafe.InitBlock(ref _dstData[startOffset], 255, 64); + } } - fld88 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=96)] - struct Struct96 - { - } - - Struct96 fld96; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap96() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / 64)] + public void CopyBlock64() { - Unsafe.InitBlock(ref _dstData[0], 0, 96); + for (int startOffset = 0; startOffset < Size; startOffset += 64) + { + Unsafe.CopyBlock(ref _dstData[startOffset], ref _srcData[startOffset], 64); + } } } - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr96() + [BenchmarkCategory(Categories.Runtime, Categories.JIT)] + public class LocalAddress { - Struct96 dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 96); - } - - fld96 = dstLcl; - } + const int OperationsPerInvoke = 100; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap96() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [StructLayout(LayoutKind.Explicit, Size=8)] + struct Struct8 { - Unsafe.InitBlock(ref _dstData[0], 255, 96); } - } - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr96() - { - Struct96 dstLcl; + Struct8 fld8; - for (int i = 0; i < OperationsPerInvoke; i++) + [StructLayout(LayoutKind.Explicit, Size=16)] + struct Struct16 { - Unsafe.InitBlock(&dstLcl, 1, 96); } - fld96 = dstLcl; - } + Struct16 fld16; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap96() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [StructLayout(LayoutKind.Explicit, Size=32)] + struct Struct32 { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 96); } - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr96() - { - Struct96 srcLcl; - Struct96 dstLcl; - srcLcl = fld96; + Struct32 fld32; - for (int i = 0; i < OperationsPerInvoke; i++) + [StructLayout(LayoutKind.Explicit, Size=64)] + struct Struct64 { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 96); } - fld96 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=104)] - struct Struct104 - { - } - - Struct104 fld104; + Struct64 fld64; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap104() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZeros8() { - Unsafe.InitBlock(ref _dstData[0], 0, 104); - } - } + Struct8 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr104() - { - Struct104 dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 8); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 104); + fld8 = dstLcl; } - fld104 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap104() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnes8() { - Unsafe.InitBlock(ref _dstData[0], 255, 104); - } - } + Struct8 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr104() - { - Struct104 dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 255, 8); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 104); + fld8 = dstLcl; } - fld104 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap104() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlock8() { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 104); - } - } + Struct8 srcLcl; + Struct8 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr104() - { - Struct104 srcLcl; - Struct104 dstLcl; + srcLcl = fld8; - srcLcl = fld104; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 8); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 104); + fld8 = dstLcl; } - fld104 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=112)] - struct Struct112 - { - } - - Struct112 fld112; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap112() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZeros16() { - Unsafe.InitBlock(ref _dstData[0], 0, 112); - } - } + Struct16 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr112() - { - Struct112 dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 16); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 112); + fld16 = dstLcl; } - fld112 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap112() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnes16() { - Unsafe.InitBlock(ref _dstData[0], 255, 112); - } - } + Struct16 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr112() - { - Struct112 dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 255, 16); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 112); + fld16 = dstLcl; } - fld112 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap112() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlock16() { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 112); - } - } + Struct16 srcLcl; + Struct16 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr112() - { - Struct112 srcLcl; - Struct112 dstLcl; + srcLcl = fld16; - srcLcl = fld112; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 16); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 112); + fld16 = dstLcl; } - fld112 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=120)] - struct Struct120 - { - } - - Struct120 fld120; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap120() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZeros32() { - Unsafe.InitBlock(ref _dstData[0], 0, 120); - } - } + Struct32 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr120() - { - Struct120 dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 32); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 120); + fld32 = dstLcl; } - fld120 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap120() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnes32() { - Unsafe.InitBlock(ref _dstData[0], 255, 120); - } - } + Struct32 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr120() - { - Struct120 dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 255, 32); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 120); + fld32 = dstLcl; } - fld120 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap120() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlock32() { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 120); - } - } + Struct32 srcLcl; + Struct32 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr120() - { - Struct120 srcLcl; - Struct120 dstLcl; + srcLcl = fld32; - srcLcl = fld120; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 32); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 120); + fld32 = dstLcl; } - fld120 = dstLcl; - } - - [StructLayout(LayoutKind.Explicit, Size=128)] - struct Struct128 - { - } - - Struct128 fld128; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap128() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZeros64() { - Unsafe.InitBlock(ref _dstData[0], 0, 128); - } - } + Struct64 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr128() - { - Struct128 dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 64); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 0, 128); + fld64 = dstLcl; } - fld128 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap128() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnes64() { - Unsafe.InitBlock(ref _dstData[0], 255, 128); - } - } + Struct64 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr128() - { - Struct128 dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 255, 64); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.InitBlock(&dstLcl, 1, 128); + fld64 = dstLcl; } - fld128 = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap128() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlock64() { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], 128); - } - } + Struct64 srcLcl; + Struct64 dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr128() - { - Struct128 srcLcl; - Struct128 dstLcl; + srcLcl = fld64; - srcLcl = fld128; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 64); + } - for (int i = 0; i < OperationsPerInvoke; i++) - { - Unsafe.CopyBlock(&dstLcl, &srcLcl, 128); + fld64 = dstLcl; } - - fld128 = dstLcl; } } diff --git a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt index 35cc1c176d9..6b700c9302e 100644 --- a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt +++ b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt @@ -8,107 +8,127 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Extensions; using MicroBenchmarks; -[BenchmarkCategory(Categories.Runtime, Categories.JIT)] -public class StoreBlock +namespace StoreBlock { - const int OperationsPerInvoke = 1000; - - byte[] _srcData = new byte[1024]; - byte[] _dstData = new byte[1024]; - - [GlobalSetup] - public void Setup() + [BenchmarkCategory(Categories.Runtime, Categories.JIT)] + public class AnyLocation { - for (int i = 0; i < _srcData.Length; i++) - _srcData[i] = (byte)(i % 256); + const int Size = 4096; - for (int i = 0; i < _dstData.Length; i++) - _dstData[i] = (byte)(i % 256); - } + byte[] _srcData; + byte[] _dstData; + + [GlobalSetup] + public void Setup() + { + _srcData = ValuesGenerator.Array(Size); + _dstData = ValuesGenerator.Array(Size); + } <# - for (int byteCount = 8; byteCount <= 128; byteCount += 8) + foreach (int byteCount in byteCounts) { #> - [StructLayout(LayoutKind.Explicit, Size=<#= byteCount #>)] - struct Struct<#= byteCount #> - { - } - - Struct<#= byteCount #> fld<#= byteCount #>; - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllZerosHeap<#= byteCount #>() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / <#= byteCount #>)] + public void InitBlockAllZeros<#= byteCount #>() { - Unsafe.InitBlock(ref _dstData[0], 0, <#= byteCount #>); + for (int startOffset = 0; startOffset < Size; startOffset += <#= byteCount #>) + { + Unsafe.InitBlock(ref _dstData[startOffset], 0, <#= byteCount #>); + } } - } - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllZerosLocalAddr<#= byteCount #>() - { - Struct<#= byteCount #> dstLcl; - - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / <#= byteCount #>)] + public void InitBlockAllOnes<#= byteCount #>() { - Unsafe.InitBlock(&dstLcl, 0, <#= byteCount #>); + for (int startOffset = 0; startOffset < Size; startOffset += <#= byteCount #>) + { + Unsafe.InitBlock(ref _dstData[startOffset], 255, <#= byteCount #>); + } } - fld<#= byteCount #> = dstLcl; - } - - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void InitBlockAllOnesHeap<#= byteCount #>() - { - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = Size / <#= byteCount #>)] + public void CopyBlock<#= byteCount #>() { - Unsafe.InitBlock(ref _dstData[0], 255, <#= byteCount #>); + for (int startOffset = 0; startOffset < Size; startOffset += <#= byteCount #>) + { + Unsafe.CopyBlock(ref _dstData[startOffset], ref _srcData[startOffset], <#= byteCount #>); + } } +<# + } +#> } - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void InitBlockAllOnesLocalAddr<#= byteCount #>() + [BenchmarkCategory(Categories.Runtime, Categories.JIT)] + public class LocalAddress { - Struct<#= byteCount #> dstLcl; + const int OperationsPerInvoke = 100; +<# + foreach (int byteCount in byteCounts) + { +#> - for (int i = 0; i < OperationsPerInvoke; i++) + [StructLayout(LayoutKind.Explicit, Size=<#= byteCount #>)] + struct Struct<#= byteCount #> { - Unsafe.InitBlock(&dstLcl, 1, <#= byteCount #>); } - fld<#= byteCount #> = dstLcl; + Struct<#= byteCount #> fld<#= byteCount #>; +<# } - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public void CopyBlockHeap<#= byteCount #>() + foreach (int byteCount in byteCounts) { - for (int i = 0; i < OperationsPerInvoke; i++) +#> + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZeros<#= byteCount #>() { - Unsafe.CopyBlock(ref _dstData[0], ref _srcData[0], <#= byteCount #>); - } - } + Struct<#= byteCount #> dstLcl; - [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] - public unsafe void CopyBlockLocalAddr<#= byteCount #>() - { - Struct<#= byteCount #> srcLcl; - Struct<#= byteCount #> dstLcl; + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, <#= byteCount #>); + } - srcLcl = fld<#= byteCount #>; + fld<#= byteCount #> = dstLcl; + } - for (int i = 0; i < OperationsPerInvoke; i++) + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnes<#= byteCount #>() { - Unsafe.CopyBlock(&dstLcl, &srcLcl, <#= byteCount #>); + Struct<#= byteCount #> dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 255, <#= byteCount #>); + } + + fld<#= byteCount #> = dstLcl; } - fld<#= byteCount #> = dstLcl; - } + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlock<#= byteCount #>() + { + Struct<#= byteCount #> srcLcl; + Struct<#= byteCount #> dstLcl; + + srcLcl = fld<#= byteCount #>; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, <#= byteCount #>); + } + + fld<#= byteCount #> = dstLcl; + } <# } #> + } } -<#+ int[] byteCounts = new int[] { 7, 8, 15, 16, 31, 32, 48, 64, 96, 128 }; #> +<#+ int[] byteCounts = new int[] { 8, 16, 32, 64 }; #> From e8e8f144095f6e3cb798eb7571794d663d556604 Mon Sep 17 00:00:00 2001 From: Egor Chesakov Date: Thu, 2 Dec 2021 18:16:52 -0800 Subject: [PATCH 3/3] Extend the byteCounts array to include sizes up to 128 bytes (the upper limit used on x86/x64) --- .../micro/runtime/StoreBlock/StoreBlock.cs | 76 +++++++++++++++++++ .../micro/runtime/StoreBlock/StoreBlock.tt | 2 +- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs index 221d9d1b41d..02afd516cd0 100644 --- a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs +++ b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.cs @@ -133,6 +133,33 @@ public void CopyBlock64() Unsafe.CopyBlock(ref _dstData[startOffset], ref _srcData[startOffset], 64); } } + + [Benchmark(OperationsPerInvoke = Size / 128)] + public void InitBlockAllZeros128() + { + for (int startOffset = 0; startOffset < Size; startOffset += 128) + { + Unsafe.InitBlock(ref _dstData[startOffset], 0, 128); + } + } + + [Benchmark(OperationsPerInvoke = Size / 128)] + public void InitBlockAllOnes128() + { + for (int startOffset = 0; startOffset < Size; startOffset += 128) + { + Unsafe.InitBlock(ref _dstData[startOffset], 255, 128); + } + } + + [Benchmark(OperationsPerInvoke = Size / 128)] + public void CopyBlock128() + { + for (int startOffset = 0; startOffset < Size; startOffset += 128) + { + Unsafe.CopyBlock(ref _dstData[startOffset], ref _srcData[startOffset], 128); + } + } } [BenchmarkCategory(Categories.Runtime, Categories.JIT)] @@ -168,6 +195,13 @@ struct Struct64 Struct64 fld64; + [StructLayout(LayoutKind.Explicit, Size=128)] + struct Struct128 + { + } + + Struct128 fld128; + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public unsafe void InitBlockAllZeros8() { @@ -335,5 +369,47 @@ public unsafe void CopyBlock64() fld64 = dstLcl; } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllZeros128() + { + Struct128 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 0, 128); + } + + fld128 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void InitBlockAllOnes128() + { + Struct128 dstLcl; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.InitBlock(&dstLcl, 255, 128); + } + + fld128 = dstLcl; + } + + [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] + public unsafe void CopyBlock128() + { + Struct128 srcLcl; + Struct128 dstLcl; + + srcLcl = fld128; + + for (int i = 0; i < OperationsPerInvoke; i++) + { + Unsafe.CopyBlock(&dstLcl, &srcLcl, 128); + } + + fld128 = dstLcl; + } } } diff --git a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt index 6b700c9302e..3cb28df56c4 100644 --- a/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt +++ b/src/benchmarks/micro/runtime/StoreBlock/StoreBlock.tt @@ -131,4 +131,4 @@ namespace StoreBlock #> } } -<#+ int[] byteCounts = new int[] { 8, 16, 32, 64 }; #> +<#+ int[] byteCounts = new int[] { 8, 16, 32, 64, 128 }; #>