Skip to content
This repository was archived by the owner on Nov 1, 2020. It is now read-only.

Commit 8ec2ef2

Browse files
authored
Merge pull request #2413 from jkotas/array-pool
Add ArrayPool to CoreLib. Port of dotnet/coreclr#7734 to CoreRT. Path and File I/O depends on it.
2 parents ef2c71a + 9a8bb3a commit 8ec2ef2

File tree

16 files changed

+865
-11
lines changed

16 files changed

+865
-11
lines changed

src/Common/src/Interop/Unix/System.Private.CoreLib.Native/Interop.GetTickCount64.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@ internal static partial class Interop
1111
internal unsafe partial class Sys
1212
{
1313
[DllImport(Interop.Libraries.CoreLibNative, EntryPoint = "CoreLibNative_GetTickCount64")]
14-
internal static extern unsafe ulong GetTickCount64();
14+
internal static extern ulong GetTickCount64();
1515
}
1616
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Runtime.CompilerServices;
7+
using System.Runtime.InteropServices;
8+
9+
internal static partial class Interop
10+
{
11+
internal unsafe partial class Sys
12+
{
13+
[DllImport(Interop.Libraries.CoreLibNative, EntryPoint = "CoreLibNative_SchedGetCpu")]
14+
internal static extern int SchedGetCpu();
15+
}
16+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Runtime.InteropServices;
7+
8+
internal static partial class Interop
9+
{
10+
internal static partial class mincore
11+
{
12+
[DllImport("api-ms-win-core-processthreads-l1-1-1.dll")]
13+
internal extern static uint GetCurrentProcessorNumber();
14+
}
15+
}

src/Native/System.Private.CoreLib.Native/config.h.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
#cmakedefine01 HAVE_CLOCK_MONOTONIC
44
#cmakedefine01 HAVE_CLOCK_MONOTONIC_COARSE
55
#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME
6+
#cmakedefine01 HAVE_SCHED_GETCPU

src/Native/System.Private.CoreLib.Native/configure.cmake

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
check_cxx_source_runs("
32
#include <stdlib.h>
43
#include <time.h>
@@ -12,6 +11,7 @@ int main()
1211
1312
exit(ret);
1413
}" HAVE_CLOCK_MONOTONIC)
14+
1515
check_cxx_source_runs("
1616
#include <stdlib.h>
1717
#include <time.h>
@@ -25,6 +25,7 @@ int main()
2525
2626
exit(ret);
2727
}" HAVE_CLOCK_MONOTONIC_COARSE)
28+
2829
check_cxx_source_runs("
2930
#include <stdlib.h>
3031
#include <mach/mach_time.h>
@@ -38,7 +39,21 @@ int main()
3839
exit(ret);
3940
}" HAVE_MACH_ABSOLUTE_TIME)
4041

42+
set(CMAKE_REQUIRED_LIBRARIES pthread)
43+
check_cxx_source_runs("
44+
#include <stdlib.h>
45+
#include <sched.h>
46+
47+
int main(void)
48+
{
49+
if (sched_getcpu() >= 0)
50+
{
51+
exit(0);
52+
}
53+
exit(1);
54+
}" HAVE_SCHED_GETCPU)
55+
set(CMAKE_REQUIRED_LIBRARIES)
56+
4157
configure_file(
4258
${CMAKE_CURRENT_SOURCE_DIR}/config.h.in
4359
${CMAKE_CURRENT_BINARY_DIR}/config.h)
44-

src/Native/System.Private.CoreLib.Native/pal_environment.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
#include <sys/time.h>
1010
#include <time.h>
1111

12+
#if HAVE_SCHED_GETCPU
13+
#include <sched.h>
14+
#endif
15+
1216
#if HAVE_MACH_ABSOLUTE_TIME
1317
#include <mach/mach_time.h>
1418
static mach_timebase_info_data_t s_timebaseInfo = {};
@@ -95,6 +99,15 @@ extern "C" uint64_t CoreLibNative_GetTickCount64()
9599
return retval;
96100
}
97101

102+
extern "C" int32_t CoreLibNative_SchedGetCpu()
103+
{
104+
#if HAVE_SCHED_GETCPU
105+
return sched_getcpu();
106+
#else
107+
return -1;
108+
#endif
109+
}
110+
98111
extern "C" void CoreLibNative_ExitProcess(int32_t exitCode)
99112
{
100113
exit(exitCode);

src/System.Private.CoreLib/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1918,4 +1918,7 @@
19181918
<data name="InvalidOperation_MustCallInitialize" xml:space="preserve">
19191919
<value>You must call Initialize on this object instance before using it.</value>
19201920
</data>
1921+
<data name="ArgumentException_BufferNotFromPool" xml:space="preserve">
1922+
<value>The buffer is not associated with this pool and may not be returned to it.</value>
1923+
</data>
19211924
</root>

src/System.Private.CoreLib/src/System.Private.CoreLib.csproj

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@
218218
<Compile Include="System\Char.cs" />
219219
<Compile Include="System\CharEnumerator.cs" />
220220
<Compile Include="System\CLSCompliantAttribute.cs" />
221+
<Compile Include="System\Buffers\ArrayPool.cs" />
222+
<Compile Include="System\Buffers\ArrayPoolEventSource.cs" />
223+
<Compile Include="System\Buffers\ConfigurableArrayPool.cs" />
224+
<Compile Include="System\Buffers\TlsOverPerCoreLockedStacksArrayPool.cs" />
225+
<Compile Include="System\Buffers\Utilities.cs" />
221226
<Compile Include="System\Collections\DictionaryEntry.cs" />
222227
<Compile Include="System\Collections\Concurrent\LowLevelConcurrentQueue.cs" />
223228
<Compile Include="System\Collections\Generic\ArraySortHelper.cs" />
@@ -654,7 +659,7 @@
654659
<Compile Include="System\WeakReference.cs" />
655660
<Compile Include="System\WeakReferenceOfT.cs" />
656661
</ItemGroup>
657-
<ItemGroup Condition="'$(TargetsWindows)'=='true' and '$(EnableWinRT)'!='true'">
662+
<ItemGroup Condition="'$(TargetsWindows)'=='true' and '$(EnableWinRT)'!='true'">
658663
<Compile Include="Microsoft\Win32\SafeHandles\SafeRegistryHandle.cs" />
659664
<Compile Include="Microsoft\Win32\SafeHandles\SafeLibraryHandle.cs" />
660665
<Compile Include="Microsoft\Win32\SafeHandles\SafeRegistryHandle.Windows.cs" />
@@ -768,6 +773,9 @@
768773
<Compile Condition="'$(EnableWinRT)' != 'true'" Include="..\..\Common\src\Interop\Windows\mincore\Interop.DynamicLoad.cs">
769774
<Link>Interop\Windows\mincore\Interop.DynamicLoad.cs</Link>
770775
</Compile>
776+
<Compile Include="..\..\Common\src\Interop\Windows\mincore\Interop.GetCurrentProcessorNumber.cs">
777+
<Link>Interop\Windows\mincore\Interop.GetCurrentProcessorNumber.cs</Link>
778+
</Compile>
771779
</ItemGroup>
772780
<ItemGroup>
773781
<!-- CORERT-TODO: Port to Unix -->
@@ -844,6 +852,9 @@
844852
<Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.SysConf.cs">
845853
<Link>Interop\Unix\System.Private.CoreLib.Native\Interop.SysConf.cs</Link>
846854
</Compile>
855+
<Compile Include="..\..\Common\src\Interop\Unix\System.Private.CoreLib.Native\Interop.SchedGetCpu.cs">
856+
<Link>Interop\Unix\System.Private.CoreLib.Native\Interop.SchedGetCpu.cs</Link>
857+
</Compile>
847858
</ItemGroup>
848859
<!-- Dummy globalization implementation -->
849860
<ItemGroup Condition="'$(TargetsUnix)'=='true'">
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace System.Buffers
6+
{
7+
/// <summary>
8+
/// Provides a resource pool that enables reusing instances of type <see cref="T:T[]"/>.
9+
/// </summary>
10+
/// <remarks>
11+
/// <para>
12+
/// Renting and returning buffers with an <see cref="ArrayPool{T}"/> can increase performance
13+
/// in situations where arrays are created and destroyed frequently, resulting in significant
14+
/// memory pressure on the garbage collector.
15+
/// </para>
16+
/// <para>
17+
/// This class is thread-safe. All members may be used by multiple threads concurrently.
18+
/// </para>
19+
/// </remarks>
20+
public abstract class ArrayPool<T>
21+
{
22+
/// <summary>Per-type cached pool.</summary>
23+
/// <remarks>
24+
/// byte[] and char[] are the most commonly pooled array types. For these we use a special pool type
25+
/// optimized for very fast access speeds, at the expense of more memory consumption.
26+
/// The shared instance is created lazily on first access by the runtime.
27+
/// </remarks>
28+
private readonly static ArrayPool<T> _sharedInstance =
29+
typeof(T) == typeof(byte) || typeof(T) == typeof(char) ? new TlsOverPerCoreLockedStacksArrayPool<T>() :
30+
Create();
31+
32+
/// <summary>
33+
/// Retrieves a shared <see cref="ArrayPool{T}"/> instance.
34+
/// </summary>
35+
/// <remarks>
36+
/// The shared pool provides a default implementation of <see cref="ArrayPool{T}"/>
37+
/// that's intended for general applicability. It maintains arrays of multiple sizes, and
38+
/// may hand back a larger array than was actually requested, but will never hand back a smaller
39+
/// array than was requested. Renting a buffer from it with <see cref="Rent"/> will result in an
40+
/// existing buffer being taken from the pool if an appropriate buffer is available or in a new
41+
/// buffer being allocated if one is not available.
42+
/// </remarks>
43+
public static ArrayPool<T> Shared => _sharedInstance;
44+
45+
/// <summary>
46+
/// Creates a new <see cref="ArrayPool{T}"/> instance using default configuration options.
47+
/// </summary>
48+
/// <returns>A new <see cref="ArrayPool{T}"/> instance.</returns>
49+
public static ArrayPool<T> Create() => new ConfigurableArrayPool<T>();
50+
51+
/// <summary>
52+
/// Creates a new <see cref="ArrayPool{T}"/> instance using custom configuration options.
53+
/// </summary>
54+
/// <param name="maxArrayLength">The maximum length of array instances that may be stored in the pool.</param>
55+
/// <param name="maxArraysPerBucket">
56+
/// The maximum number of array instances that may be stored in each bucket in the pool. The pool
57+
/// groups arrays of similar lengths into buckets for faster access.
58+
/// </param>
59+
/// <returns>A new <see cref="ArrayPool{T}"/> instance with the specified configuration options.</returns>
60+
/// <remarks>
61+
/// The created pool will group arrays into buckets, with no more than <paramref name="maxArraysPerBucket"/>
62+
/// in each bucket and with those arrays not exceeding <paramref name="maxArrayLength"/> in length.
63+
/// </remarks>
64+
public static ArrayPool<T> Create(int maxArrayLength, int maxArraysPerBucket) =>
65+
new ConfigurableArrayPool<T>(maxArrayLength, maxArraysPerBucket);
66+
67+
/// <summary>
68+
/// Retrieves a buffer that is at least the requested length.
69+
/// </summary>
70+
/// <param name="minimumLength">The minimum length of the array needed.</param>
71+
/// <returns>
72+
/// An <see cref="T:T[]"/> that is at least <paramref name="minimumLength"/> in length.
73+
/// </returns>
74+
/// <remarks>
75+
/// This buffer is loaned to the caller and should be returned to the same pool via
76+
/// <see cref="Return"/> so that it may be reused in subsequent usage of <see cref="Rent"/>.
77+
/// It is not a fatal error to not return a rented buffer, but failure to do so may lead to
78+
/// decreased application performance, as the pool may need to create a new buffer to replace
79+
/// the one lost.
80+
/// </remarks>
81+
public abstract T[] Rent(int minimumLength);
82+
83+
/// <summary>
84+
/// Returns to the pool an array that was previously obtained via <see cref="Rent"/> on the same
85+
/// <see cref="ArrayPool{T}"/> instance.
86+
/// </summary>
87+
/// <param name="array">
88+
/// The buffer previously obtained from <see cref="Rent"/> to return to the pool.
89+
/// </param>
90+
/// <param name="clearArray">
91+
/// If <c>true</c> and if the pool will store the buffer to enable subsequent reuse, <see cref="Return"/>
92+
/// will clear <paramref name="array"/> of its contents so that a subsequent consumer via <see cref="Rent"/>
93+
/// will not see the previous consumer's content. If <c>false</c> or if the pool will release the buffer,
94+
/// the array's contents are left unchanged.
95+
/// </param>
96+
/// <remarks>
97+
/// Once a buffer has been returned to the pool, the caller gives up all ownership of the buffer
98+
/// and must not use it. The reference returned from a given call to <see cref="Rent"/> must only be
99+
/// returned via <see cref="Return"/> once. The default <see cref="ArrayPool{T}"/>
100+
/// may hold onto the returned buffer in order to rent it again, or it may release the returned buffer
101+
/// if it's determined that the pool already has enough buffers stored.
102+
/// </remarks>
103+
public abstract void Return(T[] array, bool clearArray = false);
104+
}
105+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace System.Buffers
6+
{
7+
internal sealed class ArrayPoolEventSource
8+
{
9+
internal readonly static ArrayPoolEventSource Log = new ArrayPoolEventSource();
10+
11+
// TODO: EventSource instrumentation https://github.com/dotnet/corert/issues/2414
12+
13+
internal bool IsEnabled()
14+
{
15+
return false;
16+
}
17+
18+
internal enum BufferAllocatedReason : int
19+
{
20+
Pooled,
21+
OverMaximumSize,
22+
PoolExhausted
23+
}
24+
25+
internal void BufferRented(int bufferId, int bufferSize, int poolId, int bucketId)
26+
{
27+
}
28+
29+
internal void BufferAllocated(int bufferId, int bufferSize, int poolId, int bucketId, BufferAllocatedReason reason)
30+
{
31+
}
32+
33+
internal void BufferReturned(int bufferId, int bufferSize, int poolId)
34+
{
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)