diff --git a/.gitignore b/.gitignore index 17b16704..b54a2840 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,7 @@ artifacts/ .DS_Store *.snupkg + +# BenchmarkDotNet artifacts +BenchmarkDotNet.Artifacts/ +**/BenchmarkDotNet.Artifacts/ diff --git a/Directory.Packages.props b/Directory.Packages.props index d5994bd7..66af49ca 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,5 +1,6 @@ + diff --git a/tests/SharpCompress.Performance/ArchiveReadBenchmarks.cs b/tests/SharpCompress.Performance/ArchiveReadBenchmarks.cs new file mode 100644 index 00000000..1f9d6cfd --- /dev/null +++ b/tests/SharpCompress.Performance/ArchiveReadBenchmarks.cs @@ -0,0 +1,86 @@ +using System.IO; +using System.Linq; +using BenchmarkDotNet.Attributes; +using SharpCompress.Archives; + +namespace SharpCompress.Performance; + +/// +/// Benchmarks for Archive API operations across different formats. +/// Archive API is used for random access to entries with seekable streams. +/// +[MemoryDiagnoser] +public class ArchiveReadBenchmarks : BenchmarkBase +{ + [Benchmark] + public void ZipArchiveRead() + { + var path = GetTestArchivePath("Zip.deflate.zip"); + using var archive = ArchiveFactory.Open(path); + foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) + { + using var stream = entry.OpenEntryStream(); + stream.CopyTo(Stream.Null); + } + } + + [Benchmark] + public void TarArchiveRead() + { + var path = GetTestArchivePath("Tar.tar"); + using var archive = ArchiveFactory.Open(path); + foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) + { + using var stream = entry.OpenEntryStream(); + stream.CopyTo(Stream.Null); + } + } + + [Benchmark] + public void TarGzArchiveRead() + { + var path = GetTestArchivePath("Tar.tar.gz"); + using var archive = ArchiveFactory.Open(path); + foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) + { + using var stream = entry.OpenEntryStream(); + stream.CopyTo(Stream.Null); + } + } + + [Benchmark] + public void TarBz2ArchiveRead() + { + var path = GetTestArchivePath("Tar.tar.bz2"); + using var archive = ArchiveFactory.Open(path); + foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) + { + using var stream = entry.OpenEntryStream(); + stream.CopyTo(Stream.Null); + } + } + + [Benchmark] + public void SevenZipArchiveRead() + { + var path = GetTestArchivePath("7Zip.LZMA2.7z"); + using var archive = ArchiveFactory.Open(path); + foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) + { + using var stream = entry.OpenEntryStream(); + stream.CopyTo(Stream.Null); + } + } + + [Benchmark] + public void RarArchiveRead() + { + var path = GetTestArchivePath("Rar.rar"); + using var archive = ArchiveFactory.Open(path); + foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) + { + using var stream = entry.OpenEntryStream(); + stream.CopyTo(Stream.Null); + } + } +} diff --git a/tests/SharpCompress.Performance/BaselineComparisonBenchmarks.cs b/tests/SharpCompress.Performance/BaselineComparisonBenchmarks.cs new file mode 100644 index 00000000..3907858f --- /dev/null +++ b/tests/SharpCompress.Performance/BaselineComparisonBenchmarks.cs @@ -0,0 +1,47 @@ +using System.IO; +using System.Linq; +using BenchmarkDotNet.Attributes; +using SharpCompress.Archives; + +namespace SharpCompress.Performance; + +/// +/// Benchmarks comparing current code against a baseline. +/// Use [Baseline] attribute to mark the reference benchmark. +/// +[MemoryDiagnoser] +[RankColumn] +public class BaselineComparisonBenchmarks : BenchmarkBase +{ + /// + /// Baseline benchmark for Zip archive reading. + /// This serves as the reference point for comparison. + /// + [Benchmark(Baseline = true)] + public void ZipArchiveRead_Baseline() + { + var path = GetTestArchivePath("Zip.deflate.zip"); + using var archive = ArchiveFactory.Open(path); + foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) + { + using var stream = entry.OpenEntryStream(); + stream.CopyTo(Stream.Null); + } + } + + /// + /// Current implementation benchmark for Zip archive reading. + /// BenchmarkDotNet will compare this against the baseline. + /// + [Benchmark] + public void ZipArchiveRead_Current() + { + var path = GetTestArchivePath("Zip.deflate.zip"); + using var archive = ArchiveFactory.Open(path); + foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) + { + using var stream = entry.OpenEntryStream(); + stream.CopyTo(Stream.Null); + } + } +} diff --git a/tests/SharpCompress.Performance/BenchmarkBase.cs b/tests/SharpCompress.Performance/BenchmarkBase.cs new file mode 100644 index 00000000..6d9c3388 --- /dev/null +++ b/tests/SharpCompress.Performance/BenchmarkBase.cs @@ -0,0 +1,37 @@ +using System; +using System.IO; + +namespace SharpCompress.Performance; + +/// +/// Base class for all benchmarks providing common setup for test archives path +/// +public class BenchmarkBase +{ + protected readonly string TEST_ARCHIVES_PATH; + + public BenchmarkBase() + { + var index = AppDomain.CurrentDomain.BaseDirectory.IndexOf( + "SharpCompress.Performance", + StringComparison.OrdinalIgnoreCase + ); + + if (index == -1) + { + throw new InvalidOperationException( + "Could not locate SharpCompress.Performance in the base directory path" + ); + } + + var path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, index); + var solutionBasePath = + Path.GetDirectoryName(path) + ?? throw new InvalidOperationException("Could not determine solution base path"); + + TEST_ARCHIVES_PATH = Path.Combine(solutionBasePath, "TestArchives", "Archives"); + } + + protected string GetTestArchivePath(string filename) => + Path.Combine(TEST_ARCHIVES_PATH, filename); +} diff --git a/tests/SharpCompress.Performance/Program.cs b/tests/SharpCompress.Performance/Program.cs index d445208a..1d695b01 100644 --- a/tests/SharpCompress.Performance/Program.cs +++ b/tests/SharpCompress.Performance/Program.cs @@ -1,54 +1,16 @@ -using System; -using System.IO; -using System.Linq; -using System.Threading.Tasks; -using SharpCompress.Archives; -using SharpCompress.Performance; -using SharpCompress.Readers; -using SharpCompress.Test; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Running; -var index = AppDomain.CurrentDomain.BaseDirectory.IndexOf( - "SharpCompress.Performance", - StringComparison.OrdinalIgnoreCase -); -var path = AppDomain.CurrentDomain.BaseDirectory.Substring(0, index); -var SOLUTION_BASE_PATH = Path.GetDirectoryName(path) ?? throw new ArgumentNullException(); +namespace SharpCompress.Performance; -var TEST_ARCHIVES_PATH = Path.Combine(SOLUTION_BASE_PATH, "TestArchives", "Archives"); - -//using var _ = JetbrainsProfiler.Memory($"/Users/adam/temp/"); -using (var __ = JetbrainsProfiler.Cpu($"/Users/adam/temp/")) +internal class Program { - var testArchives = new[] + static void Main(string[] args) { - "Rar.Audio_program.rar", + // Run all benchmarks in the assembly + var config = DefaultConfig.Instance; - //"64bitstream.zip.7z", - //"TarWithSymlink.tar.gz" - }; - var arcs = testArchives.Select(a => Path.Combine(TEST_ARCHIVES_PATH, a)).ToArray(); - - for (int i = 0; i < 50; i++) - { - using var found = ArchiveFactory.Open(arcs[0]); - foreach (var entry in found.Entries.Where(entry => !entry.IsDirectory)) - { - Console.WriteLine($"Extracting {entry.Key}"); - using var entryStream = entry.OpenEntryStream(); - entryStream.CopyTo(Stream.Null); - } - /*using var found = ReaderFactory.Open(arcs[0]); - while (found.MoveToNextEntry()) - { - var entry = found.Entry; - if (entry.IsDirectory) - continue; - - Console.WriteLine($"Extracting {entry.Key}"); - found.WriteEntryTo(Stream.Null); - }*/ + // BenchmarkRunner will find all classes with [Benchmark] attributes + BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, config); } - - Console.WriteLine("Still running..."); } -await Task.Delay(500); diff --git a/tests/SharpCompress.Performance/README.md b/tests/SharpCompress.Performance/README.md new file mode 100644 index 00000000..9dfc12dc --- /dev/null +++ b/tests/SharpCompress.Performance/README.md @@ -0,0 +1,131 @@ +# SharpCompress Performance Benchmarks + +This project uses [BenchmarkDotNet](https://benchmarkdotnet.org/) to measure and track performance of SharpCompress archive operations. + +## Running Benchmarks + +### Run All Benchmarks +```bash +cd tests/SharpCompress.Performance +dotnet run -c Release +``` + +### Run Specific Benchmark Classes +```bash +# Run only Archive API benchmarks +dotnet run -c Release -- --filter "*ArchiveReadBenchmarks*" + +# Run only Reader API benchmarks +dotnet run -c Release -- --filter "*ReaderBenchmarks*" +``` + +### Run Specific Benchmark Methods +```bash +# Run only Zip benchmarks +dotnet run -c Release -- --filter "*Zip*" + +# Run a specific method +dotnet run -c Release -- --filter "ArchiveReadBenchmarks.ZipArchiveRead" +``` + +### Quick Dry Run (for testing) +```bash +dotnet run -c Release -- --job dry +``` + +## Benchmark Categories + +### ArchiveReadBenchmarks +Tests the **Archive API** which provides random access to entries with seekable streams. Covers: +- Zip (deflate compression) +- Tar (uncompressed) +- Tar.gz (gzip compression) +- Tar.bz2 (bzip2 compression) +- 7Zip (LZMA2 compression) +- Rar + +### ReaderBenchmarks +Tests the **Reader API** which provides forward-only streaming for non-seekable streams. Covers: +- Zip +- Tar +- Tar.gz +- Tar.bz2 +- Rar + +### WriteBenchmarks +Tests the **Writer API** for creating archives using forward-only writing. Covers: +- Zip (deflate compression) +- Tar (uncompressed) +- Tar.gz (gzip compression) + +### BaselineComparisonBenchmarks +Example benchmark showing how to compare implementations using the `[Baseline]` attribute. The baseline benchmark serves as a reference point, and BenchmarkDotNet calculates the ratio of performance between baseline and other methods. + +## Comparing Against Previous Versions + +### Using Baseline Attribute +Mark one benchmark with `[Baseline = true]` and BenchmarkDotNet will show relative performance: + +```csharp +[Benchmark(Baseline = true)] +public void MethodA() { /* ... */ } + +[Benchmark] +public void MethodB() { /* ... */ } +``` + +Results will show ratios like "1.5x slower" or "0.8x faster" compared to the baseline. + +### Using BenchmarkDotNet.Artifacts for Historical Comparison +BenchmarkDotNet saves results to `BenchmarkDotNet.Artifacts/results/`. You can: + +1. Run benchmarks and save the results +2. Keep a snapshot of the results file +3. Compare new runs against saved results + +### Using Different NuGet Versions (Advanced) +To compare against a published NuGet package: + +1. Create a separate benchmark project referencing the NuGet package +2. Use BenchmarkDotNet's `[SimpleJob]` attribute with different runtimes +3. Reference both the local project and NuGet package in different jobs + +## Interpreting Results + +BenchmarkDotNet provides: +- **Mean**: Average execution time +- **Error**: Half of 99.9% confidence interval +- **StdDev**: Standard deviation of measurements +- **Allocated**: Memory allocated per operation +- **Rank**: Relative ranking (when using `[RankColumn]`) +- **Ratio**: Relative performance vs baseline (when using `[Baseline]`) + +## Output Artifacts + +Results are saved to `BenchmarkDotNet.Artifacts/results/`: +- `*.csv`: Raw data for further analysis +- `*-report.html`: HTML report with charts +- `*-report-github.md`: Markdown report for GitHub +- `*.log`: Detailed execution log + +## Best Practices + +1. **Always run in Release mode**: Debug builds have significant overhead +2. **Close other applications**: Minimize system noise during benchmarks +3. **Run multiple times**: Look for consistency across runs +4. **Use appropriate workload**: Ensure benchmarks run for at least 100ms +5. **Track trends**: Compare results over time to detect regressions +6. **Archive results**: Keep snapshots of benchmark results for historical comparison + +## CI/CD Integration + +Consider adding benchmarks to CI/CD to: +- Detect performance regressions automatically +- Track performance trends over time +- Compare PR performance against main branch + +## Additional Resources + +- [BenchmarkDotNet Documentation](https://benchmarkdotnet.org/articles/overview.html) +- [BenchmarkDotNet Configuration](https://benchmarkdotnet.org/articles/configs/configs.html) +- [BenchmarkDotNet Baseline](https://benchmarkdotnet.org/articles/features/baselines.html) diff --git a/tests/SharpCompress.Performance/ReaderBenchmarks.cs b/tests/SharpCompress.Performance/ReaderBenchmarks.cs new file mode 100644 index 00000000..639f785b --- /dev/null +++ b/tests/SharpCompress.Performance/ReaderBenchmarks.cs @@ -0,0 +1,88 @@ +using System.IO; +using BenchmarkDotNet.Attributes; +using SharpCompress.Readers; + +namespace SharpCompress.Performance; + +/// +/// Benchmarks for Reader API operations across different formats. +/// Reader API is used for forward-only streaming with non-seekable streams. +/// +[MemoryDiagnoser] +public class ReaderBenchmarks : BenchmarkBase +{ + [Benchmark] + public void ZipReaderRead() + { + var path = GetTestArchivePath("Zip.deflate.zip"); + using var stream = File.OpenRead(path); + using var reader = ReaderFactory.Open(stream); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryTo(Stream.Null); + } + } + } + + [Benchmark] + public void TarReaderRead() + { + var path = GetTestArchivePath("Tar.tar"); + using var stream = File.OpenRead(path); + using var reader = ReaderFactory.Open(stream); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryTo(Stream.Null); + } + } + } + + [Benchmark] + public void TarGzReaderRead() + { + var path = GetTestArchivePath("Tar.tar.gz"); + using var stream = File.OpenRead(path); + using var reader = ReaderFactory.Open(stream); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryTo(Stream.Null); + } + } + } + + [Benchmark] + public void TarBz2ReaderRead() + { + var path = GetTestArchivePath("Tar.tar.bz2"); + using var stream = File.OpenRead(path); + using var reader = ReaderFactory.Open(stream); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryTo(Stream.Null); + } + } + } + + [Benchmark] + public void RarReaderRead() + { + var path = GetTestArchivePath("Rar.rar"); + using var stream = File.OpenRead(path); + using var reader = ReaderFactory.Open(stream); + while (reader.MoveToNextEntry()) + { + if (!reader.Entry.IsDirectory) + { + reader.WriteEntryTo(Stream.Null); + } + } + } +} diff --git a/tests/SharpCompress.Performance/SharpCompress.Performance.csproj b/tests/SharpCompress.Performance/SharpCompress.Performance.csproj index cab757e4..d4ad46d2 100644 --- a/tests/SharpCompress.Performance/SharpCompress.Performance.csproj +++ b/tests/SharpCompress.Performance/SharpCompress.Performance.csproj @@ -4,6 +4,7 @@ net10.0 + diff --git a/tests/SharpCompress.Performance/WriteBenchmarks.cs b/tests/SharpCompress.Performance/WriteBenchmarks.cs new file mode 100644 index 00000000..02c69a36 --- /dev/null +++ b/tests/SharpCompress.Performance/WriteBenchmarks.cs @@ -0,0 +1,106 @@ +using System.IO; +using System.Linq; +using BenchmarkDotNet.Attributes; +using SharpCompress.Common; +using SharpCompress.Writers; + +namespace SharpCompress.Performance; + +/// +/// Benchmarks for Writer operations. +/// Tests creating archives with different compression formats using forward-only Writer API. +/// +[MemoryDiagnoser] +public class WriteBenchmarks : BenchmarkBase +{ + private string _tempOutputPath = null!; + private string[] _testFiles = null!; + + [GlobalSetup] + public void Setup() + { + _tempOutputPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(_tempOutputPath); + + // Get some test files to compress + var originalPath = Path.Combine(Path.GetDirectoryName(TEST_ARCHIVES_PATH)!, "Original"); + if (Directory.Exists(originalPath)) + { + _testFiles = Directory.GetFiles(originalPath).Take(5).ToArray(); + } + else + { + _testFiles = []; + } + } + + [IterationCleanup] + public void IterationCleanup() + { + // Clean up created archives after each iteration to avoid file reuse affecting measurements + if (Directory.Exists(_tempOutputPath)) + { + foreach (var file in Directory.GetFiles(_tempOutputPath)) + { + File.Delete(file); + } + } + } + + [GlobalCleanup] + public void Cleanup() + { + if (Directory.Exists(_tempOutputPath)) + { + Directory.Delete(_tempOutputPath, true); + } + } + + [Benchmark] + public void ZipWriterWrite() + { + var outputFile = Path.Combine(_tempOutputPath, "test.zip"); + using var stream = File.Create(outputFile); + using var writer = WriterFactory.Open( + stream, + ArchiveType.Zip, + new WriterOptions(CompressionType.Deflate) + ); + foreach (var file in _testFiles) + { + writer.Write(Path.GetFileName(file), file); + } + } + + [Benchmark] + public void TarWriterWrite() + { + var outputFile = Path.Combine(_tempOutputPath, "test.tar"); + using var stream = File.Create(outputFile); + using var writer = WriterFactory.Open( + stream, + ArchiveType.Tar, + new WriterOptions(CompressionType.None) + ); + foreach (var file in _testFiles) + { + writer.Write(Path.GetFileName(file), file); + } + } + + [Benchmark] + public void TarGzWriterWrite() + { + var outputFile = Path.Combine(_tempOutputPath, "test.tar.gz"); + using var stream = File.Create(outputFile); + using var writer = WriterFactory.Open( + stream, + ArchiveType.Tar, + new WriterOptions(CompressionType.GZip) + ); + foreach (var file in _testFiles) + { + writer.Write(Path.GetFileName(file), file); + } + } +} diff --git a/tests/SharpCompress.Performance/packages.lock.json b/tests/SharpCompress.Performance/packages.lock.json index 12a15aa7..3516ef08 100644 --- a/tests/SharpCompress.Performance/packages.lock.json +++ b/tests/SharpCompress.Performance/packages.lock.json @@ -2,6 +2,24 @@ "version": 2, "dependencies": { "net10.0": { + "BenchmarkDotNet": { + "type": "Direct", + "requested": "[0.14.0, )", + "resolved": "0.14.0", + "contentHash": "eIPSDKi3oni734M1rt/XJAwGQQOIf9gLjRRKKJ0HuVy3vYd7gnmAIX1bTjzI9ZbAY/nPddgqqgM/TeBYitMCIg==", + "dependencies": { + "BenchmarkDotNet.Annotations": "0.14.0", + "CommandLineParser": "2.9.1", + "Gee.External.Capstone": "2.3.0", + "Iced": "1.17.0", + "Microsoft.CodeAnalysis.CSharp": "4.1.0", + "Microsoft.Diagnostics.Runtime": "2.2.332302", + "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.8", + "Microsoft.DotNet.PlatformAbstractions": "3.1.6", + "Perfolizer": "[0.3.17]", + "System.Management": "5.0.0" + } + }, "JetBrains.Profiler.SelfApi": { "type": "Direct", "requested": "[2.5.15, )", @@ -37,6 +55,26 @@ "resolved": "17.14.15", "contentHash": "mXQPJsbuUD2ydq4/ffd8h8tSOFCXec+2xJOVNCvXjuMOq/+5EKHq3D2m2MC2+nUaXeFMSt66VS/J4HdKBixgcw==" }, + "BenchmarkDotNet.Annotations": { + "type": "Transitive", + "resolved": "0.14.0", + "contentHash": "CUDCg6bgHrDzhjnA+IOBl5gAo8Y5hZ2YSs7MBXrYMlMKpBZqrD5ez0537uDveOkcf+YWAoK+S4sMcuWPbIz8bw==" + }, + "CommandLineParser": { + "type": "Transitive", + "resolved": "2.9.1", + "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA==" + }, + "Gee.External.Capstone": { + "type": "Transitive", + "resolved": "2.3.0", + "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw==" + }, + "Iced": { + "type": "Transitive", + "resolved": "1.17.0", + "contentHash": "8x+HCVTl/HHTGpscH3vMBhV8sknN/muZFw9s3TsI8SA6+c43cOTCi2+jE4KsU8pNLbJ++iF2ZFcpcXHXtDglnw==" + }, "JetBrains.FormatRipper": { "type": "Transitive", "resolved": "2.4.0", @@ -63,6 +101,118 @@ "resolved": "8.0.0", "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ==" }, + "Microsoft.CodeAnalysis.Analyzers": { + "type": "Transitive", + "resolved": "3.3.3", + "contentHash": "j/rOZtLMVJjrfLRlAMckJLPW/1rze9MT1yfWqSIbUPGRu1m1P0fuo9PmqapwsmePfGB5PJrudQLvmUOAMF0DqQ==" + }, + "Microsoft.CodeAnalysis.Common": { + "type": "Transitive", + "resolved": "4.1.0", + "contentHash": "bNzTyxP3iD5FPFHfVDl15Y6/wSoI7e3MeV0lOaj9igbIKTjgrmuw6LoVJ06jUNFA7+KaDC/OIsStWl/FQJz6sQ==", + "dependencies": { + "Microsoft.CodeAnalysis.Analyzers": "3.3.3" + } + }, + "Microsoft.CodeAnalysis.CSharp": { + "type": "Transitive", + "resolved": "4.1.0", + "contentHash": "sbu6kDGzo9bfQxuqWpeEE7I9P30bSuZEnpDz9/qz20OU6pm79Z63+/BsAzO2e/R/Q97kBrpj647wokZnEVr97w==", + "dependencies": { + "Microsoft.CodeAnalysis.Common": "[4.1.0]" + } + }, + "Microsoft.Diagnostics.NETCore.Client": { + "type": "Transitive", + "resolved": "0.2.251802", + "contentHash": "bqnYl6AdSeboeN4v25hSukK6Odm6/54E3Y2B8rBvgqvAW0mF8fo7XNRVE2DMOG7Rk0fiuA079QIH28+V+W1Zdg==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "1.1.0", + "Microsoft.Extensions.Logging": "2.1.1" + } + }, + "Microsoft.Diagnostics.Runtime": { + "type": "Transitive", + "resolved": "2.2.332302", + "contentHash": "Hp84ivxSKIMTBzYSATxmUsm3YSXHWivcwiRRbsydGmqujMUK8BAueLN0ssAVEOkOBmh0vjUBhrq7YcroT7VCug==", + "dependencies": { + "Microsoft.Diagnostics.NETCore.Client": "0.2.251802" + } + }, + "Microsoft.Diagnostics.Tracing.TraceEvent": { + "type": "Transitive", + "resolved": "3.1.8", + "contentHash": "kl3UMrZKSeSEYZ8rt/GjLUQToREjgQABqfg6PzQBmSlYHTZOKE9ePEOS2xptROQ9SVvngg3QGX51TIT11iZ0wA==" + }, + "Microsoft.DotNet.PlatformAbstractions": { + "type": "Transitive", + "resolved": "3.1.6", + "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg==" + }, + "Microsoft.Extensions.Configuration": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "LjVKO6P2y52c5ZhTLX/w8zc5H4Y3J/LJsgqTBj49TtFq/hAtVNue/WA0F6/7GMY90xhD7K0MDZ4qpOeWXbLvzg==", + "dependencies": { + "Microsoft.Extensions.Configuration.Abstractions": "2.1.1" + } + }, + "Microsoft.Extensions.Configuration.Abstractions": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "VfuZJNa0WUshZ/+8BFZAhwFKiKuu/qOUCFntfdLpHj7vcRnsGHqd3G2Hse78DM+pgozczGM63lGPRLmy+uhUOA==", + "dependencies": { + "Microsoft.Extensions.Primitives": "2.1.1" + } + }, + "Microsoft.Extensions.Configuration.Binder": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "fcLCTS03poWE4v9tSNBr3pWn0QwGgAn1vzqHXlXgvqZeOc7LvQNzaWcKRQZTdEc3+YhQKwMsOtm3VKSA2aWQ8w==", + "dependencies": { + "Microsoft.Extensions.Configuration": "2.1.1" + } + }, + "Microsoft.Extensions.DependencyInjection.Abstractions": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "MgYpU5cwZohUMKKg3sbPhvGG+eAZ/59E9UwPwlrUkyXU+PGzqwZg9yyQNjhxuAWmoNoFReoemeCku50prYSGzA==" + }, + "Microsoft.Extensions.Logging": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "hh+mkOAQDTp6XH80xJt3+wwYVzkbwYQl9XZRCz4Um0JjP/o7N9vHM3rZ6wwwtr+BBe/L6iBO2sz0px6OWBzqZQ==", + "dependencies": { + "Microsoft.Extensions.Configuration.Binder": "2.1.1", + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.1.1", + "Microsoft.Extensions.Logging.Abstractions": "2.1.1", + "Microsoft.Extensions.Options": "2.1.1" + } + }, + "Microsoft.Extensions.Logging.Abstractions": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "XRzK7ZF+O6FzdfWrlFTi1Rgj2080ZDsd46vzOjadHUB0Cz5kOvDG8vI7caa5YFrsHQpcfn0DxtjS4E46N4FZsA==" + }, + "Microsoft.Extensions.Options": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "V7lXCU78lAbzaulCGFKojcCyG8RTJicEbiBkPJjFqiqXwndEBBIehdXRMWEVU3UtzQ1yDvphiWUL9th6/4gJ7w==", + "dependencies": { + "Microsoft.Extensions.DependencyInjection.Abstractions": "2.1.1", + "Microsoft.Extensions.Primitives": "2.1.1" + } + }, + "Microsoft.Extensions.Primitives": { + "type": "Transitive", + "resolved": "2.1.1", + "contentHash": "scJ1GZNIxMmjpENh0UZ8XCQ6vzr/LzeF9WvEA51Ix2OQGAs9WPgPu8ABVUdvpKPLuor/t05gm6menJK3PwqOXg==" + }, + "Microsoft.NETCore.Platforms": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" + }, "Microsoft.NETFramework.ReferenceAssemblies.net461": { "type": "Transitive", "resolved": "1.0.3", @@ -73,8 +223,33 @@ "resolved": "8.0.0", "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw==" }, + "Perfolizer": { + "type": "Transitive", + "resolved": "0.3.17", + "contentHash": "FQgtCoF2HFwvzKWulAwBS5BGLlh8pgbrJtOp47jyBwh2CW16juVtacN1azOA2BqdrJXkXTNLNRMo7ZlHHiuAnA==" + }, + "System.CodeDom": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "JPJArwA1kdj8qDAkY2XGjSWoYnqiM7q/3yRNkt6n28Mnn95MuEGkZXUbPBf7qc3IjwrGY5ttQon7yqHZyQJmOQ==" + }, + "System.Management": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "MF1CHaRcC+MLFdnDthv4/bKWBZnlnSpkGqa87pKukQefgEdwtb9zFW6zs0GjPp73qtpYYg4q6PEKbzJbxCpKfw==", + "dependencies": { + "Microsoft.NETCore.Platforms": "5.0.0", + "System.CodeDom": "5.0.0" + } + }, "sharpcompress": { "type": "Project" + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "CentralTransitive", + "requested": "[10.0.0, )", + "resolved": "1.1.0", + "contentHash": "1Am6l4Vpn3/K32daEqZI+FFr96OlZkgwK2LcT3pZ2zWubR5zTPW3/FkO1Rat9kb7oQOa4rxgl9LJHc5tspCWfg==" } } }