Skip to content

Commit b903a1f

Browse files
committed
Naming and Metrics tests
1 parent 815e397 commit b903a1f

23 files changed

+216
-44
lines changed

src/Servers/HttpSys/src/WebHostBuilderHttpSysExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Buffers;
54
using System.Runtime.Versioning;
65
using Microsoft.AspNetCore.Connections;
76
using Microsoft.AspNetCore.Hosting.Server;

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.Buffers;
54
using Microsoft.AspNetCore.Builder;
65
using Microsoft.AspNetCore.Connections;
76
using Microsoft.AspNetCore.Hosting.Server;

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
1+
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System;
55
using System.Buffers;
66
using System.Runtime.InteropServices;
77
using System.Threading.Tasks;
8+
using Microsoft.AspNetCore;
89
using Xunit;
910

1011
namespace Microsoft.Extensions.Internal.Test;

src/Servers/Kestrel/Core/test/Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<Reference Include="Microsoft.Extensions.DependencyInjection" />
2929
<Reference Include="Microsoft.Extensions.FileProviders.Physical" />
3030
<Reference Include="Microsoft.Extensions.Logging" />
31+
<Reference Include="Microsoft.Extensions.Diagnostics.Testing" />
3132
<Reference Include="Microsoft.Extensions.TimeProvider.Testing" />
3233
</ItemGroup>
3334
</Project>

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

Lines changed: 159 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Buffers;
5+
using Microsoft.AspNetCore;
6+
using Microsoft.AspNetCore.InternalTesting;
7+
using Microsoft.AspNetCore.Server.Kestrel.Core.Internal;
8+
using Microsoft.Extensions.Diagnostics.Metrics.Testing;
9+
using Microsoft.Extensions.Time.Testing;
510

611
namespace Microsoft.Extensions.Internal.Test;
712

@@ -192,9 +197,10 @@ public async Task EvictionsAreScheduled()
192197
var previousCount = memoryPool.BlockCount();
193198

194199
// Scheduling only works every 10 seconds and is initialized to UtcNow + 10 when the pool is constructed
195-
Assert.False(memoryPool.TryScheduleEviction(DateTime.UtcNow));
200+
var time = DateTime.UtcNow;
201+
Assert.False(memoryPool.TryScheduleEviction(time));
196202

197-
Assert.True(memoryPool.TryScheduleEviction(DateTime.UtcNow.AddSeconds(10)));
203+
Assert.True(memoryPool.TryScheduleEviction(time.AddSeconds(10)));
198204

199205
var maxWait = TimeSpan.FromSeconds(5);
200206
while (memoryPool.BlockCount() > previousCount - (previousCount / 30) && maxWait > TimeSpan.Zero)
@@ -206,10 +212,10 @@ public async Task EvictionsAreScheduled()
206212
Assert.InRange(memoryPool.BlockCount(), previousCount - (previousCount / 10), previousCount - (previousCount / 30));
207213

208214
// Since we scheduled successfully, we now need to wait 10 seconds to schedule again.
209-
Assert.False(memoryPool.TryScheduleEviction(DateTime.UtcNow.AddSeconds(10)));
215+
Assert.False(memoryPool.TryScheduleEviction(time.AddSeconds(10)));
210216

211217
previousCount = memoryPool.BlockCount();
212-
Assert.True(memoryPool.TryScheduleEviction(DateTime.UtcNow.AddSeconds(20)));
218+
Assert.True(memoryPool.TryScheduleEviction(time.AddSeconds(20)));
213219

214220
maxWait = TimeSpan.FromSeconds(5);
215221
while (memoryPool.BlockCount() > previousCount - (previousCount / 30) && maxWait > TimeSpan.Zero)
@@ -220,4 +226,153 @@ public async Task EvictionsAreScheduled()
220226

