Skip to content

Commit 92433a2

Browse files
andersjonssonanmo
andauthored
feat: Perf work (#183)
* added some type caching and use TryGetValue * changed InvocationCount * more examples * added phrasedata --------- Co-authored-by: anmo <anmo@multinet.se>
1 parent 956e440 commit 92433a2

4 files changed

Lines changed: 61 additions & 28 deletions

File tree

MN.L10n.Benchmark/MN.L10n.Benchmark.csproj

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,25 @@
1515
<ProjectReference Include="..\MN.L10n\MN.L10n.csproj" />
1616
</ItemGroup>
1717

18+
<ItemGroup>
19+
<None Update="language-1.json">
20+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
21+
</None>
22+
<None Update="language-2.json">
23+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
24+
</None>
25+
<None Update="language-3.json">
26+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
27+
</None>
28+
<None Update="language-4.json">
29+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
30+
</None>
31+
<None Update="languages.json">
32+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
33+
</None>
34+
<None Update="phrases.json">
35+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
36+
</None>
37+
</ItemGroup>
38+
1839
</Project>

MN.L10n.Benchmark/Program.cs

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using BenchmarkDotNet.Attributes;
33
using BenchmarkDotNet.Running;
44
using MN.L10n;
5+
using MN.L10n.FileProviders;
56
using System.Collections.Concurrent;
67
using System.Reflection;
78
using System.Text;
@@ -10,7 +11,7 @@
1011

1112

1213

13-
BenchmarkRunner.Run<SpanTest>();
14+
BenchmarkRunner.Run<Benchmarks>();
1415

1516

1617

@@ -19,7 +20,7 @@ public class BenchmarkL10nLanguageProvider : IL10nLanguageProvider
1920
{
2021
public string GetLanguage()
2122
{
22-
return "0";
23+
return "1";
2324
}
2425
}
2526

@@ -55,10 +56,10 @@ public class Foo
5556
}
5657

5758
[MemoryDiagnoser(true)]
58-
[InvocationCount(1_000_000)]
59-
public class SpanTest
59+
[InvocationCount(100_000)]
60+
public class Benchmarks
6061
{
61-
[Params("$data$", "Hej $data$ $count$ $many$", "$den här texten inleds med $data$$data2$")]
62+
[Params("$data$", "Hej $data$ $count$ $many$", "$den här texten inleds med $data$$data2$", "Här har vi en längre förklarande text utan dollartecken. Den här skulle t.ex. kunna finnas i ")]
6263
public string formatString { get; set; } = "";
6364
public static Foo args = new Foo { data = "Anders" };
6465

@@ -68,9 +69,9 @@ public void GlobalSetup()
6869
var dataProvider = new BenchmarkL10nDataProvider();
6970

7071
var stack = new Stack<string>();
71-
stack.Push("0");
72+
stack.Push("1");
7273
var items = new Dictionary<object, object>() { { "___l10nlang", stack } };
73-
var l10n = L10n.CreateInstance(new BenchmarkL10nLanguageProvider(), dataProvider, () => items);
74+
var l10n = L10n.CreateInstance(new BenchmarkL10nLanguageProvider(), new FileDataProvider(AppDomain.CurrentDomain.BaseDirectory), () => items);
7475
dataProvider.SaveL10n(l10n);
7576
}
7677

@@ -80,6 +81,12 @@ public void GetPhase()
8081
L10n._s(formatString, args);
8182
}
8283

