Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Internal] Binary Encoding: Adds performance tests with binary encoding enabled. #4911

Closed
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
namespace Microsoft.Azure.Cosmos.Benchmarks
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Columns;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using BenchmarkDotNet.Exporters.Csv;
using BenchmarkDotNet.Exporters;
using BenchmarkDotNet.Jobs;
using Microsoft.Azure.Cosmos.Performance.Tests.Benchmarks;
using Newtonsoft.Json;
using Microsoft.Azure.Cosmos.Json;

[MemoryDiagnoser]
[BenchmarkCategory("NewGateBenchmark")]
[Config(typeof(CustomBenchmarkConfig))]
public class BinaryEncodingEnabledBenchmark
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to model it as a param on existing Benchmark? (To avoid code duplication)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or derive from existing ItemBenchmark tests?

{
private MockedItemBenchmarkHelper benchmarkHelper;
private Container container;

// Parameter to control binary encoding flag
[Params(true)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please have it run with both true and false to see the impact of enabling it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code path when binary encoding is set to false is covered by existing MockedItemBenchmark.cs. But I can include false parameter here also if it adds more clarity.

public bool EnableBinaryResponseOnPointOperations;

[GlobalSetup]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is GlobalCleanup needed?

public async Task GlobalSetupAsync()
{
// Initialize the mocked environment
JsonSerializationFormat serializationFormat = this.EnableBinaryResponseOnPointOperations ? JsonSerializationFormat.Binary : JsonSerializationFormat.Text;
this.benchmarkHelper = new MockedItemBenchmarkHelper(serializationFormat: serializationFormat);
this.container = this.benchmarkHelper.TestContainer;

// Create the item in the container
using (MemoryStream ms = this.benchmarkHelper.GetItemPayloadAsStream())
using (ResponseMessage response = await this.container.CreateItemStreamAsync(
ms,
new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId)))
{
if ((int)response.StatusCode > 300 || response.Content == null)
{
throw new Exception($"Failed to create item with status code {response.StatusCode}");
}
}
}

[Benchmark]
public async Task CreateItemAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
ananth7592 marked this conversation as resolved.
Show resolved Hide resolved
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

ItemResponse<ToDoActivity> itemResponse = await this.container.CreateItemAsync(
item: this.benchmarkHelper.TestItem,
partitionKey: new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions: requestOptions);

if (itemResponse.StatusCode != HttpStatusCode.Created && itemResponse.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Error: Item {this.benchmarkHelper.TestItem.id} was not created.");
}
}

[Benchmark]
public async Task CreateItemStreamAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

using (MemoryStream ms = this.benchmarkHelper.GetItemPayloadAsStream())
using (ResponseMessage response = await this.container.CreateItemStreamAsync(
ms,
new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions))
{
if ((int)response.StatusCode > 300 || response.Content == null)
{
Console.WriteLine($"Error: Item {this.benchmarkHelper.TestItem.id} was not created stream.");
}
}
}

[Benchmark]
public async Task ReadItemAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

ItemResponse<ToDoActivity> itemResponse = await this.container.ReadItemAsync<ToDoActivity>(
id: MockedItemBenchmarkHelper.ExistingItemId,
partitionKey: new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions: requestOptions);

if (itemResponse.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Error: Item {MockedItemBenchmarkHelper.ExistingItemId} was not read.");
}
}

[Benchmark]
public async Task ReadItemStreamAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

ResponseMessage response = await this.container.ReadItemStreamAsync(
id: MockedItemBenchmarkHelper.ExistingItemId,
partitionKey: new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions: requestOptions);

if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Error: Item {MockedItemBenchmarkHelper.ExistingItemId} was not read stream.");
}
}

[Benchmark]
public async Task UpsertItemAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

ItemResponse<ToDoActivity> itemResponse = await this.container.UpsertItemAsync(
item: this.benchmarkHelper.TestItem,
partitionKey: new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions: requestOptions);

if (itemResponse.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Error: Item {this.benchmarkHelper.TestItem.id} was not upserted.");
}
}

