Skip to content

Commit

Permalink
Added some benchmarks, optimized SnakeCaseNamingPolicy
Browse files Browse the repository at this point in the history
  • Loading branch information
gosferano committed Sep 15, 2022
1 parent 454f376 commit de2f36a
Show file tree
Hide file tree
Showing 7 changed files with 2,402 additions and 5 deletions.
39 changes: 39 additions & 0 deletions Gw2Sharp.Benchmarks/ItemsPageDeserializeBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.IO;
using System.Text.Json;
using BenchmarkDotNet.Attributes;
using Gw2Sharp.WebApi.V2;
using Gw2Sharp.WebApi.V2.Models;

namespace Gw2Sharp.Benchmarks
{
[MedianColumn]
[MemoryDiagnoser]
public class ItemsPageDeserializeBenchmark
{
private const int OPERATIONS_PER_INVOKE = 50;
private byte[] jsonBytes = Array.Empty<byte>();
private JsonSerializerOptions? jsonSerializerOptions = null;
private object? dump;

[GlobalSetup]
public void GlobalSetup()
{
string path = Path.Combine("TestFiles", "Items", "Items.max_page_size.json");
this.jsonBytes = System.IO.File.ReadAllBytes(path);
this.jsonSerializerOptions = SerializationHelpers.GetJsonSerializerOptions();
}

[Benchmark(OperationsPerInvoke=OPERATIONS_PER_INVOKE)]
public object DeserializeItemsPage()
{
for (int i = 0; i < OPERATIONS_PER_INVOKE; ++i)
{
this.dump = JsonSerializer.Deserialize<IApiV2ObjectList<Item>>(this.jsonBytes, this.jsonSerializerOptions);
}

return this.dump!;
}
}
}

45 changes: 45 additions & 0 deletions Gw2Sharp.Benchmarks/ItemsPageGetCachedBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;

namespace Gw2Sharp.Benchmarks
{
/// <summary>
/// This benchmark essentially checks how much time
/// it takes to retrieve items page from the cache.
/// The page is initially loaded in <see cref="GlobalSetupAsync"/>
/// via <see cref="Gw2Client"/> once and retrieved from the same
/// instance during the benchmark.
/// </summary>
[MedianColumn]
[MemoryDiagnoser]
public class ItemsPageGetCachedBenchmark
{
private const int OPERATIONS_PER_INVOKE = 10;
private Connection? connection;
private Gw2Client? gw2Client;
private object? dump;

[GlobalSetup]
public async Task GlobalSetupAsync()
{
this.connection = new Connection();
this.gw2Client = new Gw2Client(this.connection);
await this.gw2Client.WebApi.V2.Items.PageAsync(1).ConfigureAwait(false);
}

[GlobalCleanup]
public void GlobalCleanup() => this.gw2Client!.Dispose();

[Benchmark(OperationsPerInvoke=OPERATIONS_PER_INVOKE)]
public async Task<object?> DeserializeItemsBulkFastestAsync()
{
for (int i = 0; i < OPERATIONS_PER_INVOKE; ++i)
{
this.dump = await this.gw2Client!.WebApi.V2.Items.PageAsync(1).ConfigureAwait(false);
}

return this.dump;
}
}
}

29 changes: 29 additions & 0 deletions Gw2Sharp.Benchmarks/SerializationHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@

using System.Text.Json;
using Gw2Sharp.Json;
using Gw2Sharp.Json.Converters;

