From a2b6bc9e5334e4357c10a5a6553486b2d9bd5e24 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 18 Jan 2022 18:10:00 +0900 Subject: [PATCH 1/2] Add benchmark coverage of variuos methods of reading properties from realm --- osu.Game.Benchmarks/BenchmarkRealmReads.cs | 139 +++++++++++++++++++++ 1 file changed, 139 insertions(+) create mode 100644 osu.Game.Benchmarks/BenchmarkRealmReads.cs diff --git a/osu.Game.Benchmarks/BenchmarkRealmReads.cs b/osu.Game.Benchmarks/BenchmarkRealmReads.cs new file mode 100644 index 0000000000..5b5bdf595d --- /dev/null +++ b/osu.Game.Benchmarks/BenchmarkRealmReads.cs @@ -0,0 +1,139 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using System.Threading; +using BenchmarkDotNet.Attributes; +using osu.Framework.Testing; +using osu.Framework.Threading; +using osu.Game.Beatmaps; +using osu.Game.Database; +using osu.Game.Rulesets.Osu; +using osu.Game.Tests.Resources; + +namespace osu.Game.Benchmarks +{ + public class BenchmarkRealmReads : BenchmarkTest + { + private TemporaryNativeStorage storage; + private RealmContextFactory realmFactory; + private UpdateThread updateThread; + + [Params(1, 100, 1000)] + public int ReadsPerFetch { get; set; } + + public override void SetUp() + { + storage = new TemporaryNativeStorage("realm-benchmark"); + storage.DeleteDirectory(string.Empty); + + realmFactory = new RealmContextFactory(storage, "client"); + + using (var context = realmFactory.CreateContext()) + context.Write(c => c.Add(TestResources.CreateTestBeatmapSetInfo(rulesets: new[] { new OsuRuleset().RulesetInfo }))); + + updateThread = new UpdateThread(() => { }, null); + updateThread.Start(); + } + + [Benchmark] + public void BenchmarkDirectPropertyRead() + { + using (var context = realmFactory.CreateContext()) + { + var beatmapSet = context.All().First(); + + for (int i = 0; i < ReadsPerFetch; i++) + { + string _ = beatmapSet.Beatmaps.First().Hash; + } + } + } + + [Benchmark] + public void BenchmarkDirectPropertyReadUpdateThread() + { + var done = new ManualResetEventSlim(); + + updateThread.Scheduler.Add(() => + { + try + { + var beatmapSet = realmFactory.Context.All().First(); + + for (int i = 0; i < ReadsPerFetch; i++) + { + string _ = beatmapSet.Beatmaps.First().Hash; + } + } + finally + { + done.Set(); + } + }); + + done.Wait(); + } + + [Benchmark] + public void BenchmarkRealmLivePropertyRead() + { + using (var context = realmFactory.CreateContext()) + { + var beatmapSet = context.All().First().ToLive(realmFactory); + + for (int i = 0; i < ReadsPerFetch; i++) + { + string _ = beatmapSet.PerformRead(b => b.Beatmaps.First().Hash); + } + } + } + + [Benchmark] + public void BenchmarkRealmLivePropertyReadUpdateThread() + { + var done = new ManualResetEventSlim(); + + updateThread.Scheduler.Add(() => + { + try + { + var beatmapSet = realmFactory.Context.All().First().ToLive(realmFactory); + + for (int i = 0; i < ReadsPerFetch; i++) + { + string _ = beatmapSet.PerformRead(b => b.Beatmaps.First().Hash); + } + } + finally + { + done.Set(); + } + }); + + done.Wait(); + } + + [Benchmark] + public void BenchmarkDetachedPropertyRead() + { + using (var context = realmFactory.CreateContext()) + { + var beatmapSet = context.All().First().Detach(); + + for (int i = 0; i < ReadsPerFetch; i++) + { + string _ = beatmapSet.Beatmaps.First().Hash; + } + } + } + + [GlobalCleanup] + public void Cleanup() + { + realmFactory?.Dispose(); + storage?.Dispose(); + updateThread?.Exit(); + } + } +} From 8ef50ff42dab85eaae680274ccd7d3b25a78de2f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 17 Jan 2022 17:28:01 +0900 Subject: [PATCH 2/2] Add safety to ensure `RealmLiveUnmanaged` is not used with managed instances --- osu.Game/Database/RealmLiveUnmanaged.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Database/RealmLiveUnmanaged.cs b/osu.Game/Database/RealmLiveUnmanaged.cs index ea50ccc1ff..97f2faa656 100644 --- a/osu.Game/Database/RealmLiveUnmanaged.cs +++ b/osu.Game/Database/RealmLiveUnmanaged.cs @@ -21,6 +21,9 @@ namespace osu.Game.Database /// The realm data. public RealmLiveUnmanaged(T data) { + if (data.IsManaged) + throw new InvalidOperationException($"Cannot use {nameof(RealmLiveUnmanaged)} with managed instances"); + Value = data; }