Fixes benchmark project

This commit is contained in:
Shannon
2021-07-05 14:38:40 -06:00
parent 9560a2801e
commit 040b155454
5 changed files with 9 additions and 645 deletions

View File

@@ -1,561 +0,0 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Loggers;
using Moq;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core.Services.Implement;
using System.Xml.Linq;
using Umbraco.Core.Logging;
using Umbraco.Tests.Benchmarks.Config;
using Umbraco.Core.Services;
using Umbraco.Core;
using System.Xml.XPath;
using ILogger = Umbraco.Core.Logging.ILogger;
namespace Umbraco.Tests.Benchmarks
{
[QuickRunWithMemoryDiagnoserConfig]
public class LocalizedTextServiceGetAllStoredValuesBenchmarks
{
private CultureInfo culture;
private OldLocalizedTextService _dictionaryService;
private OldLocalizedTextService _xmlService;
private LocalizedTextService _optimized;
private LocalizedTextService _optimizedDict;
[GlobalSetup]
public void Setup()
{
culture = CultureInfo.GetCultureInfo("en-US");
_dictionaryService = GetDictionaryLocalizedTextService(culture);
_xmlService = GetXmlService(culture);
_optimized = GetOptimizedService(culture);
_optimizedDict = GetOptimizedServiceDict(culture);
var result1 = _dictionaryService.Localize("language", culture);
var result2 = _xmlService.Localize("language", culture);
var result3 = _dictionaryService.GetAllStoredValues(culture);
var result4 = _xmlService.GetAllStoredValues(culture);
var result5 = _optimized.GetAllStoredValues(culture);
var result6 = _xmlService.GetAllStoredValues(culture);
var result7 = _optimized.GetAllStoredValuesByAreaAndAlias(culture);
}
[Benchmark]
public void OriginalDictionaryGetAll()
{
for (int i = 0; i < 10000; i++)
{
var result = _dictionaryService.GetAllStoredValues(culture);
}
}
[Benchmark]
public void OriginalXmlGetAll()
{
for (int i = 0; i < 10000; i++)
{
var result = _xmlService.GetAllStoredValues(culture);
}
}
[Benchmark]
public void OriginalDictionaryLocalize()
{
for (int i = 0; i < 10000; i++)
{
var result = _dictionaryService.Localize("language", culture);
}
}
[Benchmark(Baseline = true)]
public void OriginalXmlLocalize()
{
for (int i = 0; i < 10000; i++)
{
var result = _xmlService.Localize("language", culture);
}
}
[Benchmark]
public void OptimizedXmlGetAll()
{
for (int i = 0; i < 10000; i++)
{
var result = _optimized.GetAllStoredValues(culture);
}
}
[Benchmark]
public void OptimizedDictGetAll()
{
for (int i = 0; i < 10000; i++)
{
var result = _optimizedDict.GetAllStoredValues(culture);
}
}
[Benchmark]
public void OptimizedDictGetAllV2()
{
for (int i = 0; i < 10000; i++)
{
var result = _optimizedDict.GetAllStoredValuesByAreaAndAlias(culture);
}
}
[Benchmark()]
public void OptimizedXmlLocalize()
{
for (int i = 0; i < 10000; i++)
{
var result = _optimized.Localize(null, "language", culture);
}
}
[Benchmark()]
public void OptimizedDictLocalize()
{
for (int i = 0; i < 10000; i++)
{
var result = _optimizedDict.Localize(null, "language", culture);
}
}
private static LocalizedTextService GetOptimizedServiceDict(CultureInfo culture)
{
return new LocalizedTextService(
new Dictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>
{
{
culture, new Dictionary<string, IDictionary<string, string>>
{
{
"testArea1", new Dictionary<string, string>
{
{"testKey1", "testValue1"},
{"testKey2", "testValue2"}
}
},
{
"testArea2", new Dictionary<string, string>
{
{"blah1", "blahValue1"},
{"blah2", "blahValue2"}
}
},
}
}
}, Mock.Of<Umbraco.Core.Logging.ILogger>());
}
private static LocalizedTextService GetOptimizedService(CultureInfo culture)
{
var txtService = new LocalizedTextService(new Dictionary<CultureInfo, Lazy<XDocument>>
{
{
culture, new Lazy<XDocument>(() => new XDocument(
new XElement("language",
new XElement("area", new XAttribute("alias", "testArea1"),
new XElement("key", new XAttribute("alias", "testKey1"), "testValue1"),
new XElement("key", new XAttribute("alias", "testKey2"), "testValue2")),
new XElement("area", new XAttribute("alias", "testArea2"),
new XElement("key", new XAttribute("alias", "blah1"), "blahValue1"),
new XElement("key", new XAttribute("alias", "blah2"), "blahValue2")))))
}
}, Mock.Of<Umbraco.Core.Logging.ILogger>());
return txtService;
}
private static OldLocalizedTextService GetXmlService(CultureInfo culture)
{
var txtService = new OldLocalizedTextService(new Dictionary<CultureInfo, Lazy<XDocument>>
{
{
culture, new Lazy<XDocument>(() => new XDocument(
new XElement("language",
new XElement("area", new XAttribute("alias", "testArea1"),
new XElement("key", new XAttribute("alias", "testKey1"), "testValue1"),
new XElement("key", new XAttribute("alias", "testKey2"), "testValue2")),
new XElement("area", new XAttribute("alias", "testArea2"),
new XElement("key", new XAttribute("alias", "blah1"), "blahValue1"),
new XElement("key", new XAttribute("alias", "blah2"), "blahValue2")))))
}
}, Mock.Of<Umbraco.Core.Logging.ILogger>());
return txtService;
}
private static OldLocalizedTextService GetDictionaryLocalizedTextService(CultureInfo culture)
{
return new OldLocalizedTextService(
new Dictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>>
{
{
culture, new Dictionary<string, IDictionary<string, string>>
{
{
"testArea1", new Dictionary<string, string>
{
{"testKey1", "testValue1"},
{"testKey2", "testValue2"}
}
},
{
"testArea2", new Dictionary<string, string>
{
{"blah1", "blahValue1"},
{"blah2", "blahValue2"}
}
},
}
}
}, Mock.Of<Umbraco.Core.Logging.ILogger>());
}
}
//Original
public class OldLocalizedTextService : ILocalizedTextService
{
private readonly ILogger _logger;
private readonly Lazy<LocalizedTextServiceFileSources> _fileSources;
private readonly IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> _dictionarySource;
private readonly IDictionary<CultureInfo, Lazy<XDocument>> _xmlSource;
/// <summary>
/// Initializes with a file sources instance
/// </summary>
/// <param name="fileSources"></param>
/// <param name="logger"></param>
public OldLocalizedTextService(Lazy<LocalizedTextServiceFileSources> fileSources, ILogger logger)
{
if (logger == null) throw new ArgumentNullException("logger");
_logger = logger;
if (fileSources == null) throw new ArgumentNullException("fileSources");
_fileSources = fileSources;
}
/// <summary>
/// Initializes with an XML source
/// </summary>
/// <param name="source"></param>
/// <param name="logger"></param>
public OldLocalizedTextService(IDictionary<CultureInfo, Lazy<XDocument>> source, ILogger logger)
{
if (source == null) throw new ArgumentNullException("source");
if (logger == null) throw new ArgumentNullException("logger");
_xmlSource = source;
_logger = logger;
}
/// <summary>
/// Initializes with a source of a dictionary of culture -> areas -> sub dictionary of keys/values
/// </summary>
/// <param name="source"></param>
/// <param name="logger"></param>
public OldLocalizedTextService(IDictionary<CultureInfo, IDictionary<string, IDictionary<string, string>>> source, ILogger logger)
{
_dictionarySource = source ?? throw new ArgumentNullException(nameof(source));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
}
public string Localize(string key, CultureInfo culture, IDictionary<string, string> tokens = null)
{
if (culture == null) throw new ArgumentNullException(nameof(culture));
// TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode
culture = ConvertToSupportedCultureWithRegionCode(culture);
//This is what the legacy ui service did
if (string.IsNullOrEmpty(key))
return string.Empty;
var keyParts = key.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
var area = keyParts.Length > 1 ? keyParts[0] : null;
var alias = keyParts.Length > 1 ? keyParts[1] : keyParts[0];
var xmlSource = _xmlSource ?? (_fileSources != null
? _fileSources.Value.GetXmlSources()
: null);
if (xmlSource != null)
{
return GetFromXmlSource(xmlSource, culture, area, alias, tokens);
}
else
{
return GetFromDictionarySource(culture, area, alias, tokens);
}
}
/// <summary>
/// Returns all key/values in storage for the given culture
/// </summary>
/// <returns></returns>
public IDictionary<string, string> GetAllStoredValues(CultureInfo culture)
{
if (culture == null) throw new ArgumentNullException("culture");
// TODO: Hack, see notes on ConvertToSupportedCultureWithRegionCode
culture = ConvertToSupportedCultureWithRegionCode(culture);
var result = new Dictionary<string, string>();
var xmlSource = _xmlSource ?? (_fileSources != null
? _fileSources.Value.GetXmlSources()
: null);
if (xmlSource != null)
{
if (xmlSource.ContainsKey(culture) == false)
{
_logger.Warn<OldLocalizedTextService>("The culture specified {Culture} was not found in any configured sources for this service", culture);
return result;
}
//convert all areas + keys to a single key with a '/'
result = GetStoredTranslations(xmlSource, culture);
//merge with the English file in case there's keys in there that don't exist in the local file
var englishCulture = new CultureInfo("en-US");
if (culture.Equals(englishCulture) == false)
{
var englishResults = GetStoredTranslations(xmlSource, englishCulture);
foreach (var englishResult in englishResults.Where(englishResult => result.ContainsKey(englishResult.Key) == false))
result.Add(englishResult.Key, englishResult.Value);
}
}
else
{
if (_dictionarySource.ContainsKey(culture) == false)
{
_logger.Warn<OldLocalizedTextService>("The culture specified {Culture} was not found in any configured sources for this service", culture);
return result;
}
//convert all areas + keys to a single key with a '/'
foreach (var area in _dictionarySource[culture])
{
foreach (var key in area.Value)
{
var dictionaryKey = string.Format("{0}/{1}", area.Key, key.Key);
//i don't think it's possible to have duplicates because we're dealing with a dictionary in the first place, but we'll double check here just in case.
if (result.ContainsKey(dictionaryKey) == false)
{
result.Add(dictionaryKey, key.Value);
}
}
}
}
return result;
}
private Dictionary<string, string> GetStoredTranslations(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo cult)
{
var result = new Dictionary<string, string>();
var areas = xmlSource[cult].Value.XPathSelectElements("//area");
foreach (var area in areas)
{
var keys = area.XPathSelectElements("./key");
foreach (var key in keys)
{
var dictionaryKey = string.Format("{0}/{1}", (string)area.Attribute("alias"),
(string)key.Attribute("alias"));
//there could be duplicates if the language file isn't formatted nicely - which is probably the case for quite a few lang files
if (result.ContainsKey(dictionaryKey) == false)
result.Add(dictionaryKey, key.Value);
}
}
return result;
}
/// <summary>
/// Returns a list of all currently supported cultures
/// </summary>
/// <returns></returns>
public IEnumerable<CultureInfo> GetSupportedCultures()
{
var xmlSource = _xmlSource ?? (_fileSources != null
? _fileSources.Value.GetXmlSources()
: null);
return xmlSource != null ? xmlSource.Keys : _dictionarySource.Keys;
}
/// <summary>
/// Tries to resolve a full 4 letter culture from a 2 letter culture name
/// </summary>
/// <param name="currentCulture">
/// The culture to determine if it is only a 2 letter culture, if so we'll try to convert it, otherwise it will just be returned
/// </param>
/// <returns></returns>
/// <remarks>
/// TODO: This is just a hack due to the way we store the language files, they should be stored with 4 letters since that
/// is what they reference but they are stored with 2, further more our user's languages are stored with 2. So this attempts
/// to resolve the full culture if possible.
///
/// This only works when this service is constructed with the LocalizedTextServiceFileSources
/// </remarks>
public CultureInfo ConvertToSupportedCultureWithRegionCode(CultureInfo currentCulture)
{
if (currentCulture == null) throw new ArgumentNullException("currentCulture");
if (_fileSources == null) return currentCulture;
if (currentCulture.Name.Length > 2) return currentCulture;
var attempt = _fileSources.Value.TryConvert2LetterCultureTo4Letter(currentCulture.TwoLetterISOLanguageName);
return attempt ? attempt.Result : currentCulture;
}
private string GetFromDictionarySource(CultureInfo culture, string area, string key, IDictionary<string, string> tokens)
{
if (_dictionarySource.ContainsKey(culture) == false)
{
_logger.Warn<OldLocalizedTextService>("The culture specified {Culture} was not found in any configured sources for this service", culture);
return "[" + key + "]";
}
var cultureSource = _dictionarySource[culture];
string found;
if (area.IsNullOrWhiteSpace())
{
found = cultureSource
.SelectMany(x => x.Value)
.Where(keyvals => keyvals.Key.InvariantEquals(key))
.Select(x => x.Value)
.FirstOrDefault();
}
else
{
found = cultureSource
.Where(areas => areas.Key.InvariantEquals(area))
.SelectMany(a => a.Value)
.Where(keyvals => keyvals.Key.InvariantEquals(key))
.Select(x => x.Value)
.FirstOrDefault();
}
if (found != null)
{
return ParseTokens(found, tokens);
}
//NOTE: Based on how legacy works, the default text does not contain the area, just the key
return "[" + key + "]";
}
private string GetFromXmlSource(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo culture, string area, string key, IDictionary<string, string> tokens)
{
if (xmlSource.ContainsKey(culture) == false)
{
_logger.Warn<OldLocalizedTextService>("The culture specified {Culture} was not found in any configured sources for this service", culture);
return "[" + key + "]";
}
var found = FindTranslation(xmlSource, culture, area, key);
if (found != null)
{
return ParseTokens(found.Value, tokens);
}
// Fall back to English by default if we can't find the key
found = FindTranslation(xmlSource, new CultureInfo("en-US"), area, key);
if (found != null)
return ParseTokens(found.Value, tokens);
// If it can't be found in either file, fall back to the default, showing just the key in square brackets
// NOTE: Based on how legacy works, the default text does not contain the area, just the key
return "[" + key + "]";
}
private XElement FindTranslation(IDictionary<CultureInfo, Lazy<XDocument>> xmlSource, CultureInfo culture, string area, string key)
{
var cultureSource = xmlSource[culture].Value;
var xpath = area.IsNullOrWhiteSpace()
? string.Format("//key [@alias = '{0}']", key)
: string.Format("//area [@alias = '{0}']/key [@alias = '{1}']", area, key);
var found = cultureSource.XPathSelectElement(xpath);
return found;
}
/// <summary>
/// Parses the tokens in the value
/// </summary>
/// <param name="value"></param>
/// <param name="tokens"></param>
/// <returns></returns>
/// <remarks>
/// This is based on how the legacy ui localized text worked, each token was just a sequential value delimited with a % symbol.
/// For example: hello %0%, you are %1% !
///
/// Since we're going to continue using the same language files for now, the token system needs to remain the same. With our new service
/// we support a dictionary which means in the future we can really have any sort of token system.
/// Currently though, the token key's will need to be an integer and sequential - though we aren't going to throw exceptions if that is not the case.
/// </remarks>
internal static string ParseTokens(string value, IDictionary<string, string> tokens)
{
if (tokens == null || tokens.Any() == false)
{
return value;
}
foreach (var token in tokens)
{
value = value.Replace(string.Format("{0}{1}{0}", "%", token.Key), token.Value);
}
return value;
}
}
// // * Summary *
// BenchmarkDotNet=v0.11.3, OS=Windows 10.0.18362
//Intel Core i5-8265U CPU 1.60GHz(Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
// [Host] : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.8.4250.0
// Job-JIATTD : .NET Framework 4.7.2 (CLR 4.0.30319.42000), 32bit LegacyJIT-v4.8.4250.0
//IterationCount=3 IterationTime=100.0000 ms LaunchCount = 1
//WarmupCount=3
// Method | Mean | Error | StdDev | Ratio | Gen 0/1k Op | Gen 1/1k Op | Gen 2/1k Op | Allocated Memory/Op |
//---------------------- |----------:|-----------:|----------:|------:|------------:|------------:|------------:|--------------------:|
// DictionaryGetAll | 11.199 ms | 1.8170 ms | 0.0996 ms | 0.14 | 1888.8889 | - | - | 5868.59 KB |
// XmlGetAll | 62.963 ms | 24.0615 ms | 1.3189 ms | 0.81 | 13500.0000 | - | - | 42448.71 KB |
// DictionaryLocalize | 9.757 ms | 1.6966 ms | 0.0930 ms | 0.13 | 1100.0000 | - | - | 3677.65 KB |
// XmlLocalize | 77.725 ms | 14.6069 ms | 0.8007 ms | 1.00 | 14000.0000 | - | - | 43032.8 KB |
// OptimizedXmlLocalize | 2.402 ms | 0.4256 ms | 0.0233 ms | 0.03 | 187.5000 | - | - | 626.01 KB |
// OptimizedDictLocalize | 2.345 ms | 0.2411 ms | 0.0132 ms | 0.03 | 187.5000 | - | - | 626.01 KB |
//// * Warnings *
//MinIterationTime
// LocalizedTextServiceGetAllStoredValuesBenchmarks.DictionaryGetAll: IterationCount= 3, IterationTime= 100.0000 ms, LaunchCount= 1, WarmupCount= 3->MinIterationTime = 99.7816 ms which is very small. It's recommended to increase it.
// LocalizedTextServiceGetAllStoredValuesBenchmarks.DictionaryLocalize: IterationCount= 3, IterationTime= 100.0000 ms, LaunchCount= 1, WarmupCount= 3->MinIterationTime = 96.7415 ms which is very small. It's recommended to increase it.
// LocalizedTextServiceGetAllStoredValuesBenchmarks.XmlLocalize: IterationCount= 3, IterationTime= 100.0000 ms, LaunchCount= 1, WarmupCount= 3->MinIterationTime = 76.8151 ms which is very small. It's recommended to increase it.
//// * Legends *
// Mean : Arithmetic mean of all measurements
// Error : Half of 99.9% confidence interval
// StdDev : Standard deviation of all measurements
// Ratio : Mean of the ratio distribution ([Current]/[Baseline])
// Gen 0/1k Op : GC Generation 0 collects per 1k Operations
// Gen 1/1k Op : GC Generation 1 collects per 1k Operations
// Gen 2/1k Op : GC Generation 2 collects per 1k Operations
// Allocated Memory/Op : Allocated memory per single operation(managed only, inclusive, 1KB = 1024B)
// 1 ms : 1 Millisecond(0.001 sec)
//// * Diagnostic Output - MemoryDiagnoser *
// // ***** BenchmarkRunner: End *****
// Run time: 00:00:09 (9.15 sec), executed benchmarks: 6
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Linq.Expressions;
using BenchmarkDotNet.Attributes;
using Microsoft.Extensions.Options;
@@ -9,7 +9,6 @@ using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.Mappers;
using Umbraco.Cms.Infrastructure.Persistence.Querying;
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
using Umbraco.Cms.Persistence.SqlCe;
namespace Umbraco.Tests.Benchmarks
{
@@ -19,7 +18,7 @@ namespace Umbraco.Tests.Benchmarks
protected Lazy<ISqlContext> MockSqlContext()
{
var sqlContext = Mock.Of<ISqlContext>();
var syntax = new SqlCeSyntaxProvider(Options.Create(new GlobalSettings()));
var syntax = new SqlServerSyntaxProvider(Options.Create(new GlobalSettings()));
Mock.Get(sqlContext).Setup(x => x.SqlSyntax).Returns(syntax);
return new Lazy<ISqlContext>(() => sqlContext);
}
@@ -36,7 +35,7 @@ namespace Umbraco.Tests.Benchmarks
_mapperCollection = mapperCollection.Object;
}
private readonly ISqlSyntaxProvider _syntaxProvider = new SqlCeSyntaxProvider(Options.Create(new GlobalSettings()));
private readonly ISqlSyntaxProvider _syntaxProvider = new SqlServerSyntaxProvider(Options.Create(new GlobalSettings()));
private readonly CachedExpression _cachedExpression;
private readonly IMapperCollection _mapperCollection;

View File

@@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Umbraco.Tests.Benchmarks")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Umbraco.Tests.Benchmarks")]
[assembly: AssemblyCopyright("Copyright © 2018")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("3a33adc9-c6c0-4db1-a613-a9af0210df3d")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@@ -1,4 +1,4 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Diagnosers;
using Microsoft.Extensions.Options;
@@ -6,7 +6,7 @@ using NPoco;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.Mappers;
using Umbraco.Cms.Persistence.SqlCe;
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
using Umbraco.Extensions;
namespace Umbraco.Tests.Benchmarks
@@ -36,7 +36,7 @@ namespace Umbraco.Tests.Benchmarks
var mappers = new NPoco.MapperCollection( );
var factory = new FluentPocoDataFactory((type, iPocoDataFactory) => new PocoDataBuilder(type, mappers).Init());
SqlContext = new SqlContext(new SqlCeSyntaxProvider(Options.Create(new GlobalSettings())), DatabaseType.SQLCe, factory);
SqlContext = new SqlContext(new SqlServerSyntaxProvider(Options.Create(new GlobalSettings())), DatabaseType.SQLCe, factory);
SqlTemplates = new SqlTemplates(SqlContext);
}

