Skip to content

Commit c6d6fb2

Browse files
authored
Fix Merge operation failed for EtwProfiler (#1545)
* we should consider trace file extension as part of the name * add failing test case * don't use long paths for file names, even if the Windows feature is enabled, fixes #1544 * update TraceEvent to the latest version * nit: user Assert.Range that gives a clear error message instead of a very general Assert.True * handle one more edge case
1 parent 152414b commit c6d6fb2

File tree

4 files changed

+96
-4
lines changed

4 files changed

+96
-4
lines changed

src/BenchmarkDotNet.Diagnostics.Windows/BenchmarkDotNet.Diagnostics.Windows.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@
1212
<ProjectReference Include="..\BenchmarkDotNet\BenchmarkDotNet.csproj" />
1313
</ItemGroup>
1414
<ItemGroup>
15-
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.57" PrivateAssets="contentfiles;analyzers" />
15+
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.61" PrivateAssets="contentfiles;analyzers" />
1616
</ItemGroup>
1717
</Project>

src/BenchmarkDotNet/BenchmarkDotNet.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.5.2" />
2828
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="2.10.0" />
2929
<PackageReference Include="Microsoft.Diagnostics.NETCore.Client" Version="0.2.61701" />
30-
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.57" PrivateAssets="contentfiles;analyzers" />
30+
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="2.0.61" PrivateAssets="contentfiles;analyzers" />
3131
</ItemGroup>
3232
<ItemGroup Condition="'$(OS)' == 'Windows_NT'">
3333
<ProjectReference Include="..\BenchmarkDotNet.Disassembler.x64\BenchmarkDotNet.Disassembler.x64.csproj">

src/BenchmarkDotNet/Helpers/ArtifactFileNameHelper.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using BenchmarkDotNet.Diagnosers;
55
using BenchmarkDotNet.Exporters;
66
using BenchmarkDotNet.Extensions;
7+
using BenchmarkDotNet.Portability;
78
using BenchmarkDotNet.Running;
89
using BenchmarkDotNet.Toolchains;
910

@@ -18,7 +19,11 @@ internal static string GetTraceFilePath(DiagnoserActionParameters details, DateT
1819
{
1920
string nameNoLimit = GetFilePathNoLimits(details, creationTime, fileExtension);
2021

21-
int limit = PathFeatures.AreAllLongPathsAvailable() ? CommonSenseLimit : WindowsOldPathLimit;
22+
// long paths can be enabled on Windows but it does not mean that ETW is going to work fine..
23+
// so we always use 260 as limit on Windows
24+
int limit = RuntimeInformation.IsWindows()
25+
? WindowsOldPathLimit - "userheap.etl".Length // the session files get merged, they need to have same name (without extension)
26+
: CommonSenseLimit;
2227

2328
if (nameNoLimit.Length <= limit)
2429
{
@@ -40,7 +45,7 @@ private static string GetLimitedFilePath(DiagnoserActionParameters details, Date
4045
string shortTypeName = FolderNameHelper.ToFolderName(details.BenchmarkCase.Descriptor.Type, includeNamespace: false);
4146
string methodName = details.BenchmarkCase.Descriptor.WorkloadMethod.Name;
4247
string parameters = details.BenchmarkCase.HasParameters
43-
? $"-hash{Hashing.HashString(FullNameProvider.GetMethodName(details.BenchmarkCase)).ToString()}"
48+
? $"-hash{Hashing.HashString(FullNameProvider.GetMethodName(details.BenchmarkCase))}"
4449
: string.Empty;
4550

4651
string fileName = $@"{shortTypeName}.{methodName}{parameters}";
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Configs;
3+
using BenchmarkDotNet.Diagnosers;
4+
using BenchmarkDotNet.Helpers;
5+
using BenchmarkDotNet.Running;
6+
using BenchmarkDotNet.Tests.XUnit;
7+
using System.Buffers.Tests;
8+
using System.Linq;
9+
using System.Threading.Tasks;
10+
using Xunit;
11+
12+
namespace BenchmarkDotNet.Tests
13+
{
14+
public class ArtifactFileNameHelperTests
15+
{
16+
[FactWindowsOnly(nonWindowsSkipReason: "ETW Sessions can be created only on Windows")]
17+
public void OnWindowsWeMustAlwaysUseOldLongPathsLimitForSessionFiles()
18+
{
19+
var config = DefaultConfig.Instance
20+
.WithArtifactsPath(@"C:\Projects\performance\artifacts\bin\MicroBenchmarks\Release\netcoreapp5.0\BenchmarkDotNet.Artifacts");
21+
22+
var benchmarkCase = BenchmarkConverter.TypeToBenchmarks(typeof(RentReturnArrayPoolTests<byte>), config).BenchmarksCases.First();
23+
24+
var parameters = new DiagnoserActionParameters(
25+
process: null,
26+
benchmarkCase: benchmarkCase,
27+
new BenchmarkId(0, benchmarkCase));
28+
29+
foreach (string fileExtension in new[] { "etl", "kernel.etl", "userheap.etl" })
30+
{
31+
var traceFilePath = ArtifactFileNameHelper.GetTraceFilePath(parameters, new System.DateTime(2020, 10, 1), fileExtension);
32+
33+
Assert.InRange(actual: traceFilePath.Length, low: 0, high: 260);
34+
}
35+
}
36+
}
37+
}
38+
39+
namespace System.Buffers.Tests
40+
{
41+
[GenericTypeArguments(typeof(byte))] // value type
42+
[GenericTypeArguments(typeof(object))] // reference type
43+
public class RentReturnArrayPoolTests<T>
44+
{
45+
private readonly ArrayPool<T> _createdPool = ArrayPool<T>.Create();
46+
private const int Iterations = 100_000;
47+
[Params(4096)]
48+
public int RentalSize;
49+
50+
[Params(false, true)]
51+
public bool ManipulateArray { get; set; }
52+
53+
[Params(false, true)]
54+
public bool Async { get; set; }
55+
56+
[Params(false, true)]
57+
public bool UseSharedPool { get; set; }
58+
59+
private ArrayPool<T> Pool => UseSharedPool ? ArrayPool<T>.Shared : _createdPool;
60+
61+
private static void Clear(T[] arr) => arr.AsSpan().Clear();
62+
63+
private static T IterateAll(T[] arr)
64+
{
65+
T ret = default;
66+
foreach (T item in arr)
67+
{
68+
ret = item;
69+
}
70+
return ret;
71+
}
72+
73+
[Benchmark(OperationsPerInvoke = Iterations)]
74+
public async Task SingleSerial()
75+
{
76+
ArrayPool<T> pool = Pool;
77+
for (int i = 0; i < Iterations; i++)
78+
{
79+
T[] arr = pool.Rent(RentalSize);
80+
if (ManipulateArray) Clear(arr);
81+
if (Async) await Task.Yield();
82+
if (ManipulateArray) IterateAll(arr);
83+
pool.Return(arr);
84+
}
85+
}
86+
}
87+
}

0 commit comments

Comments
 (0)