221227
Assert.InRange(memoryPool.BlockCount(), previousCount - (previousCount / 10), previousCount - (previousCount / 30));
222228
}
229+
230+
[Fact]
231+
public void CurrentMemoryMetricTracksPooledMemory()
232+
{
233+
var testMeterFactory = new TestMeterFactory();
234+
using var currentMemoryMetric = new MetricCollector<long>(testMeterFactory, "Microsoft.AspNetCore.MemoryPool", "aspnetcore.memorypool.current_memory");
235+
236+
var pool = new PinnedBlockMemoryPool(testMeterFactory);
237+
238+
Assert.Empty(currentMemoryMetric.GetMeasurementSnapshot());
239+
240+
var mem = pool.Rent();
241+
mem.Dispose();
242+
243+
Assert.Collection(currentMemoryMetric.GetMeasurementSnapshot(), m => Assert.Equal(PinnedBlockMemoryPool.BlockSize, m.Value));
244+
245+
mem = pool.Rent();
246+
247+
Assert.Equal(-1 * PinnedBlockMemoryPool.BlockSize, currentMemoryMetric.LastMeasurement.Value);
248+
249+
var mem2 = pool.Rent();
250+
251+
mem.Dispose();
252+
mem2.Dispose();
253+
254+
Assert.Equal(2 * PinnedBlockMemoryPool.BlockSize, currentMemoryMetric.GetMeasurementSnapshot().EvaluateAsCounter());
255+
256+
// Eviction after returning everything to reset internal counters
257+
pool.PerformEviction();
258+
259+
// Trigger eviction
260+
pool.PerformEviction();
261+
262+
// Verify eviction updates current memory metric
263+
Assert.Equal(0, currentMemoryMetric.GetMeasurementSnapshot().EvaluateAsCounter());
264+
}
265+
266+
[Fact]
267+
public void TotalAllocatedMetricTracksAllocatedMemory()
268+
{
269+
var testMeterFactory = new TestMeterFactory();
270+
using var totalMemoryMetric = new MetricCollector<long>(testMeterFactory, "Microsoft.AspNetCore.MemoryPool", "aspnetcore.memorypool.total_allocated");
271+
272+
var pool = new PinnedBlockMemoryPool(testMeterFactory);
273+
274+
Assert.Empty(totalMemoryMetric.GetMeasurementSnapshot());
275+
276+
var mem1 = pool.Rent();
277+
var mem2 = pool.Rent();
278+
279+
// Each Rent that allocates a new block should increment total memory by block size
280+
Assert.Equal(2 * PinnedBlockMemoryPool.BlockSize, totalMemoryMetric.GetMeasurementSnapshot().EvaluateAsCounter());
281+
282+
mem1.Dispose();
283+
mem2.Dispose();
284+
285+
// Disposing (returning) blocks does not affect total memory
286+
Assert.Equal(2 * PinnedBlockMemoryPool.BlockSize, totalMemoryMetric.GetMeasurementSnapshot().EvaluateAsCounter());
287+
}
288+
289+
[Fact]
290+
public void TotalRentedMetricTracksRentOperations()
291+
{
292+
var testMeterFactory = new TestMeterFactory();
293+
using var rentMetric = new MetricCollector<long>(testMeterFactory, "Microsoft.AspNetCore.MemoryPool", "aspnetcore.memorypool.total_rented");
294+
295+
var pool = new PinnedBlockMemoryPool(testMeterFactory);
296+
297+
Assert.Empty(rentMetric.GetMeasurementSnapshot());
298+
299+
var mem1 = pool.Rent();
300+
var mem2 = pool.Rent();
301+
302+
// Each Rent should record the size of the block rented
303+
Assert.Collection(rentMetric.GetMeasurementSnapshot(),
304+
m => Assert.Equal(PinnedBlockMemoryPool.BlockSize, m.Value),
305+
m => Assert.Equal(PinnedBlockMemoryPool.BlockSize, m.Value));
306+
307+
mem1.Dispose();
308+
mem2.Dispose();
309+
310+
// Disposing does not affect rent metric
311+
Assert.Equal(2 * PinnedBlockMemoryPool.BlockSize, rentMetric.GetMeasurementSnapshot().EvaluateAsCounter());
312+
}
313+
314+
[Fact]
315+
public void EvictedMemoryMetricTracksEvictedMemory()
316+
{
317+
var testMeterFactory = new TestMeterFactory();
318+
using var evictMetric = new MetricCollector<long>(testMeterFactory, "Microsoft.AspNetCore.MemoryPool", "aspnetcore.memorypool.evicted_memory");
319+
320+
var pool = new PinnedBlockMemoryPool(testMeterFactory);
321+
322+
// Fill the pool with some blocks
323+
var blocks = new List<IMemoryOwner<byte>>();
324+
for (int i = 0; i < 10; i++)
325+
{
326+
blocks.Add(pool.Rent());
327+
}
328+
foreach (var block in blocks)
329+
{
330+
block.Dispose();
331+
}
332+
blocks.Clear();
333+
334+
Assert.Empty(evictMetric.GetMeasurementSnapshot());
335+
336+
// Eviction after returning everything to reset internal counters
337+
pool.PerformEviction();
338+
339+
// Trigger eviction
340+
pool.PerformEviction();
341+
342+
// At least some blocks should be evicted, each eviction records block size
343+
Assert.NotEmpty(evictMetric.GetMeasurementSnapshot());
344+
foreach (var measurement in evictMetric.GetMeasurementSnapshot())
345+
{
346+
Assert.Equal(PinnedBlockMemoryPool.BlockSize, measurement.Value);
347+
}
348+
}
349+
350+
// Smoke test to ensure that metrics are aggregated across multiple pools if the same meter factory is used
351+
[Fact]
352+
public void MetricsAreAggregatedAcrossPoolsWithSameMeterFactory()
353+
{
354+
var testMeterFactory = new TestMeterFactory();
355+
using var rentMetric = new MetricCollector<long>(testMeterFactory, "Microsoft.AspNetCore.MemoryPool", "aspnetcore.memorypool.total_rented");
356+
357+
var pool1 = new PinnedBlockMemoryPool(testMeterFactory);
358+
var pool2 = new PinnedBlockMemoryPool(testMeterFactory);
359+
360+
var mem1 = pool1.Rent();
361+
var mem2 = pool2.Rent();
362+
363+
// Both pools should contribute to the same metric stream
364+
Assert.Equal(2 * PinnedBlockMemoryPool.BlockSize, rentMetric.GetMeasurementSnapshot().EvaluateAsCounter());
365+
366+
mem1.Dispose();
367+
mem2.Dispose();
368+
369+
// Renting and returning from both pools should not interfere with metric collection
370+
var mem3 = pool1.Rent();
371+
var mem4 = pool2.Rent();
372+
373+
Assert.Equal(4 * PinnedBlockMemoryPool.BlockSize, rentMetric.GetMeasurementSnapshot().EvaluateAsCounter());
374+
375+
mem3.Dispose();
376+
mem4.Dispose();
377+
}
223378
}

