Skip to content

Commit 8f517a2

Browse files
committed
Server memory pool metrics updates
1 parent eff021a commit 8f517a2

26 files changed

+292
-146
lines changed

src/Servers/Connections.Abstractions/src/IMemoryPoolFactory.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public interface IMemoryPoolFactory<T>
1313
/// <summary>
1414
/// Creates a new instance of a memory pool.
1515
/// </summary>
16+
/// <param name="options">Options for configuring the memory pool.</param>
1617
/// <returns>A new memory pool instance.</returns>
17-
MemoryPool<T> Create();
18+
MemoryPool<T> Create(MemoryPoolOptions options);
1819
}
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+
4+
namespace Microsoft.AspNetCore.Connections;
5+
6+
/// <summary>
7+
/// Options for configuring a memory pool.
8+
/// </summary>
9+
public sealed class MemoryPoolOptions
10+
{
11+
/// <summary>
12+
/// Gets or sets the owner of the memory pool. This is used for logging and diagnostics purposes.
13+
/// </summary>
14+
public string? Owner { get; set; }
15+
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
#nullable enable
22
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>
3-
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>.Create() -> System.Buffers.MemoryPool<T>!
3+
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>.Create(Microsoft.AspNetCore.Connections.MemoryPoolOptions! options) -> System.Buffers.MemoryPool<T>!
4+
Microsoft.AspNetCore.Connections.MemoryPoolOptions
5+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.MemoryPoolOptions() -> void
6+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.Owner.get -> string?
7+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.Owner.set -> void
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
#nullable enable
22
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>
3-
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>.Create() -> System.Buffers.MemoryPool<T>!
3+
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>.Create(Microsoft.AspNetCore.Connections.MemoryPoolOptions! options) -> System.Buffers.MemoryPool<T>!
4+
Microsoft.AspNetCore.Connections.MemoryPoolOptions
5+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.MemoryPoolOptions() -> void
6+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.Owner.get -> string?
7+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.Owner.set -> void
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
#nullable enable
22
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>
3-
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>.Create() -> System.Buffers.MemoryPool<T>!
3+
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>.Create(Microsoft.AspNetCore.Connections.MemoryPoolOptions! options) -> System.Buffers.MemoryPool<T>!
4+
Microsoft.AspNetCore.Connections.MemoryPoolOptions
5+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.MemoryPoolOptions() -> void
6+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.Owner.get -> string?
7+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.Owner.set -> void
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
#nullable enable
22
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>
3-
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>.Create() -> System.Buffers.MemoryPool<T>!
3+
Microsoft.AspNetCore.Connections.IMemoryPoolFactory<T>.Create(Microsoft.AspNetCore.Connections.MemoryPoolOptions! options) -> System.Buffers.MemoryPool<T>!
4+
Microsoft.AspNetCore.Connections.MemoryPoolOptions
5+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.MemoryPoolOptions() -> void
6+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.Owner.get -> string?
7+
Microsoft.AspNetCore.Connections.MemoryPoolOptions.Owner.set -> void

src/Servers/IIS/IIS/src/Core/IISHttpServer.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public IISHttpServer(
6666
ILogger<IISHttpServer> logger
6767
)
6868
{
69-
_memoryPool = memoryPoolFactory.Create();
69+
_memoryPool = memoryPoolFactory.Create(new MemoryPoolOptions { Owner = "iis" });
7070
_nativeApplication = nativeApplication;
7171
_applicationLifetime = applicationLifetime;
7272
_logger = logger;

src/Servers/IIS/IIS/src/WebHostBuilderIISExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ public static IWebHostBuilder UseIIS(this IWebHostBuilder hostBuilder)
5757
);
5858

5959
services.TryAddSingleton<IMemoryPoolFactory<byte>, DefaultMemoryPoolFactory>();
60+
services.TryAddSingleton<MemoryPoolMetrics>();
6061
});
6162
}
6263

src/Servers/Kestrel/Core/src/Internal/PinnedBlockMemoryPoolFactory.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System.Buffers;
55
using System.Collections.Concurrent;
6-
using System.Diagnostics.Metrics;
76
using Microsoft.AspNetCore.Connections;
87
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure;
98
using Microsoft.Extensions.Logging;
@@ -12,22 +11,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
1211