84+
[Benchmark]
85+
public void GetPhaseWithoutArgs()
86+
{
87+
L10n._s(formatString);
88+
}
89+
8390
[Benchmark]
8491
public void FormatNamed()
8592
{

MN.L10n/L10n.cs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
using System.Threading;
66
using System.Threading.Tasks;
77
using MN.L10n.PhraseMetadata;
8+
using System.Reflection;
9+
using System.Text;
10+
using System.Xml;
811

912
namespace MN.L10n
1013
{
@@ -140,19 +143,21 @@ internal L10nTranslatedString __getPhrase(string phrase, object args = null)
140143
{
141144
if (lang.Phrases.TryGetValue(cleanedPhrase, out var phr))
142145
{
143-
if (phr.r.ContainsKey("0"))
146+
string getVal;
147+
148+
if (phr.r.TryGetValue("0", out getVal))
144149
{
145-
cleanedPhrase = phr.r["0"];
150+
cleanedPhrase = getVal;
146151
}
147152

148153
if (isPluralized && lang.AstPluralRule != null)
149154
{
150155
// Here there be dragons
151156
// Dynamic evaluation to get the phrase to use, based on the pluralization rule specified
152157
var phraseIndex = lang.AstPluralRule.Evaluate(GetCount(args)).ToString();
153-
if (phr.r.ContainsKey(phraseIndex))
158+
if (phr.r.TryGetValue(phraseIndex, out getVal))
154159
{
155-
cleanedPhrase = phr.r[phraseIndex];
160+
cleanedPhrase = getVal;
156161
}
157162
}
158163
}
@@ -182,41 +187,41 @@ internal L10nTranslatedString __getPhrase(string phrase, object args = null)
182187
return FormatNamed(withoutMetadata, args);
183188
}
184189

190+
private static ConcurrentDictionary<Type, PropertyInfo> IsPluralizedCache = new ConcurrentDictionary<Type, PropertyInfo>();
191+
185192
public static bool IsPluralized(object args = null)
186193
{
187194
if (args == null) return false;
188-
var t = args.GetType();
189-
foreach (var p in t.GetProperties())
190-
{
191-
if (p.Name == "__count") return true;
192-
}
193195

194-
return false;
196+
var t = args.GetType();
197+
return IsPluralizedCache.GetOrAdd(t, t.GetProperty("__count")) is not null;
195198
}
196199

197200
public static long GetCount(object args = null)
198201
{
199-
if (args == null) return 0;
200-
var t = args.GetType();
201-
foreach (var p in t.GetProperties())
202+
IsPluralizedCache.TryGetValue(args.GetType(), out var p);
203+
204+
if(p is not null)
202205
{
203-
if (p.Name == "__count")
204-
{
205-
long.TryParse(p.GetValue(args).ToString(), out long __count);
206-
return __count;
207-
}
206+
return Convert.ToInt64(p.GetValue(args));
207+
208208
}
209209

210210
return 0;
211211
}
212212

213+
private static ConcurrentDictionary<Type, PropertyInfo[]> propCache = new ConcurrentDictionary<Type, PropertyInfo[]>();
214+
213215
public static L10nTranslatedString FormatNamed(string formatString, object args = null)
214216
{
215217
if (args == null) return new L10nTranslatedString(formatString);
216218

217219
var t = args.GetType();
218220
var tmpVal = formatString;
219-
foreach (var p in t.GetProperties())
221+
222+
var props = propCache.GetOrAdd(t, tp => tp.GetProperties());
223+
224+
foreach (var p in props)
220225
{
221226
tmpVal = tmpVal.Replace("$" + p.Name + "$", p.GetValue(args)?.ToString());
222227
}

MN.L10n/MN.L10n.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>net472;netstandard2.0;net8.0;net9.0</TargetFrameworks>
4+
<TargetFrameworks>net48;netstandard2.0;net8.0;net9.0</TargetFrameworks>
55
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
66
<Company>MultiNet Interactive AB</Company>
77
<Authors>Chris Gårdenberg</Authors>
@@ -29,7 +29,7 @@ Translation package</Description>
2929
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
3030
<PlatformTarget>AnyCPU</PlatformTarget>
3131
</PropertyGroup>
32-
<ItemGroup Condition=" '$(TargetFramework)' == 'net472' ">
32+
<ItemGroup Condition=" '$(TargetFramework)' == 'net48' ">
3333
<Reference Include="System.Net.Http" />
3434
</ItemGroup>
3535
<ItemGroup>

0 commit comments

Comments
 (0)