diff --git a/net/Azure.Storage.Blobs.PerfStress/Azure.Storage.Blobs.PerfStress.csproj b/net/Azure.Storage.Blobs.PerfStress/Azure.Storage.Blobs.PerfStress.csproj index 85dc8744d1c4..caa67e9bf36e 100644 --- a/net/Azure.Storage.Blobs.PerfStress/Azure.Storage.Blobs.PerfStress.csproj +++ b/net/Azure.Storage.Blobs.PerfStress/Azure.Storage.Blobs.PerfStress.csproj @@ -6,6 +6,12 @@ true + + + + + + diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/CircularStream.cs b/net/Azure.Storage.Blobs.PerfStress/Core/CircularStream.cs index 22eadca39abe..0ecb6509a4af 100644 --- a/net/Azure.Storage.Blobs.PerfStress/Core/CircularStream.cs +++ b/net/Azure.Storage.Blobs.PerfStress/Core/CircularStream.cs @@ -86,5 +86,11 @@ public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); } + + protected override void Dispose(bool disposing) + { + _innerStream.Dispose(); + base.Dispose(disposing); + } } } diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/ContainerTest.cs b/net/Azure.Storage.Blobs.PerfStress/Core/ContainerTest.cs new file mode 100644 index 000000000000..75a101eb31a5 --- /dev/null +++ b/net/Azure.Storage.Blobs.PerfStress/Core/ContainerTest.cs @@ -0,0 +1,36 @@ +using Azure.Test.PerfStress; +using System; +using System.Threading.Tasks; + +namespace Azure.Storage.Blobs.PerfStress.Core +{ + public abstract class ContainerTest : ServiceTest where TOptions : PerfStressOptions + { + private const string _containerPrefix = "perfstress"; + protected static string ContainerName { get; private set; } + + static ContainerTest() + { + ContainerName = _containerPrefix + "-" + Guid.NewGuid().ToString(); + } + + protected BlobContainerClient BlobContainerClient { get; private set; } + + public ContainerTest(TOptions options) : base(options) + { + BlobContainerClient = BlobServiceClient.GetBlobContainerClient(ContainerName); + } + + public override async Task GlobalSetup() + { + await base.GlobalSetup(); + await BlobContainerClient.CreateAsync(); + } + + public override async Task GlobalCleanup() + { + await BlobContainerClient.DeleteAsync(); + await base.GlobalCleanup(); + } + } +} diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/ContainerV11Test.cs b/net/Azure.Storage.Blobs.PerfStress/Core/ContainerV11Test.cs new file mode 100644 index 000000000000..322dbd42c38e --- /dev/null +++ b/net/Azure.Storage.Blobs.PerfStress/Core/ContainerV11Test.cs @@ -0,0 +1,37 @@ +using Azure.Test.PerfStress; +using Microsoft.Azure.Storage.Blob; +using System; +using System.Threading.Tasks; + +namespace Azure.Storage.Blobs.PerfStress.Core +{ + public abstract class ContainerV11Test : ServiceV11Test where TOptions: PerfStressOptions + { + private const string _containerPrefix = "perfstress"; + protected static string ContainerName { get; private set; } + + static ContainerV11Test() + { + ContainerName = _containerPrefix + "-" + Guid.NewGuid().ToString(); + } + + protected CloudBlobContainer CloudBlobContainer { get; private set; } + + public ContainerV11Test(TOptions options) : base(options) + { + CloudBlobContainer = CloudBlobClient.GetContainerReference(ContainerName); + } + + public override async Task GlobalSetup() + { + await base.GlobalSetup(); + await CloudBlobContainer.CreateAsync(); + } + + public override async Task GlobalCleanup() + { + await CloudBlobContainer.DeleteAsync(); + await base.GlobalCleanup(); + } + } +} diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/CountOptions.cs b/net/Azure.Storage.Blobs.PerfStress/Core/CountOptions.cs new file mode 100644 index 000000000000..80e956633b69 --- /dev/null +++ b/net/Azure.Storage.Blobs.PerfStress/Core/CountOptions.cs @@ -0,0 +1,11 @@ +using Azure.Test.PerfStress; +using CommandLine; + +namespace Azure.Storage.Blobs.PerfStress.Core +{ + public class CountOptions : PerfStressOptions + { + [Option('c', "count", Default = 100, HelpText = "Number of blobs")] + public int Count { get; set; } + } +} diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/ParallelTransferOptionsOptions.cs b/net/Azure.Storage.Blobs.PerfStress/Core/ParallelTransferOptionsOptions.cs index 16bcd17b6576..401cb9f5b701 100644 --- a/net/Azure.Storage.Blobs.PerfStress/Core/ParallelTransferOptionsOptions.cs +++ b/net/Azure.Storage.Blobs.PerfStress/Core/ParallelTransferOptionsOptions.cs @@ -1,13 +1,44 @@ -using CommandLine; +using Azure.Storage.Common; +using CommandLine; namespace Azure.Storage.Blobs.PerfStress.Core { public class ParallelTransferOptionsOptions : SizeOptions { + private int? _maximumTransferLength; + private int? _maximumThreadCount; + [Option('l', "maximumTransferLength")] - public int? MaximumTransferLength { get; set; } + public int? MaximumTransferLength + { + get => _maximumTransferLength; + set + { + _maximumTransferLength = value; + UpdateParallelTransferOptions(); + } + } [Option('t', "maximumThreadCount")] - public int? MaximumThreadCount { get; set; } + public int? MaximumThreadCount + { + get => _maximumThreadCount; + set + { + _maximumThreadCount = value; + UpdateParallelTransferOptions(); + } + } + + public ParallelTransferOptions ParallelTransferOptions { get; private set; } = new ParallelTransferOptions(); + + private void UpdateParallelTransferOptions() + { + ParallelTransferOptions = new ParallelTransferOptions() + { + MaximumThreadCount = MaximumThreadCount, + MaximumTransferLength = MaximumTransferLength + }; + } } } diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/ParallelTransferTest.cs b/net/Azure.Storage.Blobs.PerfStress/Core/ParallelTransferTest.cs deleted file mode 100644 index 89fef548ce8e..000000000000 --- a/net/Azure.Storage.Blobs.PerfStress/Core/ParallelTransferTest.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Azure.Storage.Common; - -namespace Azure.Storage.Blobs.PerfStress.Core -{ - public abstract class ParallelTransferTest : RandomDataTest where TOptions : ParallelTransferOptionsOptions - { - public ParallelTransferTest(string id, TOptions options) : base(id, options) - { - ParallelTransferOptions = new ParallelTransferOptions() - { - MaximumThreadCount = options.MaximumThreadCount, - MaximumTransferLength = options.MaximumTransferLength - }; - } - - protected ParallelTransferOptions ParallelTransferOptions { get; private set; } - } -} diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/RandomDataTest.cs b/net/Azure.Storage.Blobs.PerfStress/Core/RandomDataTest.cs deleted file mode 100644 index 7dc90d958be2..000000000000 --- a/net/Azure.Storage.Blobs.PerfStress/Core/RandomDataTest.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.IO; - -namespace Azure.Storage.Blobs.PerfStress.Core -{ - public abstract class RandomDataTest : StorageTest where TOptions : SizeOptions - { - private readonly byte[] _randomData; - - public RandomDataTest(string id, TOptions options) : base(id, options) - { - _randomData = new byte[1024 * 1024]; - (new Random(0)).NextBytes(_randomData); - } - - protected Stream RandomStream => new CircularStream(new MemoryStream(_randomData, writable: false), Options.Size); - - public override void Dispose() - { - RandomStream.Dispose(); - base.Dispose(); - } - } -} diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/RandomDataV11Test.cs b/net/Azure.Storage.Blobs.PerfStress/Core/RandomDataV11Test.cs deleted file mode 100644 index b0cf3152125a..000000000000 --- a/net/Azure.Storage.Blobs.PerfStress/Core/RandomDataV11Test.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.IO; - -namespace Azure.Storage.Blobs.PerfStress.Core -{ - public abstract class RandomDataV11Test : StorageV11Test where TOptions : SizeOptions - { - private readonly byte[] _randomData; - - public RandomDataV11Test(string id, TOptions options) : base(id, options) - { - _randomData = new byte[1024 * 1024]; - (new Random(0)).NextBytes(_randomData); - } - - protected Stream RandomStream => new CircularStream(new MemoryStream(_randomData, writable: false), Options.Size); - - public override void Dispose() - { - RandomStream.Dispose(); - base.Dispose(); - } - } -} diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/RandomStream.cs b/net/Azure.Storage.Blobs.PerfStress/Core/RandomStream.cs new file mode 100644 index 000000000000..af1835b3e723 --- /dev/null +++ b/net/Azure.Storage.Blobs.PerfStress/Core/RandomStream.cs @@ -0,0 +1,17 @@ +using System; +using System.IO; + +namespace Azure.Storage.Blobs.PerfStress.Core +{ + public static class RandomStream + { + private static readonly Lazy _randomBytes = new Lazy(() => + { + var randomData = new byte[1024 * 1024]; + (new Random(0)).NextBytes(randomData); + return randomData; + }); + + public static Stream Create(long size) => new CircularStream(new MemoryStream(_randomBytes.Value, writable: false), size); + } +} diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/StorageTest.cs b/net/Azure.Storage.Blobs.PerfStress/Core/ServiceTest.cs similarity index 57% rename from net/Azure.Storage.Blobs.PerfStress/Core/StorageTest.cs rename to net/Azure.Storage.Blobs.PerfStress/Core/ServiceTest.cs index 21823e487c46..1b4dfba51a97 100644 --- a/net/Azure.Storage.Blobs.PerfStress/Core/StorageTest.cs +++ b/net/Azure.Storage.Blobs.PerfStress/Core/ServiceTest.cs @@ -5,19 +5,12 @@ namespace Azure.Storage.Blobs.PerfStress { - public abstract class StorageTest : PerfStressTest where TOptions: PerfStressOptions + public abstract class ServiceTest : PerfStressTest where TOptions: PerfStressOptions { - private const string _containerName = "perfstress"; - protected BlobServiceClient BlobServiceClient { get; private set; } - protected BlobContainerClient BlobContainerClient { get; private set; } - - protected BlobClient BlobClient { get; private set; } - - public StorageTest(string id, TOptions options) : base(id, options) + public ServiceTest(TOptions options) : base(options) { - var blobName = this.GetType().Name.ToLowerInvariant() + id; var connectionString = Environment.GetEnvironmentVariable("STORAGE_CONNECTION_STRING"); if (string.IsNullOrEmpty(connectionString)) @@ -33,17 +26,6 @@ public StorageTest(string id, TOptions options) : base(id, options) blobClientOptions.Transport = new HttpClientTransport(httpClient); BlobServiceClient = new BlobServiceClient(connectionString, blobClientOptions); - try - { - BlobServiceClient.CreateBlobContainer(_containerName); - } - catch (StorageRequestFailedException) - { - } - - BlobContainerClient = BlobServiceClient.GetBlobContainerClient(_containerName); - - BlobClient = BlobContainerClient.GetBlobClient(blobName); } } } diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/ServiceV11Test.cs b/net/Azure.Storage.Blobs.PerfStress/Core/ServiceV11Test.cs new file mode 100644 index 000000000000..a4414abbddea --- /dev/null +++ b/net/Azure.Storage.Blobs.PerfStress/Core/ServiceV11Test.cs @@ -0,0 +1,27 @@ +using Azure.Test.PerfStress; +using Microsoft.Azure.Storage; +using Microsoft.Azure.Storage.Blob; +using System; + +namespace Azure.Storage.Blobs.PerfStress.Core +{ + public abstract class ServiceV11Test : PerfStressTest where TOptions : PerfStressOptions + { + protected CloudBlobClient CloudBlobClient { get; private set; } + + public ServiceV11Test(TOptions options) : base(options) + { + var connectionString = Environment.GetEnvironmentVariable("STORAGE_CONNECTION_STRING"); + + if (string.IsNullOrEmpty(connectionString)) + { + throw new InvalidOperationException("Undefined environment variable STORAGE_CONNECTION_STRING"); + } + + CloudStorageAccount.TryParse(connectionString, out var storageAccount); + + + CloudBlobClient = storageAccount.CreateCloudBlobClient(); + } + } +} diff --git a/net/Azure.Storage.Blobs.PerfStress/Core/StorageV11Test.cs b/net/Azure.Storage.Blobs.PerfStress/Core/StorageV11Test.cs deleted file mode 100644 index 74ea4eeb36a3..000000000000 --- a/net/Azure.Storage.Blobs.PerfStress/Core/StorageV11Test.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Azure.Test.PerfStress; -using Microsoft.Azure.Storage; -using Microsoft.Azure.Storage.Blob; -using System; -using System.Collections.Generic; -using System.Text; - -namespace Azure.Storage.Blobs.PerfStress.Core -{ - public abstract class StorageV11Test : PerfStressTest where TOptions : PerfStressOptions - { - private const string _containerName = "perfstress"; - - protected CloudBlockBlob CloudBlockBlob { get; private set; } - - public StorageV11Test(string id, TOptions options) : base(id, options) - { - var blobName = this.GetType().Name.ToLowerInvariant() + id; - var connectionString = Environment.GetEnvironmentVariable("STORAGE_CONNECTION_STRING"); - - if (string.IsNullOrEmpty(connectionString)) - { - throw new InvalidOperationException("Undefined environment variable STORAGE_CONNECTION_STRING"); - } - - CloudStorageAccount.TryParse(connectionString, out var storageAccount); - var cloudBlobClient = storageAccount.CreateCloudBlobClient(); - - var cloudBlobContainer = cloudBlobClient.GetContainerReference(_containerName); - - try - { - cloudBlobContainer.Create(); - } - catch (StorageException) - { - } - - - CloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(blobName); - } - } -} diff --git a/net/Azure.Storage.Blobs.PerfStress/DownloadTest.cs b/net/Azure.Storage.Blobs.PerfStress/DownloadTest.cs index 2db0b041011f..21ad71081213 100644 --- a/net/Azure.Storage.Blobs.PerfStress/DownloadTest.cs +++ b/net/Azure.Storage.Blobs.PerfStress/DownloadTest.cs @@ -5,42 +5,33 @@ namespace Azure.Storage.Blobs.PerfStress { - public class DownloadTest : ParallelTransferTest + public class DownloadTest : ContainerTest { - public DownloadTest(string id, ParallelTransferOptionsOptions options) : base(id, options) - { - try - { - BlobClient.Delete(); - } - catch (StorageRequestFailedException) - { - } + private readonly BlobClient _blobClient; - BlobClient.Upload(RandomStream); + public DownloadTest(ParallelTransferOptionsOptions options) : base(options) + { + _blobClient = BlobContainerClient.GetBlobClient("downloadtest"); } - public override void Run(CancellationToken cancellationToken) + public override async Task GlobalSetup() { - BlobClient.Download(Stream.Null, parallelTransferOptions: ParallelTransferOptions, cancellationToken: cancellationToken); + await base.GlobalSetup(); + + using var stream = RandomStream.Create(Options.Size); + + // No need to delete file in GlobalCleanup(), since ContainerTest.GlobalCleanup() deletes the whole container + await _blobClient.UploadAsync(stream); } - public override async Task RunAsync(CancellationToken cancellationToken) + public override void Run(CancellationToken cancellationToken) { - await BlobClient.DownloadAsync(Stream.Null, parallelTransferOptions: ParallelTransferOptions, cancellationToken: cancellationToken); + _blobClient.Download(Stream.Null, parallelTransferOptions: Options.ParallelTransferOptions, cancellationToken: cancellationToken); } - public override void Dispose() + public override async Task RunAsync(CancellationToken cancellationToken) { - try - { - BlobClient.Delete(); - } - catch (StorageRequestFailedException) - { - } - - base.Dispose(); + await _blobClient.DownloadAsync(Stream.Null, parallelTransferOptions: Options.ParallelTransferOptions, cancellationToken: cancellationToken); } } } diff --git a/net/Azure.Storage.Blobs.PerfStress/DownloadV11Test.cs b/net/Azure.Storage.Blobs.PerfStress/DownloadV11Test.cs index c5d0fe3c936c..d464e0d36fa7 100644 --- a/net/Azure.Storage.Blobs.PerfStress/DownloadV11Test.cs +++ b/net/Azure.Storage.Blobs.PerfStress/DownloadV11Test.cs @@ -1,47 +1,38 @@ using Azure.Storage.Blobs.PerfStress.Core; -using Microsoft.Azure.Storage; +using Microsoft.Azure.Storage.Blob; using System.IO; using System.Threading; using System.Threading.Tasks; namespace Azure.Storage.Blobs.PerfStress { - public class DownloadV11Test : RandomDataV11Test + public class DownloadV11Test : ContainerV11Test { - public DownloadV11Test(string id, SizeOptions options) : base(id, options) - { - try - { - CloudBlockBlob.Delete(); - } - catch (StorageException) - { - } + private readonly CloudBlockBlob _cloudBlockBlob; - CloudBlockBlob.UploadFromStream(RandomStream); - } - - public override void Run(CancellationToken cancellationToken) + public DownloadV11Test(SizeOptions options) : base(options) { - CloudBlockBlob.DownloadToStream(Stream.Null); + _cloudBlockBlob = CloudBlobContainer.GetBlockBlobReference("downloadv11test"); } - public override async Task RunAsync(CancellationToken cancellationToken) + public override async Task GlobalSetup() { - await CloudBlockBlob.DownloadToStreamAsync(Stream.Null, cancellationToken); + await base.GlobalSetup(); + + using var stream = RandomStream.Create(Options.Size); + + // No need to delete file in GlobalCleanup(), since ContainerV11Test.GlobalCleanup() deletes the whole container + await _cloudBlockBlob.UploadFromStreamAsync(stream); } - public override void Dispose() + public override void Run(CancellationToken cancellationToken) { - try - { - CloudBlockBlob.Delete(); - } - catch (StorageException) - { - } + _cloudBlockBlob.DownloadToStream(Stream.Null); + } - base.Dispose(); + public override async Task RunAsync(CancellationToken cancellationToken) + { + await _cloudBlockBlob.DownloadToStreamAsync(Stream.Null, cancellationToken); } } } diff --git a/net/Azure.Storage.Blobs.PerfStress/GetBlobsTest.cs b/net/Azure.Storage.Blobs.PerfStress/GetBlobsTest.cs new file mode 100644 index 000000000000..4a6636e10d99 --- /dev/null +++ b/net/Azure.Storage.Blobs.PerfStress/GetBlobsTest.cs @@ -0,0 +1,40 @@ +using Azure.Storage.Blobs.PerfStress.Core; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Azure.Storage.Blobs.PerfStress +{ + public class GetBlobsTest : ContainerTest + { + public GetBlobsTest(CountOptions options) : base(options) + { + } + + public override async Task GlobalSetup() + { + await base.GlobalSetup(); + + var uploadTasks = new Task[Options.Count]; + for (var i = 0; i < uploadTasks.Length; i++) + { + var blobName = "getblobstest-" + Guid.NewGuid().ToString(); + uploadTasks[i] = BlobContainerClient.UploadBlobAsync(blobName, Stream.Null); + } + await Task.WhenAll(uploadTasks); + } + + public override void Run(CancellationToken cancellationToken) + { + // Enumerate collection to ensure all BlobItems are downloaded + foreach (var _ in BlobContainerClient.GetBlobs(cancellationToken: cancellationToken)); + } + + public override async Task RunAsync(CancellationToken cancellationToken) + { + // Enumerate collection to ensure all BlobItems are downloaded + await foreach (var _ in BlobContainerClient.GetBlobsAsync(cancellationToken: cancellationToken)) { } + } + } +} diff --git a/net/Azure.Storage.Blobs.PerfStress/GetBlobsV11Test.cs b/net/Azure.Storage.Blobs.PerfStress/GetBlobsV11Test.cs new file mode 100644 index 000000000000..5ef85351fc01 --- /dev/null +++ b/net/Azure.Storage.Blobs.PerfStress/GetBlobsV11Test.cs @@ -0,0 +1,48 @@ +using Azure.Storage.Blobs.PerfStress.Core; +using Microsoft.Azure.Storage.Blob; +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Azure.Storage.Blobs.PerfStress +{ + public class GetBlobsV11Test : ContainerV11Test + { + public GetBlobsV11Test(CountOptions options) : base(options) { } + + public override async Task GlobalSetup() + { + await base.GlobalSetup(); + + var uploadTasks = new Task[Options.Count]; + for (var i = 0; i < uploadTasks.Length; i++) + { + var blobName = "getblobstest-" + Guid.NewGuid().ToString(); + uploadTasks[i] = CloudBlobContainer.GetBlockBlobReference(blobName).UploadFromStreamAsync(Stream.Null); + } + await Task.WhenAll(uploadTasks); + } + + public override void Run(CancellationToken cancellationToken) + { + // Enumerate collection to ensure all IListBlobItems are downloaded + foreach (var _ in CloudBlobContainer.ListBlobs()) { } + } + + public override async Task RunAsync(CancellationToken cancellationToken) + { + BlobContinuationToken continuationToken = null; + do + { + var result = await CloudBlobContainer.ListBlobsSegmentedAsync(continuationToken, cancellationToken); + continuationToken = result.ContinuationToken; + + // Enumerate collection to ensure all IListBlobItems are downloaded + foreach (var _ in result.Results) { } + } + while (continuationToken != null); + } + + } +} diff --git a/net/Azure.Storage.Blobs.PerfStress/UploadTest.cs b/net/Azure.Storage.Blobs.PerfStress/UploadTest.cs index a87c0193925d..8afa748a8c6a 100644 --- a/net/Azure.Storage.Blobs.PerfStress/UploadTest.cs +++ b/net/Azure.Storage.Blobs.PerfStress/UploadTest.cs @@ -1,42 +1,34 @@ using Azure.Storage.Blobs.PerfStress.Core; +using System; using System.Threading; using System.Threading.Tasks; namespace Azure.Storage.Blobs.PerfStress { - public class UploadTest : ParallelTransferTest + public class UploadTest : ContainerTest { - public UploadTest(string id, ParallelTransferOptionsOptions options) : base(id, options) + private readonly BlobClient _blobClient; + + public UploadTest(ParallelTransferOptionsOptions options) : base(options) { - try - { - BlobClient.Delete(); - } - catch (StorageRequestFailedException) - { - } + var blobName = "uploadtest-" + Guid.NewGuid().ToString(); + _blobClient = BlobContainerClient.GetBlobClient(blobName); } public override void Run(CancellationToken cancellationToken) { - BlobClient.Upload(RandomStream, parallelTransferOptions: ParallelTransferOptions, cancellationToken: cancellationToken); + using var stream = RandomStream.Create(Options.Size); + + // No need to delete file in Cleanup(), since ContainerTest.GlobalCleanup() deletes the whole container + _blobClient.Upload(stream, parallelTransferOptions: Options.ParallelTransferOptions, cancellationToken: cancellationToken); } public override async Task RunAsync(CancellationToken cancellationToken) { - await BlobClient.UploadAsync(RandomStream, parallelTransferOptions: ParallelTransferOptions, cancellationToken: cancellationToken); - } + using var stream = RandomStream.Create(Options.Size); - public override void Dispose() - { - try - { - BlobClient.Delete(); - } - catch (StorageRequestFailedException) - { - } - base.Dispose(); + // No need to delete file in Cleanup(), since ContainerTest.GlobalCleanup() deletes the whole container + await _blobClient.UploadAsync(stream, parallelTransferOptions: Options.ParallelTransferOptions, cancellationToken: cancellationToken); } } } diff --git a/net/Azure.Storage.Blobs.PerfStress/UploadV11Test.cs b/net/Azure.Storage.Blobs.PerfStress/UploadV11Test.cs index 0bec6c26668b..d520812745e5 100644 --- a/net/Azure.Storage.Blobs.PerfStress/UploadV11Test.cs +++ b/net/Azure.Storage.Blobs.PerfStress/UploadV11Test.cs @@ -1,45 +1,35 @@ using Azure.Storage.Blobs.PerfStress.Core; -using Microsoft.Azure.Storage; -using System.IO; +using Microsoft.Azure.Storage.Blob; +using System; using System.Threading; using System.Threading.Tasks; namespace Azure.Storage.Blobs.PerfStress { - public class UploadV11Test : RandomDataV11Test + public class UploadV11Test : ContainerV11Test { - public UploadV11Test(string id, SizeOptions options) : base(id, options) + private readonly CloudBlockBlob _cloudBlockBlob; + + public UploadV11Test(SizeOptions options) : base(options) { - try - { - CloudBlockBlob.Delete(); - } - catch (StorageException) - { - } + var blobName = "uploadv11test-" + Guid.NewGuid().ToString(); + _cloudBlockBlob = CloudBlobContainer.GetBlockBlobReference(blobName); } public override void Run(CancellationToken cancellationToken) { - CloudBlockBlob.UploadFromStream(RandomStream); - } + using var stream = RandomStream.Create(Options.Size); - public override async Task RunAsync(CancellationToken cancellationToken) - { - await CloudBlockBlob.UploadFromStreamAsync(RandomStream, cancellationToken); + // No need to delete file in Cleanup(), since ContainerTest.GlobalCleanup() deletes the whole container + _cloudBlockBlob.UploadFromStream(stream); } - public override void Dispose() + public override async Task RunAsync(CancellationToken cancellationToken) { - try - { - CloudBlockBlob.Delete(); - } - catch (StorageException) - { - } + using var stream = RandomStream.Create(Options.Size); - base.Dispose(); + // No need to delete file in Cleanup(), since ContainerTest.GlobalCleanup() deletes the whole container + await _cloudBlockBlob.UploadFromStreamAsync(stream, cancellationToken); } } } diff --git a/net/Azure.Test.PerfStress/IPerfStressTest.cs b/net/Azure.Test.PerfStress/IPerfStressTest.cs index 886a925fb9f1..85293f469dd4 100644 --- a/net/Azure.Test.PerfStress/IPerfStressTest.cs +++ b/net/Azure.Test.PerfStress/IPerfStressTest.cs @@ -1,12 +1,15 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; namespace Azure.Test.PerfStress { - internal interface IPerfStressTest : IDisposable + internal interface IPerfStressTest { + Task GlobalSetup(); + Task Setup(); void Run(CancellationToken cancellationToken); Task RunAsync(CancellationToken cancellationToken); + Task Cleanup(); + Task GlobalCleanup(); } } diff --git a/net/Azure.Test.PerfStress/PerfStressOptions.cs b/net/Azure.Test.PerfStress/PerfStressOptions.cs index 48c36e45852d..3596d2179444 100644 --- a/net/Azure.Test.PerfStress/PerfStressOptions.cs +++ b/net/Azure.Test.PerfStress/PerfStressOptions.cs @@ -4,13 +4,16 @@ namespace Azure.Test.PerfStress { public class PerfStressOptions { - [Option("sync")] - public bool Sync { get; set; } - [Option('d', "duration", Default = 10, HelpText = "Duration of test in seconds")] public int Duration { get; set; } + [Option("no-cleanup", HelpText = "Disables test cleanup")] + public bool NoCleanup { get; set; } + [Option('p', "parallel", Default = 1, HelpText = "Number of operations to execute in parallel")] public int Parallel { get; set; } + + [Option("sync", HelpText = "Runs sync version of test")] + public bool Sync { get; set; } } } diff --git a/net/Azure.Test.PerfStress/PerfStressProgram.cs b/net/Azure.Test.PerfStress/PerfStressProgram.cs index 67a187a557e7..2aac437041ac 100644 --- a/net/Azure.Test.PerfStress/PerfStressProgram.cs +++ b/net/Azure.Test.PerfStress/PerfStressProgram.cs @@ -52,45 +52,73 @@ private static async Task Run(Type testType, PerfStressOptions options) var duration = TimeSpan.FromSeconds(options.Duration); - var tests = CreateTests(testType, options); + var tests = new IPerfStressTest[options.Parallel]; + for (var i = 0; i < options.Parallel; i++) + { + tests[i] = (IPerfStressTest)Activator.CreateInstance(testType, options); + } try { - using var cts = new CancellationTokenSource(duration); - var cancellationToken = cts.Token; + await tests[0].GlobalSetup(); - _ = PrintStatusAsync(cancellationToken); - - if (options.Sync) + try { - var threads = new Thread[options.Parallel]; - + var setupTasks = new Task[options.Parallel]; for (var i = 0; i < options.Parallel; i++) { - var j = i; - threads[i] = new Thread(() => RunLoop(tests[j], cancellationToken)); - threads[i].Start(); + setupTasks[i] = tests[i].Setup(); } - for (var i = 0; i < options.Parallel; i++) + await Task.WhenAll(setupTasks); + + using var cts = new CancellationTokenSource(duration); + var cancellationToken = cts.Token; + + _ = PrintStatusAsync(cancellationToken); + + if (options.Sync) + { + var threads = new Thread[options.Parallel]; + + for (var i = 0; i < options.Parallel; i++) + { + var j = i; + threads[i] = new Thread(() => RunLoop(tests[j], cancellationToken)); + threads[i].Start(); + } + for (var i = 0; i < options.Parallel; i++) + { + threads[i].Join(); + } + } + else { - threads[i].Join(); + var tasks = new Task[options.Parallel]; + for (var i = 0; i < options.Parallel; i++) + { + tasks[i] = RunLoopAsync(tests[i], cancellationToken); + } + await Task.WhenAll(tasks); } } - else + finally { - var tasks = new Task[options.Parallel]; - for (var i = 0; i < options.Parallel; i++) + if (!options.NoCleanup) { - tasks[i] = RunLoopAsync(tests[i], cancellationToken); + var cleanupTasks = new Task[options.Parallel]; + for (var i = 0; i < options.Parallel; i++) + { + cleanupTasks[i] = tests[i].Cleanup(); + } + await Task.WhenAll(cleanupTasks); } - await Task.WhenAll(tasks); } } finally { - for (var i = 0; i < options.Parallel; i++) + if (!options.NoCleanup) { - tests[i]?.Dispose(); + await tests[0].GlobalCleanup(); } } @@ -104,28 +132,6 @@ private static async Task Run(Type testType, PerfStressOptions options) Console.WriteLine(); } - private static IPerfStressTest[] CreateTests(Type testType, PerfStressOptions options) - { - var tests = new IPerfStressTest[options.Parallel]; - var threads = new Thread[options.Parallel]; - - for (var i=0; i < options.Parallel; i++) - { - var j = i; - threads[i] = new Thread(() => - { - tests[j] = (IPerfStressTest)Activator.CreateInstance(testType, j.ToString(), options); - }); - threads[i].Start(); - } - for (var i = 0; i < options.Parallel; i++) - { - threads[i].Join(); - } - - return tests; - } - private static void RunLoop(IPerfStressTest test, CancellationToken cancellationToken) { var sw = Stopwatch.StartNew(); @@ -210,7 +216,7 @@ private static Type[] GetOptionTypes(IEnumerable testTypes) foreach (var t in testTypes) { - var baseOptionsType = t.GetConstructors().First().GetParameters()[1].ParameterType; + var baseOptionsType = t.GetConstructors().First().GetParameters()[0].ParameterType; var tb = mb.DefineType(t.Name + "Options", TypeAttributes.Public, baseOptionsType); var attrCtor = typeof(VerbAttribute).GetConstructor(new Type[] { typeof(string) }); diff --git a/net/Azure.Test.PerfStress/PerfStressTest.cs b/net/Azure.Test.PerfStress/PerfStressTest.cs index dafc3caaf50b..45ab2392d5f1 100644 --- a/net/Azure.Test.PerfStress/PerfStressTest.cs +++ b/net/Azure.Test.PerfStress/PerfStressTest.cs @@ -5,22 +5,35 @@ namespace Azure.Test.PerfStress { public abstract class PerfStressTest : IPerfStressTest where TOptions : PerfStressOptions { - protected string Id { get; private set; } - protected TOptions Options { get; private set; } - public PerfStressTest(string id, TOptions options) + public PerfStressTest(TOptions options) { - Id = id; Options = options; } + public virtual Task GlobalSetup() + { + return Task.CompletedTask; + } + + public virtual Task Setup() + { + return Task.CompletedTask; + } + public abstract void Run(CancellationToken cancellationToken); public abstract Task RunAsync(CancellationToken cancellationToken); - public virtual void Dispose() + public virtual Task Cleanup() + { + return Task.CompletedTask; + } + + public virtual Task GlobalCleanup() { + return Task.CompletedTask; } } }