namespace Gw2Sharp.Benchmarks
{
public class SerializationHelpers
{
public static JsonSerializerOptions GetJsonSerializerOptions()
{
var options = new JsonSerializerOptions
{
AllowTrailingCommas = true,
PropertyNameCaseInsensitive = true,
PropertyNamingPolicy = SnakeCaseNamingPolicy.SnakeCase
};
options.Converters.Add(new ApiEnumConverter());
options.Converters.Add(new ApiFlagsConverter());
options.Converters.Add(new ApiObjectConverter());
options.Converters.Add(new ApiObjectListConverter());
options.Converters.Add(new CastableTypeConverter());
options.Converters.Add(new DictionaryIntKeyConverter());
options.Converters.Add(new RenderUrlConverter(new Connection(), null!));
options.Converters.Add(new TimeSpanConverter());
return options;
}
}
}
38 changes: 38 additions & 0 deletions Gw2Sharp.Benchmarks/SnakeCaseJsonNamingPolicyBenchmark.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using BenchmarkDotNet.Attributes;
using Gw2Sharp.Json;

namespace Gw2Sharp.Benchmarks
{
[MedianColumn]
[MemoryDiagnoser]
public class SnakeCaseJsonNamingPolicyBenchmark
{
private const int OPERATIONS_PER_INVOKE = 1_000_000;
private static readonly SnakeCaseNamingPolicy policy = SnakeCaseNamingPolicy.SnakeCase;
private const string CONVENTIONAL_PROPERTY_NAME = "HypotheticalPropertyNameWithUnrealisticlyManyWords";
private const string UNCONVENTIONAL_PROPERTY_NAME = "HyPOThETicAl_PRopeRtYnAmE_wiThUNReAlisTicLyMaNy_wOrDs";
private object? dump;

[Benchmark(OperationsPerInvoke=OPERATIONS_PER_INVOKE)]
public object? ConvertConventionalPropertyNameFast()
{
for (int i = 0; i < OPERATIONS_PER_INVOKE; ++i)
{
this.dump = policy.ConvertName(CONVENTIONAL_PROPERTY_NAME);
}

return this.dump;
}

[Benchmark(OperationsPerInvoke=OPERATIONS_PER_INVOKE)]
public object? ConvertUnconventionalPropertyNameFast()
{
for (int i = 0; i < OPERATIONS_PER_INVOKE; ++i)
{
this.dump = policy.ConvertName(UNCONVENTIONAL_PROPERTY_NAME);
}

return this.dump;
}
}
}
43 changes: 43 additions & 0 deletions Gw2Sharp.Tests/Json/SnakeCaseJsonNamingPolicyTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Gw2Sharp.Json;
using Xunit;

namespace Gw2Sharp.Tests.Json.Converters
{
public class SnakeCaseNamingPolicyTests
{
[Fact]
public void ConvertsUpperCamelCase()
{
const string propertyName = "UpperCamelCasePropertyName";
string convertedPropertyName = SnakeCaseNamingPolicy.SnakeCase.ConvertName(propertyName);
Assert.Equal("upper_camel_case_property_name", convertedPropertyName);
}

[Fact]
public void ConvertsLowerCamelCase()
{
const string propertyName = "lowerCamelCasePropertyName";
string convertedPropertyName = SnakeCaseNamingPolicy.SnakeCase.ConvertName(propertyName);
Assert.Equal("lower_camel_case_property_name", convertedPropertyName);
}

[Fact]
public void PreservesSnakeCase()
{
const string propertyName = "snake_case_property_name";
string convertedPropertyName = SnakeCaseNamingPolicy.SnakeCase.ConvertName(propertyName);
Assert.Equal(propertyName, convertedPropertyName);
}

[Theory]
[InlineData("GuildWars2EOD", "guild_wars2_eod")]
[InlineData("GW2EndOfDragons", "gw2_end_of_dragons")]
[InlineData("LWSeason2", "lwseason2")]
[InlineData("LW_Season2", "lw_season2")]
public void HandlesAcronyms(string propertyName, string expectedConvertedPropertyName)
{
string convertedPropertyName = SnakeCaseNamingPolicy.SnakeCase.ConvertName(propertyName);
Assert.Equal(expectedConvertedPropertyName, convertedPropertyName);
}
}
}
Loading

0 comments on commit de2f36a

Please sign in to comment.