mscorlib cache padding for 128 byte lines (#13102)
authorSteve MacLean <sdmaclea.qdt@qualcommdatacenter.com>
Thu, 24 Aug 2017 17:54:37 +0000 (13:54 -0400)
committerJan Kotas <jkotas@microsoft.com>
Thu, 24 Aug 2017 17:54:37 +0000 (10:54 -0700)
* mscorlib ConcurrentQueue pad for 128B cache lines

* Add Padding.cs

src/mscorlib/System.Private.CoreLib.csproj
src/mscorlib/src/Internal/Padding.cs [new file with mode: 0644]
src/mscorlib/src/System/Collections/Concurrent/ConcurrentQueue.cs
src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs
src/mscorlib/src/System/Threading/ThreadPool.cs

index e7065d1bf2a1795417e1457b54ed3332cbd4a325..609986876bcfbfd6a9cd141116b0d15bb1869b17 100644 (file)
     <Compile Include="$(BclSourcesRoot)\Internal\Runtime\Augments\EnvironmentAugments.cs" />
     <Compile Include="$(BclSourcesRoot)\Internal\Runtime\Augments\RuntimeThread.cs" />
     <Compile Include="$(BclSourcesRoot)\Internal\Console.cs" />
+    <Compile Include="$(BclSourcesRoot)\Internal\Padding.cs" />
   </ItemGroup>
   <ItemGroup>
     <Compile Include="$(BclSourcesRoot)\System\Reflection\Assembly.CoreCLR.cs" />
     <Win32Resource Condition="'$(GenerateNativeVersionInfo)'=='true'">$(IntermediateOutputPath)\System.Private.CoreLib.res</Win32Resource>
   </PropertyGroup>
   <Import Project="GenerateCompilerResponseFile.targets" />
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/mscorlib/src/Internal/Padding.cs b/src/mscorlib/src/Internal/Padding.cs
new file mode 100644 (file)
index 0000000..d25acdc
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.Runtime.InteropServices;
+
+namespace Internal
+{
+
+    /// <summary>A class for common padding constants and eventually routines.</summary>
+    internal static class PaddingHelpers
+    {
+        /// <summary>A size greater than or equal to the size of the most common CPU cache lines.</summary>
+#if ARM64
+        internal const int CACHE_LINE_SIZE = 128;
+#else
+        internal const int CACHE_LINE_SIZE = 64;
+#endif
+    }
+
+    /// <summary>Padding structure used to minimize false sharing</summary>
+    [StructLayout(LayoutKind.Explicit, Size = PaddingHelpers.CACHE_LINE_SIZE - sizeof(int))]
+    internal struct PaddingFor32
+    {
+    }
+}
+
index 632f0eecef9ec115021b3503874a930eb5fbd415..53b7525bc9958c724a056d18ba8aef0de15af124 100644 (file)
@@ -1111,10 +1111,10 @@ namespace System.Collections.Concurrent
 
     /// <summary>Padded head and tail indices, to avoid false sharing between producers and consumers.</summary>
     [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 = 3*Internal.PaddingHelpers.CACHE_LINE_SIZE)] // padding before/between/after fields
     internal struct PaddedHeadAndTail
     {
-        [FieldOffset(64)] public int Head;
-        [FieldOffset(128)] public int Tail;
+        [FieldOffset(1*Internal.PaddingHelpers.CACHE_LINE_SIZE)] public int Head;
+        [FieldOffset(2*Internal.PaddingHelpers.CACHE_LINE_SIZE)] public int Tail;
     }
 }
index f9d5f89398bbd805efc7b51f4043e77f21d39344..df0dbe3942f202909f1e87270f4097c8b5241896 100644 (file)
@@ -332,7 +332,7 @@ namespace System.Threading.Tasks
         private struct SegmentState
         {
             /// <summary>Padding to reduce false sharing between the segment's array and m_first.</summary>
-            internal PaddingFor32 m_pad0;
+            internal Internal.PaddingFor32 m_pad0;
 
             /// <summary>The index of the current head in the segment.</summary>
             internal volatile int m_first;
@@ -340,7 +340,7 @@ namespace System.Threading.Tasks
             internal int m_lastCopy; // not volatile as read and written by the producer, except for IsEmpty, and there m_lastCopy is only read after reading the volatile m_first
 
             /// <summary>Padding to reduce false sharing between the first and last.</summary>
-            internal PaddingFor32 m_pad1;
+            internal Internal.PaddingFor32 m_pad1;
 
             /// <summary>A copy of the current head index.</summary>
             internal int m_firstCopy; // not voliatle as only read and written by the consumer thread
@@ -348,7 +348,7 @@ namespace System.Threading.Tasks
             internal volatile int m_last;
 
             /// <summary>Padding to reduce false sharing with the last and what's after the segment.</summary>
-            internal PaddingFor32 m_pad2;
+            internal Internal.PaddingFor32 m_pad2;
         }
 
         /// <summary>Debugger type proxy for a SingleProducerSingleConsumerQueue of T.</summary>
@@ -366,17 +366,4 @@ namespace System.Threading.Tasks
             }
         }
     }
-
-    /// <summary>A placeholder class for common padding constants and eventually routines.</summary>
-    internal static class PaddingHelpers
-    {
-        /// <summary>A size greater than or equal to the size of the most common CPU cache lines.</summary>
-        internal const int CACHE_LINE_SIZE = 128;
-    }
-
-    /// <summary>Padding structure used to minimize false sharing in SingleProducerSingleConsumerQueue{T}.</summary>
-    [StructLayout(LayoutKind.Explicit, Size = PaddingHelpers.CACHE_LINE_SIZE - sizeof(Int32))] // Based on common case of 64-byte cache lines
-    internal struct PaddingFor32
-    {
-    }
 }
index e457f15eed025ba9e5f1003360daef408a6846da..ec9ceef156aa79e7ee11299a2b164adba656bbc6 100644 (file)
@@ -385,11 +385,11 @@ namespace System.Threading
         internal bool loggingEnabled;
         internal readonly ConcurrentQueue<IThreadPoolWorkItem> workItems = new ConcurrentQueue<IThreadPoolWorkItem>();
 
-        private System.Threading.Tasks.PaddingFor32 pad1;
+        private Internal.PaddingFor32 pad1;
 
         private volatile int numOutstandingThreadRequests = 0;
 
-        private System.Threading.Tasks.PaddingFor32 pad2;
+        private Internal.PaddingFor32 pad2;
 
         public ThreadPoolWorkQueue()
         {