src/Servers/Kestrel/Transport.NamedPipes/src/Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<Compile Include="$(KestrelSharedSourceRoot)\TransportConnection.cs" Link="Internal\TransportConnection.cs" />
2222
<Compile Include="$(KestrelSharedSourceRoot)\TransportConnection.Generated.cs" Link="Internal\TransportConnection.Generated.cs" />
2323
<Compile Include="$(KestrelSharedSourceRoot)\TransportConnection.FeatureCollection.cs" Link="Internal\TransportConnection.FeatureCollection.cs" />
24-
<Compile Include="$(KestrelSharedSourceRoot)\DefaultMemoryPoolFactory.cs" Link="Internal\DefaultMemoryPoolFactory.cs" />
24+
<Compile Include="$(KestrelSharedSourceRoot)\DefaultSimpleMemoryPoolFactory.cs" Link="Internal\DefaultSimpleMemoryPoolFactory.cs" />
2525
</ItemGroup>
2626

2727
<ItemGroup>

src/Servers/Kestrel/Transport.NamedPipes/src/NamedPipeTransportOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,5 +117,5 @@ public static NamedPipeServerStream CreateDefaultNamedPipeServerStream(CreateNam
117117
}
118118
}
119119

120-
internal IMemoryPoolFactory<byte> MemoryPoolFactory { get; set; } = DefaultMemoryPoolFactory.Instance;
120+
internal IMemoryPoolFactory<byte> MemoryPoolFactory { get; set; } = DefaultSimpleMemoryPoolFactory.Instance;
121121
}

src/Servers/Kestrel/Transport.NamedPipes/src/WebHostBuilderNamedPipeExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System.Runtime.Versioning;
55
using Microsoft.AspNetCore.Connections;
6-
using Microsoft.AspNetCore.Server.Kestrel.Internal;
76
using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes;
87
using Microsoft.AspNetCore.Server.Kestrel.Transport.NamedPipes.Internal;
98
using Microsoft.Extensions.DependencyInjection;

src/Servers/Kestrel/Transport.Sockets/src/Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
<Compile Include="$(KestrelSharedSourceRoot)\TransportConnection.cs" Link="Internal\TransportConnection.cs" />
1818
<Compile Include="$(KestrelSharedSourceRoot)\TransportConnection.Generated.cs" Link="Internal\TransportConnection.Generated.cs" />
1919
<Compile Include="$(KestrelSharedSourceRoot)\TransportConnection.FeatureCollection.cs" Link="Internal\TransportConnection.FeatureCollection.cs" />
20-
<Compile Include="$(KestrelSharedSourceRoot)\DefaultMemoryPoolFactory.cs" Link="Internal\DefaultMemoryPoolFactory.cs" />
20+
<Compile Include="$(KestrelSharedSourceRoot)\DefaultSimpleMemoryPoolFactory.cs" Link="Internal\DefaultSimpleMemoryPoolFactory.cs" />
2121
</ItemGroup>
2222

2323
<ItemGroup>

src/Servers/Kestrel/Transport.Sockets/src/SocketConnectionFactoryOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,5 +68,5 @@ internal SocketConnectionFactoryOptions(SocketTransportOptions transportOptions)
6868
/// </remarks>
6969
public bool UnsafePreferInlineScheduling { get; set; }
7070

71-
internal IMemoryPoolFactory<byte> MemoryPoolFactory { get; set; } = DefaultMemoryPoolFactory.Instance;
71+
internal IMemoryPoolFactory<byte> MemoryPoolFactory { get; set; } = DefaultSimpleMemoryPoolFactory.Instance;
7272
}

0 commit comments

Comments
 (0)