diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs index 22fb2f448..850aeb7e9 100644 --- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs +++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; +using System.Threading.Tasks; using Dalamud.Game.Text; using Dalamud.Interface; @@ -45,6 +46,8 @@ internal sealed class DalamudConfiguration : IInternalDisposableService [JsonIgnore] private bool isSaveQueued; + private Task? writeTask; + /// /// Delegate for the event that occurs when the dalamud configuration is saved. /// @@ -560,6 +563,9 @@ internal sealed class DalamudConfiguration : IInternalDisposableService { // Make sure that we save, if a save is queued while we are shutting down this.Update(); + + // Wait for the write task to finish + this.writeTask?.Wait(); } /// @@ -614,8 +620,22 @@ internal sealed class DalamudConfiguration : IInternalDisposableService if (this.configPath is null) throw new InvalidOperationException("configPath is not set."); - Service.Get().WriteAllText( - this.configPath, JsonConvert.SerializeObject(this, SerializerSettings)); + // Wait for previous write to finish + this.writeTask?.Wait(); + + this.writeTask = Task.Run(() => + { + Service.Get().WriteAllText( + this.configPath, + JsonConvert.SerializeObject(this, SerializerSettings)); + }).ContinueWith(t => + { + if (t.IsFaulted) + { + Log.Error(t.Exception, "Failed to save DalamudConfiguration to {Path}", this.configPath); + } + }); + this.DalamudConfigurationSaved?.Invoke(this); } } diff --git a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs index 7678b395e..f3ec882fc 100644 --- a/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Data/DataWindow.cs @@ -60,6 +60,7 @@ internal class DataWindow : Window, IDisposable new ToastWidget(), new UiColorWidget(), new UldWidget(), + new VfsWidget(), }; private readonly IOrderedEnumerable orderedModules; diff --git a/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs b/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs new file mode 100644 index 000000000..019d743bc --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Data/Widgets/VfsWidget.cs @@ -0,0 +1,102 @@ +using System.Diagnostics; +using System.IO; + +using Dalamud.Configuration.Internal; +using Dalamud.Storage; +using ImGuiNET; +using Serilog; + +namespace Dalamud.Interface.Internal.Windows.Data.Widgets; + +/// +/// Widget for displaying configuration info. +/// +internal class VfsWidget : IDataWindowWidget +{ + private int numBytes = 1024; + private int reps = 1; + + /// + public string[]? CommandShortcuts { get; init; } = { "vfs" }; + + /// + public string DisplayName { get; init; } = "VFS Performance"; + + /// + public bool Ready { get; set; } + + /// + public void Load() + { + this.Ready = true; + } + + /// + public void Draw() + { + var service = Service.Get(); + var dalamud = Service.Get(); + + ImGui.InputInt("Num bytes", ref this.numBytes); + ImGui.InputInt("Reps", ref this.reps); + + var path = Path.Combine(dalamud.StartInfo.WorkingDirectory!, "test.bin"); + + if (ImGui.Button("Write")) + { + Log.Information("=== WRITING ==="); + var data = new byte[this.numBytes]; + var stopwatch = new Stopwatch(); + var acc = 0L; + + for (var i = 0; i < this.reps; i++) + { + stopwatch.Restart(); + service.WriteAllBytes(path, data); + stopwatch.Stop(); + acc += stopwatch.ElapsedMilliseconds; + Log.Information("Turn {Turn} took {Ms}ms", i, stopwatch.ElapsedMilliseconds); + } + + Log.Information("Took {Ms}ms in total", acc); + } + + if (ImGui.Button("Read")) + { + Log.Information("=== READING ==="); + var stopwatch = new Stopwatch(); + var acc = 0L; + + for (var i = 0; i < this.reps; i++) + { + stopwatch.Restart(); + service.ReadAllBytes(path); + stopwatch.Stop(); + acc += stopwatch.ElapsedMilliseconds; + Log.Information("Turn {Turn} took {Ms}ms", i, stopwatch.ElapsedMilliseconds); + } + + Log.Information("Took {Ms}ms in total", acc); + } + + if (ImGui.Button("Test Config")) + { + var config = Service.Get(); + + Log.Information("=== READING ==="); + var stopwatch = new Stopwatch(); + var acc = 0L; + + for (var i = 0; i < this.reps; i++) + { + stopwatch.Restart(); + config.ForceSave(); + stopwatch.Stop(); + acc += stopwatch.ElapsedMilliseconds; + Log.Information("Turn {Turn} took {Ms}ms", i, stopwatch.ElapsedMilliseconds); + } + + Log.Information("Took {Ms}ms in total", acc); + } + } +}