Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

mscorlib cache padding for 128 byte lines #13102

Merged
merged 2 commits into from
Aug 24, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/mscorlib/System.Private.CoreLib.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@
<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" />
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used the filename Padding.cs because I noticed corefx used that name for the equivalent file.

</ItemGroup>
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\System\Reflection\Assembly.CoreCLR.cs" />
Expand Down Expand Up @@ -678,4 +679,4 @@
<Win32Resource Condition="'$(GenerateNativeVersionInfo)'=='true'">$(IntermediateOutputPath)\System.Private.CoreLib.res</Win32Resource>
</PropertyGroup>
<Import Project="GenerateCompilerResponseFile.targets" />
</Project>
</Project>
27 changes: 27 additions & 0 deletions src/mscorlib/src/Internal/Padding.cs
Original file line number Diff line number Diff line change
@@ -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
{
}
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left these structure pretty much intact because that matches corefx.

}

Original file line number Diff line number Diff line change
Expand Up @@ -1111,10 +1111,10 @@ internal struct Slot

/// <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;
}
}
19 changes: 3 additions & 16 deletions src/mscorlib/src/System/Threading/Tasks/ProducerConsumerQueues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -332,23 +332,23 @@ internal Segment(int size)
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;
/// <summary>A copy of the current tail index.</summary>
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
/// <summary>The index of the current tail in the segment.</summary>
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>
Expand All @@ -366,17 +366,4 @@ public SingleProducerSingleConsumerQueue_DebugView(SingleProducerSingleConsumerQ
}
}
}

/// <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
{
}
}
4 changes: 2 additions & 2 deletions src/mscorlib/src/System/Threading/ThreadPool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -385,11 +385,11 @@ public IThreadPoolWorkItem TrySteal(ref bool missedSteal)
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()
{
Expand Down