1312
internal sealed class PinnedBlockMemoryPoolFactory : IMemoryPoolFactory<byte>, IHeartbeatHandler
1413
{
15-
private readonly IMeterFactory _meterFactory;
14+
private readonly MemoryPoolMetrics _metrics;
1615
private readonly ILogger? _logger;
1716
private readonly TimeProvider _timeProvider;
1817
// micro-optimization: Using nuint as the value type to avoid GC write barriers; could replace with ConcurrentHashSet if that becomes available
1918
private readonly ConcurrentDictionary<PinnedBlockMemoryPool, nuint> _pools = new();
2019

21-
public PinnedBlockMemoryPoolFactory(IMeterFactory meterFactory, TimeProvider? timeProvider = null, ILogger<PinnedBlockMemoryPoolFactory>? logger = null)
20+
public PinnedBlockMemoryPoolFactory(MemoryPoolMetrics metrics, TimeProvider? timeProvider = null, ILogger<PinnedBlockMemoryPoolFactory>? logger = null)
2221
{
2322
_timeProvider = timeProvider ?? TimeProvider.System;
24-
_meterFactory = meterFactory;
23+
_metrics = metrics;
2524
_logger = logger;
2625
}
2726

28-
public MemoryPool<byte> Create()
27+
public MemoryPool<byte> Create(MemoryPoolOptions options)
2928
{
30-
var pool = new PinnedBlockMemoryPool(_meterFactory, _logger);
29+
var pool = new PinnedBlockMemoryPool(options.Owner, _metrics, _logger);
3130

3231
_pools.TryAdd(pool, nuint.Zero);
3332

src/Servers/Kestrel/Core/test/PinnedBlockMemoryPoolFactoryTests.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Buffers;
55
using System.Collections.Concurrent;
66
using System.Reflection;
7+
using Microsoft.AspNetCore.Connections;
78
using Microsoft.AspNetCore.InternalTesting;
89
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
910
using Microsoft.Extensions.Time.Testing;
@@ -15,18 +16,18 @@ public class PinnedBlockMemoryPoolFactoryTests
1516
[Fact]
1617
public void CreatePool()
1718
{
18-
var factory = new PinnedBlockMemoryPoolFactory(new TestMeterFactory());
19-
var pool = factory.Create();
19+
var factory = CreateMemoryPoolFactory();
20+
var pool = factory.Create(new MemoryPoolOptions());
2021
Assert.NotNull(pool);
2122
Assert.IsType<PinnedBlockMemoryPool>(pool);
2223
}
2324

2425
[Fact]
2526
public void CreateMultiplePools()
2627
{
27-
var factory = new PinnedBlockMemoryPoolFactory(new TestMeterFactory());
28-
var pool1 = factory.Create();
29-
var pool2 = factory.Create();
28+
var factory = CreateMemoryPoolFactory();
29+
var pool1 = factory.Create(new MemoryPoolOptions());
30+
var pool2 = factory.Create(new MemoryPoolOptions());
3031

3132
Assert.NotNull(pool1);
3233
Assert.NotNull(pool2);
@@ -36,8 +37,8 @@ public void CreateMultiplePools()
3637
[Fact]
3738
public void DisposePoolRemovesFromFactory()
3839
{
39-
var factory = new PinnedBlockMemoryPoolFactory(new TestMeterFactory());
40-
var pool = factory.Create();
40+
var factory = CreateMemoryPoolFactory();
41+
var pool = factory.Create(new MemoryPoolOptions());
4142
Assert.NotNull(pool);
4243

4344
var dict = (ConcurrentDictionary<PinnedBlockMemoryPool, nuint>)(typeof(PinnedBlockMemoryPoolFactory)
@@ -53,11 +54,11 @@ public void DisposePoolRemovesFromFactory()
5354
public async Task FactoryHeartbeatWorks()
5455
{
5556
var timeProvider = new FakeTimeProvider(DateTimeOffset.UtcNow.AddDays(1));
56-
var factory = new PinnedBlockMemoryPoolFactory(new TestMeterFactory(), timeProvider);
57+
var factory = CreateMemoryPoolFactory(timeProvider);
5758

5859
// Use 2 pools to make sure they all get triggered by the heartbeat
59-
var pool = Assert.IsType<PinnedBlockMemoryPool>(factory.Create());
60-
var pool2 = Assert.IsType<PinnedBlockMemoryPool>(factory.Create());
60+
var pool = Assert.IsType<PinnedBlockMemoryPool>(factory.Create(new MemoryPoolOptions()));
61+
var pool2 = Assert.IsType<PinnedBlockMemoryPool>(factory.Create(new MemoryPoolOptions()));
6162

6263
var blocks = new List<IMemoryOwner<byte>>();
6364
for (var i = 0; i < 10000; i++)
@@ -110,4 +111,11 @@ static async Task VerifyPoolEviction(PinnedBlockMemoryPool pool, int previousCou
110111
Assert.InRange(pool.BlockCount(), previousCount - (previousCount / 10), previousCount - (previousCount / 30));
111112
}
112113
}
114+
115+
private static PinnedBlockMemoryPoolFactory CreateMemoryPoolFactory(TimeProvider timeProvider = null)
116+
{
117+
return new PinnedBlockMemoryPoolFactory(
118+
new MemoryPoolMetrics(new TestMeterFactory()),
119+
timeProvider: timeProvider);
120+
}
113121
}

0 commit comments

Comments
 (0)