[Benchmark]
public async Task UpsertItemStreamAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

using (MemoryStream ms = this.benchmarkHelper.GetItemPayloadAsStream())
using (ResponseMessage response = await this.container.UpsertItemStreamAsync(
ms,
new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions))
{
if ((int)response.StatusCode > 300 || response.Content == null)
{
Console.WriteLine($"Error: Item {this.benchmarkHelper.TestItem.id} was not upserted stream.");
}
}
}

[Benchmark]
public async Task ReplaceItemAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

ItemResponse<ToDoActivity> itemResponse = await this.container.ReplaceItemAsync(
item: this.benchmarkHelper.TestItem,
id: MockedItemBenchmarkHelper.ExistingItemId,
partitionKey: new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions: requestOptions);

if (itemResponse.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Error: Item {this.benchmarkHelper.TestItem.id} was not replaced.");
}
}

[Benchmark]
public async Task ReplaceItemStreamAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

using (MemoryStream ms = this.benchmarkHelper.GetItemPayloadAsStream())
using (ResponseMessage response = await this.container.ReplaceItemStreamAsync(
ms,
MockedItemBenchmarkHelper.ExistingItemId,
new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions))
{
if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Error: Item {this.benchmarkHelper.TestItem.id} was not replaced stream.");
}
}
}

[Benchmark]
public async Task DeleteItemAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

ItemResponse<ToDoActivity> itemResponse = await this.container.DeleteItemAsync<ToDoActivity>(
id: MockedItemBenchmarkHelper.ExistingItemId,
partitionKey: new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions: requestOptions);

if (itemResponse.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Error: Item {MockedItemBenchmarkHelper.ExistingItemId} was not deleted: {itemResponse.StatusCode}");
}
}

[Benchmark]
public async Task DeleteItemStreamAsync()
{
ItemRequestOptions requestOptions = new ItemRequestOptions
{
EnableBinaryResponseOnPointOperations = this.EnableBinaryResponseOnPointOperations,
};

ResponseMessage response = await this.container.DeleteItemStreamAsync(
id: MockedItemBenchmarkHelper.ExistingItemId,
partitionKey: new PartitionKey(MockedItemBenchmarkHelper.ExistingItemId),
requestOptions: requestOptions);

if (response.StatusCode != HttpStatusCode.OK)
{
Console.WriteLine($"Error: Item {MockedItemBenchmarkHelper.ExistingItemId} was not deleted stream: {response.StatusCode}");
}
}

[GlobalCleanup]
public async Task CleanupAsync()
{
await Task.CompletedTask;
}

