dotnet / BenchmarkDotNet

Powerful .NET library for benchmarking
https://benchmarkdotnet.org
MIT License
10.56k stars 969 forks source link

PathTooLongException with benchmark that has long parameter #2093

Open jakobbotsch opened 2 years ago

jakobbotsch commented 2 years ago

The following invocation in dotnet/performance:

dotnet run -c Release -f net7.0 -- --filter "System.Numerics.Tests.Perf_BigInteger.Parse" --corerun /mnt/c/dev/dotnet/core_roots/cf2187_release/corerun -p EP

hangs on a benchmark with a very long parameter. When I ctrl-C it, I get the following:

An exception occurred during reading trace stream: System.IO.PathTooLongException: The path '/home/jakob/dev/dotnet/performance/artifacts/bin/MicroBenchmarks/Release/net7.0/BenchmarkDotNet.Artifacts/System.Numerics.Tests.Perf_BigInteger.Parse(numberString_ 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890)-20220830-133655.nettrace' is too long, or a component of the specified path is too long.
   at Interop.ThrowExceptionForIoErrno(ErrorInfo errorInfo, String path, Boolean isDirError)
   at Microsoft.Win32.SafeHandles.SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, UnixFileMode openPermissions, Int64& fileLength, UnixFileMode& filePermissions, Func`4 createOpenException)
   at System.IO.Strategies.OSFileStreamStrategy..ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize, Nullable`1 unixCreateMode)
   at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access)
   at BenchmarkDotNet.Diagnosers.EventPipeProfiler.CopyEventStreamToFile(EventPipeSession session, String fileName, ILogger logger)
ExitCode != 0 and no results reported

Seems like BDN is trying to include all the parameters in the file name of the event pipe trace.

adamsitnik commented 2 years ago

Hi @jakobbotsch

Thank you for detailed bug report.

I currently don't have the time to look at, so I am going to make it "up-for-grabs" hoping that someone else will. The bug is somewhere in the following method: https://github.com/dotnet/BenchmarkDotNet/blob/master/src/BenchmarkDotNet/Helpers/ArtifactFileNameHelper.cs#L18

To work around this bug you need get rid of [Arguments/ArgumentsSource/Params/ParamsSource] usage. Example:

private readonly BigIntegerData arg1 = new BigIntegerData("123");
private readonly BigIntegerData arg2 = new BigIntegerData(int.MinValue.ToString());
private readonly BigIntegerData arg2 = new BigIntegerData(string.Concat(Enumerable.Repeat("1234567890", 20)));

[Benchmark] public BigInteger Parse1() => BigInteger.Parse(arg1.Text);
[Benchmark] public BigInteger Parse2() => BigInteger.Parse(arg2.Text);
[Benchmark] public BigInteger Parse2() => BigInteger.Parse(arg3.Text);
dotnet run -c Release -f net7.0 -- --filter "System.Numerics.Tests.Perf_BigInteger.Parse*" --corerun /mnt/c/dev/dotnet/core_roots/cf2187_release/corerun -p EP
SeanFarrow commented 2 years ago

@adamsitnik I'd be interested in working on this. How far away is 0.13.3?

SeanFarrow commented 2 years ago

@jakobbotsch Which directory were you running this in specifically? did you have any docker container or mounts set up?

jakobbotsch commented 2 years ago

I think I was running the command inside /home/jakob/dev/dotnet/perforamnce/src/benchmarks/micro.

adamsitnik commented 2 years ago

I'd be interested in working on this.

@SeanFarrow great, I've assigned you.

How far away is 0.13.3?

I would like to release it within a month, as it's going to contain some important bugfixes.

SeanFarrow commented 2 years ago

@adamsitnik Thanks, I'll start work this weekend.

What do we want as the behaviour if the path is too long? Currently as per the bug report, we are thrrowing an exception, short we just shorten th path to somethingthat is acceptable? Finally, wha is the easiest way of debugging a benchmark, assuming I'm running using corerun?

saad995 commented 2 years ago

is this still an open/unresolved issue?

SeanFarrow commented 2 years ago

@adamsitnik @saad995 It will be in the next few minutes, unfortunately, we have a family illness/emergency meaning I can't do as much outside of work as I would like.

Do you want me to push my branch with some tests?

Thanks, Sean.

saad995 commented 2 years ago

@SeanFarrow yes please, that would be helpful...I will look into it tomorrow. if it's possible for me to continue on this fix I will let you guys know.

SeanFarrow commented 2 years ago

@saad995 The fork is at: https://github.com/SeanFarrow/benchmarkdotnet.git the branch you want to start with is: bugfix/sf/2093-fix-path-too-long-exception I'll leave the fork there for a few days, so if you could let me know when you have it, I can then delete it.

Thanks, Sean.

timcassell commented 1 year ago

For whoever will work on this, it looks like Windows has an escape hatch for very long paths, but it requires parsing the path to make sure it has proper formatting manually. Pre-pending the path with \\?\ allows up to 32,767 characters instead of 260. See the StackOverflow answers for details. More Reading

Not sure if we want to go down that path (pun not intended).

[Edit] I am surprised it's failing on net7.0, as there are claims that long paths are automatically handled in Core already.

AndreyAkinshin commented 1 year ago

@timcassell since BenchmarkDotNet toolchains involve other tools (like MSBuild or profilers) and these tools may not support long paths, it doesn't make a lot of sense to introduce hacks with \\?\ to workaround the long path problem. I would suggest working on shortification of the existing paths we generate.

kant2002 commented 1 year ago

From what I see,

https://github.com/dotnet/BenchmarkDotNet/blob/6fa7a91444b01029cc2ed81c90e237ae3e36c595/src/BenchmarkDotNet/Helpers/ArtifactFileNameHelper.cs#L27-L31

The long names due to parameters already handled by code. My guess that observed issue is due to fact that code run under WSL, but mounted filesystem run under Windows. So BDN calculate path limit to 1024 characters, while FS supports only ~260.