From d26d8e54524d5c0ce98925be1c65adb52a4fec53 Mon Sep 17 00:00:00 2001 From: "Steve MacLean, Qualcomm Datacenter Technologies Inc" Date: Fri, 28 Jul 2017 12:50:53 -0400 Subject: [PATCH 1/4] ConcurrentQueue 128-byte cache line --- .../src/System/Collections/Concurrent/ConcurrentQueue.cs | 6 +++--- .../src/Internal/ProducerConsumerQueues.cs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs b/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs index 1fe4a45f335d..ef14425da230 100644 --- a/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs +++ b/src/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentQueue.cs @@ -1112,10 +1112,10 @@ internal struct Slot /// Padded head and tail indices, to avoid false sharing between producers and consumers. [DebuggerDisplay("Head = {Head}, Tail = {Tail}")] - [StructLayout(LayoutKind.Explicit, Size = 192)] // padding before/between/after fields based on typical cache line size of 64 + [StructLayout(LayoutKind.Explicit, Size = 384)] // padding before/between/after fields based on worst case cache line size of 128 internal struct PaddedHeadAndTail { - [FieldOffset(64)] public int Head; - [FieldOffset(128)] public int Tail; + [FieldOffset(128)] public int Head; + [FieldOffset(256)] public int Tail; } } diff --git a/src/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs b/src/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs index d14fd60cec6a..44b10b3dc83f 100644 --- a/src/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs +++ b/src/System.Threading.Tasks.Dataflow/src/Internal/ProducerConsumerQueues.cs @@ -551,7 +551,7 @@ static class PaddingHelpers } /// Padding structure used to minimize false sharing in SingleProducerSingleConsumerQueue{T}. - [StructLayout(LayoutKind.Explicit, Size = PaddingHelpers.CACHE_LINE_SIZE - sizeof(Int32))] // Based on common case of 64-byte cache lines + [StructLayout(LayoutKind.Explicit, Size = PaddingHelpers.CACHE_LINE_SIZE - sizeof(Int32))] struct PaddingFor32 { } From b18f89334447079231bbd2f72d5fce3b942eefd1 Mon Sep 17 00:00:00 2001 From: "Steve MacLean, Qualcomm Datacenter Technologies Inc" Date: Wed, 30 Aug 2017 14:06:57 -0400 Subject: [PATCH 2/4] Add ConcurrentQueuePerfTest --- .../ConcurrentQueuePerfTest.netcoreapp.cs | 44 +++++++++++++++++++ ...ctions.Concurrent.Performance.Tests.csproj | 25 +++++++++++ 2 files changed, 69 insertions(+) create mode 100644 src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.netcoreapp.cs create mode 100644 src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj diff --git a/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.netcoreapp.cs b/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.netcoreapp.cs new file mode 100644 index 000000000000..d6bbedd23aa0 --- /dev/null +++ b/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.netcoreapp.cs @@ -0,0 +1,44 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Xunit.Performance; +using Xunit; + +namespace System.Collections.Concurrent.Tests +{ + public class Perf_ConcurrentQueueTests + { + /// + /// Creates a list containing a number of elements equal to the specified size + /// + [Benchmark] + [InlineData(8, 1000)] + [InlineData(50, 1000)] + public void Enqueue_Dequeue(int threadsCount, int itemsPerThread) + { + var q = new ConcurrentQueue(); + Task.WaitAll((from i in Enumerable.Range(0, threadsCount) select Task.Run(() => + { + var random = new Random(); + for (int j = 0; j < itemsPerThread; j++) + { + switch (random.Next(2)) + { + case 0: + q.Enqueue(random.Next(int.MaxValue)); + break; + case 1: + int d; + q.TryDequeue(out d); + break; + } + } + })).ToArray()); + } + } +} diff --git a/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj b/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj new file mode 100644 index 000000000000..fb4acb982730 --- /dev/null +++ b/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj @@ -0,0 +1,25 @@ + + + + + true + {13A6510E-E11C-4329-BCDD-4DE561AB6CC0} + true + + + + + + + + Common\System\PerfUtils.cs + + + + + {69e46a6f-9966-45a5-8945-2559fe337827} + PerfRunner + + + + From 380198c5a8f86c141257ccf2c8465c8694341fc3 Mon Sep 17 00:00:00 2001 From: Steve MacLean Date: Thu, 14 Sep 2017 18:24:17 -0400 Subject: [PATCH 3/4] Revise ConcurrentQueuePerfTest per comments --- .../Performance/ConcurrentQueuePerfTest.cs | 93 +++++++++++++++++++ .../ConcurrentQueuePerfTest.netcoreapp.cs | 44 --------- ...ctions.Concurrent.Performance.Tests.csproj | 2 +- 3 files changed, 94 insertions(+), 45 deletions(-) create mode 100644 src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.cs delete mode 100644 src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.netcoreapp.cs diff --git a/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.cs b/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.cs new file mode 100644 index 000000000000..85691b814595 --- /dev/null +++ b/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.cs @@ -0,0 +1,93 @@ +// 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.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Xunit.Performance; +using Xunit; + +namespace System.Collections.Concurrent.Tests +{ + public class Perf_ConcurrentQueueTests + { + internal struct FastRandom // xorshift prng + { + private uint _w, _x, _y, _z; + + public FastRandom(int seed) + { + _x = (uint)seed; + _w = 88675123; + _y = 362436069; + _z = 521288629; + } + + public int Next(int maxValue) + { + uint t = _x ^ (_x << 11); + _x = _y; _y = _z; _z = _w; + _w = _w ^ (_w >> 19) ^ (t ^ (t >> 8)); + + return (int)(_w % (uint)maxValue); + } + } + + /// + /// Benchmark many thread enqueue/dequeue from ConcurrentQueue + /// + [Benchmark(InnerIterationCount = 10)] + [InlineData(8, 100000)] + [InlineData(50, 100000)] + public void Enqueue_Dequeue(int threadCount, int itemsPerThread) + { + foreach (var iteration in Benchmark.Iterations) + { + var q = new ConcurrentQueue(); + + var startTest = new ManualResetEvent(false); + + var tasks = new Task[threadCount]; + for (int i = 0; i < tasks.Length; ++i) + { + tasks[i] = Task.Factory.StartNew(() => + { + var random = new FastRandom(i); + + // Short Warmup + for (int j = 0; j < 10; j++) + { + int d; + q.Enqueue(random.Next(1024)); + q.TryDequeue(out d); + } + + startTest.WaitOne(); + + for (int j = 0; j < itemsPerThread; j++) + { + if (random.Next(1024) < 511) // Slight Dequeue bias + { + q.Enqueue(0); + } + else + { + int d; + q.TryDequeue(out d); + } + } + }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); + } + + using (iteration.StartMeasurement()) + { + startTest.Set(); + + Task.WaitAll(tasks); + } + } + } + } +} diff --git a/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.netcoreapp.cs b/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.netcoreapp.cs deleted file mode 100644 index d6bbedd23aa0..000000000000 --- a/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.netcoreapp.cs +++ /dev/null @@ -1,44 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Xunit.Performance; -using Xunit; - -namespace System.Collections.Concurrent.Tests -{ - public class Perf_ConcurrentQueueTests - { - /// - /// Creates a list containing a number of elements equal to the specified size - /// - [Benchmark] - [InlineData(8, 1000)] - [InlineData(50, 1000)] - public void Enqueue_Dequeue(int threadsCount, int itemsPerThread) - { - var q = new ConcurrentQueue(); - Task.WaitAll((from i in Enumerable.Range(0, threadsCount) select Task.Run(() => - { - var random = new Random(); - for (int j = 0; j < itemsPerThread; j++) - { - switch (random.Next(2)) - { - case 0: - q.Enqueue(random.Next(int.MaxValue)); - break; - case 1: - int d; - q.TryDequeue(out d); - break; - } - } - })).ToArray()); - } - } -} diff --git a/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj b/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj index fb4acb982730..342c59d6d1c8 100644 --- a/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj +++ b/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj @@ -10,7 +10,7 @@ - + Common\System\PerfUtils.cs From 2c0fbc103b42423231d539c69413efd7859fccdc Mon Sep 17 00:00:00 2001 From: Steve MacLean Date: Thu, 14 Sep 2017 18:25:56 -0400 Subject: [PATCH 4/4] Remove ConcurrentQueuePerfTest --- .../Performance/ConcurrentQueuePerfTest.cs | 93 ------------------- ...ctions.Concurrent.Performance.Tests.csproj | 25 ----- 2 files changed, 118 deletions(-) delete mode 100644 src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.cs delete mode 100644 src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj diff --git a/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.cs b/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.cs deleted file mode 100644 index 85691b814595..000000000000 --- a/src/System.Collections.Concurrent/tests/Performance/ConcurrentQueuePerfTest.cs +++ /dev/null @@ -1,93 +0,0 @@ -// 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.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.Xunit.Performance; -using Xunit; - -namespace System.Collections.Concurrent.Tests -{ - public class Perf_ConcurrentQueueTests - { - internal struct FastRandom // xorshift prng - { - private uint _w, _x, _y, _z; - - public FastRandom(int seed) - { - _x = (uint)seed; - _w = 88675123; - _y = 362436069; - _z = 521288629; - } - - public int Next(int maxValue) - { - uint t = _x ^ (_x << 11); - _x = _y; _y = _z; _z = _w; - _w = _w ^ (_w >> 19) ^ (t ^ (t >> 8)); - - return (int)(_w % (uint)maxValue); - } - } - - /// - /// Benchmark many thread enqueue/dequeue from ConcurrentQueue - /// - [Benchmark(InnerIterationCount = 10)] - [InlineData(8, 100000)] - [InlineData(50, 100000)] - public void Enqueue_Dequeue(int threadCount, int itemsPerThread) - { - foreach (var iteration in Benchmark.Iterations) - { - var q = new ConcurrentQueue(); - - var startTest = new ManualResetEvent(false); - - var tasks = new Task[threadCount]; - for (int i = 0; i < tasks.Length; ++i) - { - tasks[i] = Task.Factory.StartNew(() => - { - var random = new FastRandom(i); - - // Short Warmup - for (int j = 0; j < 10; j++) - { - int d; - q.Enqueue(random.Next(1024)); - q.TryDequeue(out d); - } - - startTest.WaitOne(); - - for (int j = 0; j < itemsPerThread; j++) - { - if (random.Next(1024) < 511) // Slight Dequeue bias - { - q.Enqueue(0); - } - else - { - int d; - q.TryDequeue(out d); - } - } - }, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default); - } - - using (iteration.StartMeasurement()) - { - startTest.Set(); - - Task.WaitAll(tasks); - } - } - } - } -} diff --git a/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj b/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj deleted file mode 100644 index 342c59d6d1c8..000000000000 --- a/src/System.Collections.Concurrent/tests/Performance/System.Collections.Concurrent.Performance.Tests.csproj +++ /dev/null @@ -1,25 +0,0 @@ - - - - - true - {13A6510E-E11C-4329-BCDD-4DE561AB6CC0} - true - - - - - - - - Common\System\PerfUtils.cs - - - - - {69e46a6f-9966-45a5-8945-2559fe337827} - PerfRunner - - - -