View File

@@ -1,45 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<OutputType>Exe</OutputType>
<LangVersion>8</LangVersion>
<OutputType>Exe</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<LangVersion>7.3</LangVersion>
</PropertyGroup>
<ItemGroup>
<None Remove="CtorInvokeBenchmarks.cs.bak" />
<None Remove="ReflectionUtilities-Unused.cs.bak" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="BulkInsertBenchmarks.cs" />
<Compile Include="CombineGuidBenchmarks.cs" />
<Compile Include="ConcurrentDictionaryBenchmarks.cs" />
<Compile Include="Config\QuickRunConfigAttribute.cs" />
<Compile Include="Config\QuickRunWithMemoryDiagnoserConfigAttribute.cs" />
<Compile Include="CtorInvokeBenchmarks.cs" />
<Compile Include="HexStringBenchmarks.cs" />
<Compile Include="EnumeratorBenchmarks.cs" />
<Compile Include="JsonSerializerSettingsBenchmarks.cs" />
<Compile Include="LinqCastBenchmarks.cs" />
<Compile Include="LocalizedTextServiceGetAllStoredValuesBenchmarks.cs" />
<Compile Include="LoggerAllocationBenchmark.cs" />
<Compile Include="ModelToSqlExpressionHelperBenchmarks.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="SqlTemplatesBenchmark.cs" />
<Compile Include="StringReplaceManyBenchmarks.cs" />
<Compile Include="TryConvertToBenchmarks.cs" />
<Compile Include="XmlBenchmarks.cs" />
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
@@ -47,7 +14,6 @@
<ItemGroup>
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj" />
<ProjectReference Include="..\Umbraco.Infrastructure\Umbraco.Infrastructure.csproj" />
<ProjectReference Include="..\Umbraco.Persistence.SqlCe\Umbraco.Persistence.SqlCe.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet">
@@ -59,11 +25,7 @@
<PackageReference Include="Moq">
<Version>4.16.1</Version>
</PackageReference>
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers" Version="0.2.231403">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="System.Reflection.Emit" Version="4.7.0" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</ItemGroup>
</Project>