diff --git a/eng/.docsettings.yml b/eng/.docsettings.yml
index 4165f16ae065..e0d759f84acb 100644
--- a/eng/.docsettings.yml
+++ b/eng/.docsettings.yml
@@ -154,6 +154,7 @@ known_content_issues:
- ['sdk/formrecognizer/Azure.AI.FormRecognizer/README.md','#5499']
- ['sdk/formrecognizer/Azure.AI.FormRecognizer/README.md','#11492']
- ['sdk/storage/Azure.Storage.Blobs/README.md','#11492']
+ - ['sdk/storage/Azure.Storage.Blobs/perf/README.md','#11492']
- ['sdk/storage/Azure.Storage.Blobs.Batch/README.md','#11492']
- ['sdk/storage/Azure.Storage.Blobs.Cryptography/README.md','#11492']
- ['sdk/storage/Azure.Storage.Common/README.md','#11492']
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf.slnf b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf.slnf
new file mode 100644
index 000000000000..dbb8dff3a6eb
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf.slnf
@@ -0,0 +1,13 @@
+{
+ "solution": {
+ "path": "..\\..\\Azure.Storage.sln",
+ "projects": [
+ "..\\..\\common\\Perf\\Azure.Test.Perf\\Azure.Test.Perf.csproj",
+ "..\\core\\Azure.Core.TestFramework\\src\\Azure.Core.TestFramework.csproj",
+ "Azure.Storage.Common\\src\\Azure.Storage.Common.csproj",
+ "Azure.Storage.Blobs\\src\\Azure.Storage.Blobs.csproj",
+ "Azure.Storage.Blobs\\perf\\Azure.Storage.Blobs.Perf\\Azure.Storage.Blobs.Perf.csproj",
+ "Azure.Storage.Blobs\\perf\\Microsoft.Azure.Storage.Blob.Perf\\Microsoft.Azure.Storage.Blob.Perf.csproj"
+ ]
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Azure.Storage.Blobs.Perf.csproj b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Azure.Storage.Blobs.Perf.csproj
new file mode 100644
index 000000000000..922d3d5fc108
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Azure.Storage.Blobs.Perf.csproj
@@ -0,0 +1,11 @@
+
+
+ Exe
+
+
+
+
+
+
+
+
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/BlobTest.cs b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/BlobTest.cs
new file mode 100644
index 000000000000..431b47b4e3a7
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/BlobTest.cs
@@ -0,0 +1,23 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using Azure.Storage.Blobs.Specialized;
+using Azure.Test.Perf;
+
+namespace Azure.Storage.Blobs.Perf
+{
+ public abstract class BlobTest : ContainerTest where TOptions : SizeOptions
+ {
+ protected BlobClient BlobClient { get; private set; }
+ protected BlockBlobClient BlockBlobClient { get; private set; }
+
+ public BlobTest(TOptions options) : base(options)
+ {
+ var blobName = $"Azure.Storage.Blobs.Perf.BlobTest-{Guid.NewGuid()}";
+
+ BlobClient = BlobContainerClient.GetBlobClient(blobName);
+ BlockBlobClient = BlobContainerClient.GetBlockBlobClient(blobName);
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/ContainerTest.cs b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/ContainerTest.cs
new file mode 100644
index 000000000000..a9d80633695b
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/ContainerTest.cs
@@ -0,0 +1,35 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Threading.Tasks;
+using Azure.Test.Perf;
+
+namespace Azure.Storage.Blobs.Perf
+{
+ public abstract class ContainerTest : ServiceTest where TOptions : PerfOptions
+ {
+ // See https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata for
+ // restrictions on blob containers and blob storage naming.
+ protected static string ContainerName { get; } = $"ContainerTest-{Guid.NewGuid()}".ToLowerInvariant();
+
+ protected BlobContainerClient BlobContainerClient { get; private set; }
+
+ public ContainerTest(TOptions options) : base(options)
+ {
+ BlobContainerClient = BlobServiceClient.GetBlobContainerClient(ContainerName);
+ }
+
+ public override async Task GlobalSetupAsync()
+ {
+ await base.GlobalSetupAsync();
+ await BlobContainerClient.CreateAsync();
+ }
+
+ public override async Task GlobalCleanupAsync()
+ {
+ await BlobContainerClient.DeleteAsync();
+ await base.GlobalCleanupAsync();
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/PerfTestEnvironment.cs b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/PerfTestEnvironment.cs
new file mode 100644
index 000000000000..90c28120b77d
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/PerfTestEnvironment.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using Azure.Core.TestFramework;
+
+namespace Azure.Storage.Blobs.Perf
+{
+ ///
+ /// Represents the ambient environment in which the test suite is being run, offering access to information such as environment variables.
+ ///
+ internal sealed class PerfTestEnvironment : TestEnvironment
+ {
+ ///
+ /// The shared instance of the to be used during test runs.
+ ///
+ public static PerfTestEnvironment Instance { get; } = new PerfTestEnvironment();
+
+ ///
+ /// The storage account endpoint suffix of the cloud to use for testing.
+ ///
+ public new string StorageEndpointSuffix => base.StorageEndpointSuffix ?? "core.windows.net";
+
+ ///
+ /// The name of the Blob storage account to test against.
+ ///
+ /// The Blob storage account name, read from the "AZURE_STORAGE_ACCOUNT_NAME" environment variable.
+ public string BlobStorageAccountName => GetVariable("AZURE_STORAGE_ACCOUNT_NAME");
+
+ ///
+ /// The shared access key of the Blob storage account to test against.
+ ///
+ /// The Blob storage account key, read from the "AZURE_STORAGE_ACCOUNT_KEY" environment variable.
+ public string BlobStorageAccountKey => GetVariable("AZURE_STORAGE_ACCOUNT_KEY");
+
+ ///
+ /// The connection string for accessing the Blob storage account used for testing.
+ ///
+ public string BlobStorageConnectionString { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PerfTestEnvironment()
+ {
+ BlobStorageConnectionString = $"DefaultEndpointsProtocol={Uri.UriSchemeHttps};AccountName={BlobStorageAccountName};AccountKey={BlobStorageAccountKey};EndpointSuffix={StorageEndpointSuffix}";
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/ServiceTest.cs b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/ServiceTest.cs
new file mode 100644
index 000000000000..3ea21ecb0a96
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/ServiceTest.cs
@@ -0,0 +1,22 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Azure.Test.Perf;
+
+namespace Azure.Storage.Blobs.Perf
+{
+ public abstract class ServiceTest : PerfTest where TOptions : PerfOptions
+ {
+ protected BlobServiceClient BlobServiceClient { get; private set; }
+
+ public ServiceTest(TOptions options) : base(options)
+ {
+ var blobClientOptions = new BlobClientOptions()
+ {
+ Transport = PerfTransport.Create(options)
+ };
+
+ BlobServiceClient = new BlobServiceClient(PerfTestEnvironment.Instance.BlobStorageConnectionString, blobClientOptions);
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/StorageTransferOptionsOptions.cs b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/StorageTransferOptionsOptions.cs
new file mode 100644
index 000000000000..f02ff284a06c
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Infrastructure/StorageTransferOptionsOptions.cs
@@ -0,0 +1,47 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Azure.Test.Perf;
+using CommandLine;
+
+namespace Azure.Storage.Blobs.Perf
+{
+ public class StorageTransferOptionsOptions : SizeOptions
+ {
+ private int? _maximumTransferLength;
+ private int? _maximumConcurrency;
+
+ [Option('l', "maximumTransferLength")]
+ public int? MaximumTransferLength
+ {
+ get => _maximumTransferLength;
+ set
+ {
+ _maximumTransferLength = value;
+ UpdateStorageTransferOptions();
+ }
+ }
+
+ [Option('t', "MaximumConcurrency")]
+ public int? MaximumConcurrency
+ {
+ get => _maximumConcurrency;
+ set
+ {
+ _maximumConcurrency = value;
+ UpdateStorageTransferOptions();
+ }
+ }
+
+ public StorageTransferOptions StorageTransferOptions { get; private set; }
+
+ private void UpdateStorageTransferOptions()
+ {
+ StorageTransferOptions = new StorageTransferOptions()
+ {
+ MaximumConcurrency = MaximumConcurrency,
+ MaximumTransferLength = MaximumTransferLength
+ };
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Program.cs b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Program.cs
new file mode 100644
index 000000000000..1ad7284aaa19
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Program.cs
@@ -0,0 +1,7 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Reflection;
+using Azure.Test.Perf;
+
+await PerfProgram.Main(Assembly.GetEntryAssembly(), args);
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/DownloadBlob.cs b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/DownloadBlob.cs
new file mode 100644
index 000000000000..3e83c7a12f78
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/DownloadBlob.cs
@@ -0,0 +1,44 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Test.Perf;
+
+namespace Azure.Storage.Blobs.Perf.Scenarios
+{
+ ///
+ /// The performance test scenario focused on downloading blobs from the Azure blobs storage.
+ ///
+ ///
+ public sealed class DownloadBlob : ContainerTest
+ {
+ private readonly BlobClient _blobClient;
+
+ public DownloadBlob(StorageTransferOptionsOptions options) : base(options)
+ {
+ _blobClient = BlobContainerClient.GetBlobClient("Azure.Storage.Blobs.Perf.Scenarios.DownloadBlob");
+ }
+
+ public override async Task GlobalSetupAsync()
+ {
+ await base.GlobalSetupAsync();
+
+ using Stream 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 void Run(CancellationToken cancellationToken)
+ {
+ _blobClient.DownloadTo(Stream.Null, transferOptions: Options.StorageTransferOptions, cancellationToken: cancellationToken);
+ }
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
+ {
+ await _blobClient.DownloadToAsync(Stream.Null, transferOptions: Options.StorageTransferOptions, cancellationToken: cancellationToken);
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/UploadBlob.cs b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/UploadBlob.cs
new file mode 100644
index 000000000000..a43702ecbf5f
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/UploadBlob.cs
@@ -0,0 +1,42 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Test.Perf;
+
+namespace Azure.Storage.Blobs.Perf.Scenarios
+{
+ ///
+ /// The performance test scenario focused on uploading blobs to the Azure blobs storage.
+ ///
+ ///
+ public sealed class UploadBlob : BlobTest
+ {
+ private readonly Stream _stream;
+
+ public UploadBlob(StorageTransferOptionsOptions options) : base (options)
+ {
+ _stream = RandomStream.Create(options.Size);
+ }
+
+ public override void Dispose(bool disposing)
+ {
+ _stream.Dispose();
+ base.Dispose(disposing);
+ }
+
+ public override void Run(CancellationToken cancellationToken)
+ {
+ _stream.Seek(0, SeekOrigin.Begin);
+ BlobClient.Upload(_stream, transferOptions: Options.StorageTransferOptions, cancellationToken: cancellationToken);
+ }
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
+ {
+ _stream.Seek(0, SeekOrigin.Begin);
+ await BlobClient.UploadAsync(_stream, transferOptions: Options.StorageTransferOptions, cancellationToken: cancellationToken);
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/BlobTest.cs b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/BlobTest.cs
new file mode 100644
index 000000000000..a73dea1a87da
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/BlobTest.cs
@@ -0,0 +1,19 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using Azure.Test.Perf;
+
+namespace Microsoft.Azure.Storage.Blob.Perf
+{
+ public abstract class BlobTest : ContainerTest where TOptions : SizeOptions
+ {
+ protected CloudBlockBlob CloudBlockBlob { get; private set; }
+
+ public BlobTest(TOptions options) : base(options)
+ {
+ var blobName = $"Microsoft.Azure.Storage.Blob.Perf.RandomBlobTest-{Guid.NewGuid()}";
+ CloudBlockBlob = CloudBlobContainer.GetBlockBlobReference(blobName);
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/ContainerTest.cs b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/ContainerTest.cs
new file mode 100644
index 000000000000..12297854565d
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/ContainerTest.cs
@@ -0,0 +1,35 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Threading.Tasks;
+using Azure.Test.Perf;
+
+namespace Microsoft.Azure.Storage.Blob.Perf
+{
+ public abstract class ContainerTest : ServiceTest where TOptions : PerfOptions
+ {
+ // See https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata for
+ // restrictions on blob containers and blob storage naming.
+ protected static string ContainerName { get; } = $"ContainerTest-{Guid.NewGuid()}".ToLowerInvariant();
+
+ protected CloudBlobContainer CloudBlobContainer { get; private set; }
+
+ public ContainerTest(TOptions options) : base(options)
+ {
+ CloudBlobContainer = CloudBlobClient.GetContainerReference(ContainerName);
+ }
+
+ public override async Task GlobalSetupAsync()
+ {
+ await base.GlobalSetupAsync();
+ await CloudBlobContainer.CreateAsync();
+ }
+
+ public override async Task GlobalCleanupAsync()
+ {
+ await CloudBlobContainer.DeleteAsync();
+ await base.GlobalCleanupAsync();
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/PerfTestEnvironment.cs b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/PerfTestEnvironment.cs
new file mode 100644
index 000000000000..2c17003af5ea
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/PerfTestEnvironment.cs
@@ -0,0 +1,49 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using Azure.Core.TestFramework;
+
+namespace Microsoft.Azure.Storage.Blob.Perf
+{
+ ///
+ /// Represents the ambient environment in which the test suite is being run, offering access to information such as environment variables.
+ ///
+ internal sealed class PerfTestEnvironment : TestEnvironment
+ {
+ ///
+ /// The shared instance of the to be used during test runs.
+ ///
+ public static PerfTestEnvironment Instance { get; } = new PerfTestEnvironment();
+
+ ///
+ /// The storage account endpoint suffix of the cloud to use for testing.
+ ///
+ public new string StorageEndpointSuffix => base.StorageEndpointSuffix ?? "core.windows.net";
+
+ ///
+ /// The name of the Blob storage account to test against.
+ ///
+ /// The Blob storage account name, read from the "AZURE_STORAGE_ACCOUNT_NAME" environment variable.
+ public string BlobStorageAccountName => GetVariable("AZURE_STORAGE_ACCOUNT_NAME");
+
+ ///
+ /// The shared access key of the Blob storage account to test against.
+ ///
+ /// The Blob storage account key, read from the "AZURE_STORAGE_ACCOUNT_KEY" environment variable.
+ public string BlobStorageAccountKey => GetVariable("AZURE_STORAGE_ACCOUNT_KEY");
+
+ ///
+ /// The connection string for accessing the Blob storage account used for testing.
+ ///
+ public string BlobStorageConnectionString { get; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public PerfTestEnvironment()
+ {
+ BlobStorageConnectionString = $"DefaultEndpointsProtocol={Uri.UriSchemeHttps};AccountName={BlobStorageAccountName};AccountKey={BlobStorageAccountKey};EndpointSuffix={StorageEndpointSuffix}";
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/ServiceTest.cs b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/ServiceTest.cs
new file mode 100644
index 000000000000..bb3061e29576
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Infrastructure/ServiceTest.cs
@@ -0,0 +1,19 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using Azure.Test.Perf;
+
+namespace Microsoft.Azure.Storage.Blob.Perf
+{
+ public abstract class ServiceTest : PerfTest where TOptions : PerfOptions
+ {
+ protected CloudBlobClient CloudBlobClient { get; private set; }
+
+ public ServiceTest(TOptions options) : base(options)
+ {
+ CloudStorageAccount storageAccount = CloudStorageAccount.Parse(PerfTestEnvironment.Instance.BlobStorageConnectionString);
+
+ CloudBlobClient = storageAccount.CreateCloudBlobClient();
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Microsoft.Azure.Storage.Blob.Perf.csproj b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Microsoft.Azure.Storage.Blob.Perf.csproj
new file mode 100644
index 000000000000..2c62a7b27196
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Microsoft.Azure.Storage.Blob.Perf.csproj
@@ -0,0 +1,14 @@
+
+
+ Exe
+
+
+
+
+
+
+
+
+
+
+
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Program.cs b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Program.cs
new file mode 100644
index 000000000000..1ad7284aaa19
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Program.cs
@@ -0,0 +1,7 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Reflection;
+using Azure.Test.Perf;
+
+await PerfProgram.Main(Assembly.GetEntryAssembly(), args);
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Scenarios/DownloadBlob.cs b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Scenarios/DownloadBlob.cs
new file mode 100644
index 000000000000..9dcc559cfc41
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Scenarios/DownloadBlob.cs
@@ -0,0 +1,44 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Test.Perf;
+
+namespace Microsoft.Azure.Storage.Blob.Perf.Scenarios
+{
+ ///
+ /// The performance test scenario focused on downloading blobs from the Azure blobs storage.
+ ///
+ ///
+ public sealed class DownloadBlob : ContainerTest
+ {
+ private readonly CloudBlockBlob _cloudBlockBlob;
+
+ public DownloadBlob(SizeOptions options) : base(options)
+ {
+ _cloudBlockBlob = CloudBlobContainer.GetBlockBlobReference("Microsoft.Azure.Storage.Blob.Perf.Scenarios.DownloadBlob");
+ }
+
+ public override async Task GlobalSetupAsync()
+ {
+ await base.GlobalSetupAsync();
+
+ using Stream stream = RandomStream.Create(Options.Size);
+
+ // No need to delete file in GlobalCleanup(), since ContainerTest.GlobalCleanup() deletes the whole container
+ await _cloudBlockBlob.UploadFromStreamAsync(stream);
+ }
+
+ public override void Run(CancellationToken cancellationToken)
+ {
+ _cloudBlockBlob.DownloadToStream(Stream.Null);
+ }
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
+ {
+ await _cloudBlockBlob.DownloadToStreamAsync(Stream.Null, cancellationToken);
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Scenarios/UploadBlob.cs b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Scenarios/UploadBlob.cs
new file mode 100644
index 000000000000..0222eabe5482
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/Microsoft.Azure.Storage.Blob.Perf/Scenarios/UploadBlob.cs
@@ -0,0 +1,42 @@
+//Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+using Azure.Test.Perf;
+
+namespace Microsoft.Azure.Storage.Blob.Perf.Scenarios
+{
+ ///
+ /// The performance test scenario focused on uploading blobs to the Azure blobs storage.
+ ///
+ ///
+ public sealed class UploadBlob : BlobTest
+ {
+ private readonly Stream _stream;
+
+ public UploadBlob(SizeOptions options) : base(options)
+ {
+ _stream = RandomStream.Create(options.Size);
+ }
+
+ public override void Dispose(bool disposing)
+ {
+ _stream.Dispose();
+ base.Dispose(disposing);
+ }
+
+ public override void Run(CancellationToken cancellationToken)
+ {
+ _stream.Seek(0, SeekOrigin.Begin);
+ CloudBlockBlob.UploadFromStream(_stream);
+ }
+
+ public override async Task RunAsync(CancellationToken cancellationToken)
+ {
+ _stream.Seek(0, SeekOrigin.Begin);
+ await CloudBlockBlob.UploadFromStreamAsync(_stream, cancellationToken);
+ }
+ }
+}
diff --git a/sdk/storage/Azure.Storage.Blobs/perf/README.md b/sdk/storage/Azure.Storage.Blobs/perf/README.md
new file mode 100644
index 000000000000..0dd95508f6c2
--- /dev/null
+++ b/sdk/storage/Azure.Storage.Blobs/perf/README.md
@@ -0,0 +1,15 @@
+# Azure Storage Blobs performance tests
+
+The assets in this area comprise a set of performance tests for the [Azure Storage Blobs client library for .NET](https://github.com/Azure/azure-sdk-for-net/tree/master/sdk/storage/Azure.Storage.Blobs) and its associated ecosystem. The artifacts in this library are intended to be used primarily with the Azure SDK engineering system's testing infrastructure, but may also be run as stand-alone applications from the command line.
+
+## Contributing
+
+This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.microsoft.com.
+
+When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.
+
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+
+Please see our [contributing guide](https://github.com/Azure/azure-sdk-for-net/blob/master/sdk/eventhub/Azure.Messaging.EventHubs/CONTRIBUTING.md) for more information.
+
+
diff --git a/sdk/storage/Azure.Storage.sln b/sdk/storage/Azure.Storage.sln
index 7885d4a8da1f..b3c0f657ba2e 100644
--- a/sdk/storage/Azure.Storage.sln
+++ b/sdk/storage/Azure.Storage.sln
@@ -124,6 +124,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Storage.Blobs.ChangeF
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Core.TestFramework", "..\core\Azure.Core.TestFramework\src\Azure.Core.TestFramework.csproj", "{23B3D5C8-3160-4BD6-8B25-0D33C98ABE70}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Azure.Storage.Blobs.Perf", "Azure.Storage.Blobs\perf\Azure.Storage.Blobs.Perf\Azure.Storage.Blobs.Perf.csproj", "{CC33E052-9737-42A3-BEB5-060CA659F408}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Azure.Storage.Blob.Perf", "Azure.Storage.Blobs\perf\Microsoft.Azure.Storage.Blob.Perf\Microsoft.Azure.Storage.Blob.Perf.csproj", "{2FB0A438-7DCB-4748-8E95-BA495865AD1D}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Perf", "Perf", "{FBC7A205-B57A-44E7-A7CA-2E82F79A4D9C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -246,17 +252,29 @@ Global
{23B3D5C8-3160-4BD6-8B25-0D33C98ABE70}.Debug|Any CPU.Build.0 = Debug|Any CPU
{23B3D5C8-3160-4BD6-8B25-0D33C98ABE70}.Release|Any CPU.ActiveCfg = Release|Any CPU
{23B3D5C8-3160-4BD6-8B25-0D33C98ABE70}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CC33E052-9737-42A3-BEB5-060CA659F408}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CC33E052-9737-42A3-BEB5-060CA659F408}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CC33E052-9737-42A3-BEB5-060CA659F408}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CC33E052-9737-42A3-BEB5-060CA659F408}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2FB0A438-7DCB-4748-8E95-BA495865AD1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2FB0A438-7DCB-4748-8E95-BA495865AD1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2FB0A438-7DCB-4748-8E95-BA495865AD1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2FB0A438-7DCB-4748-8E95-BA495865AD1D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
+ {89578DF8-BF19-46BE-BEC9-48E76C216EC9} = {FBC7A205-B57A-44E7-A7CA-2E82F79A4D9C}
+ {66294703-8530-4A97-BC4A-F106DA6525EC} = {FBC7A205-B57A-44E7-A7CA-2E82F79A4D9C}
{3830DDDD-5BAB-44BD-9589-57B71E21381A} = {BC2C1207-3C0A-4217-A867-81B0C03D2519}
- {23B3D5C8-3160-4BD6-8B25-0D33C98ABE70} = {BC2C1207-3C0A-4217-A867-81B0C03D2519}
{69A8687B-B040-451E-A72E-295C6CFC1B8B} = {B93D17A7-F7D7-4A2E-9E57-7B6ED57EF749}
{AD85524A-FB82-475C-9907-27DBC2BE2945} = {9EF57C69-DC48-4E5C-BBD5-76E23E4ADDA6}
{6EEF892F-E4EE-4610-9C94-4B206D9E7152} = {F4218B06-A246-4762-984D-5BC852B62889}
{610DBA57-60FD-4115-8D74-F13A8428973E} = {B93D17A7-F7D7-4A2E-9E57-7B6ED57EF749}
+ {23B3D5C8-3160-4BD6-8B25-0D33C98ABE70} = {BC2C1207-3C0A-4217-A867-81B0C03D2519}
+ {CC33E052-9737-42A3-BEB5-060CA659F408} = {FBC7A205-B57A-44E7-A7CA-2E82F79A4D9C}
+ {2FB0A438-7DCB-4748-8E95-BA495865AD1D} = {FBC7A205-B57A-44E7-A7CA-2E82F79A4D9C}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F236F49-3FED-4E35-AF93-48BA7EB0D42A}