private class CustomBenchmarkConfig : ManualConfig
{
public CustomBenchmarkConfig()
{
this.AddColumn(StatisticColumn.OperationsPerSecond);
this.AddColumn(StatisticColumn.Q3);
this.AddColumn(StatisticColumn.P80);
this.AddColumn(StatisticColumn.P85);
this.AddColumn(StatisticColumn.P90);
this.AddColumn(StatisticColumn.P95);
this.AddColumn(StatisticColumn.P100);

this.AddDiagnoser(new IDiagnoser[] { MemoryDiagnoser.Default, ThreadingDiagnoser.Default });
this.AddColumnProvider(DefaultConfig.Instance.GetColumnProviders().ToArray());

// Minimal run to reduce time
this.AddJob(Job.ShortRun
.WithStrategy(BenchmarkDotNet.Engines.RunStrategy.Throughput));

this.AddExporter(HtmlExporter.Default);
this.AddExporter(CsvExporter.Default);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@ namespace Microsoft.Azure.Cosmos.Performance.Tests.Benchmarks
{
using System;
using System.IO;
using System.Text;
using Microsoft.Azure.Cosmos;
using Microsoft.Azure.Cosmos.CosmosElements;
using Microsoft.Azure.Cosmos.Json;
using Microsoft.Azure.Cosmos.Json.Interop;
using Newtonsoft.Json;

/// <summary>
Expand All @@ -24,42 +27,63 @@ public class MockedItemBenchmarkHelper
internal ToDoActivity TestItem { get; }
internal CosmosClient TestClient { get; }
internal Container TestContainer { get; }

internal byte[] TestItemBytes { get; }
internal JsonSerializationFormat SerializationFormat { get; }

/// <summary>
/// Initializes a new instance of the <see cref="MockedItemBenchmark"/> class.
/// Initializes a new instance of the <see cref="MockedItemBenchmarkHelper"/> class.
/// </summary>
public MockedItemBenchmarkHelper(
internal MockedItemBenchmarkHelper(
bool useCustomSerializer = false,
bool includeDiagnosticsToString = false,
bool useBulk = false,
bool isDistributedTracingEnabled = false,
bool isClientMetricsEnabled = false)
bool isClientMetricsEnabled = false,
JsonSerializationFormat serializationFormat = JsonSerializationFormat.Text)
{
this.TestClient = MockDocumentClient.CreateMockCosmosClient(useCustomSerializer,
this.TestClient = MockDocumentClient.CreateMockCosmosClient(
useCustomSerializer,
(builder) => builder
.WithBulkExecution(useBulk)
.WithClientTelemetryOptions(new CosmosClientTelemetryOptions()
{
DisableDistributedTracing = !isDistributedTracingEnabled,
IsClientMetricsEnabled = isClientMetricsEnabled
}));
.WithBulkExecution(useBulk)
.WithClientTelemetryOptions(new CosmosClientTelemetryOptions()
{
DisableDistributedTracing = !isDistributedTracingEnabled,
IsClientMetricsEnabled = isClientMetricsEnabled
}));

this.TestContainer = this.TestClient.GetDatabase("myDB").GetContainer("myColl");
this.IncludeDiagnosticsToString = includeDiagnosticsToString;
this.SerializationFormat = serializationFormat;

// Load the test item from the JSON file
string payloadContent = File.ReadAllText("samplepayload.json");
this.TestItem = JsonConvert.DeserializeObject<ToDoActivity>(payloadContent);

using (FileStream tmp = File.OpenRead("samplepayload.json"))
using (MemoryStream ms = new MemoryStream())
// Serialize TestItem into the desired format (Text or Binary)
if (this.SerializationFormat == JsonSerializationFormat.Binary)
{
tmp.CopyTo(ms);
this.TestItemBytes = ms.ToArray();
using (CosmosDBToNewtonsoftWriter writer = new CosmosDBToNewtonsoftWriter(JsonSerializationFormat.Binary))
{
writer.Formatting = Newtonsoft.Json.Formatting.None;
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
serializer.Serialize(writer, this.TestItem);
this.TestItemBytes = writer.GetResult().ToArray();
}
}

using (MemoryStream ms = new MemoryStream(this.TestItemBytes))
else
{
string payloadContent = File.ReadAllText("samplepayload.json");
this.TestItem = JsonConvert.DeserializeObject<ToDoActivity>(payloadContent);
using (MemoryStream ms = new MemoryStream())
using (StreamWriter sw = new StreamWriter(ms, new UTF8Encoding(false, true), 1024, true))
using (Newtonsoft.Json.JsonWriter writer = new Newtonsoft.Json.JsonTextWriter(sw))
{
writer.Formatting = Newtonsoft.Json.Formatting.None;
Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
serializer.Serialize(writer, this.TestItem);
writer.Flush();
sw.Flush();
this.TestItemBytes = ms.ToArray();
}
}
}

Expand All @@ -74,7 +98,7 @@ public void IncludeDiagnosticToStringHelper(
string diagnostics = cosmosDiagnostics.ToString();
if (string.IsNullOrEmpty(diagnostics))
{
throw new Exception();
throw new Exception("Diagnostics string is empty.");
}
}

Expand All @@ -88,4 +112,4 @@ public MemoryStream GetItemPayloadAsStream()
publiclyVisible: true);
}
}
}
}
Loading
Loading