Skip to content

Commit c730361

Browse files
authored
Merge pull request #3429 from Jack251970/stopwatch_api
New API Function from Stopwatch & Improve Program Plugin
2 parents d230ebe + 1af9d06 commit c730361

File tree

8 files changed

+77
-59
lines changed

8 files changed

+77
-59
lines changed

Flow.Launcher.Core/Plugin/PluginManager.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ namespace Flow.Launcher.Core.Plugin
2323
/// </summary>
2424
public static class PluginManager
2525
{
26+
private static readonly string ClassName = nameof(PluginManager);
27+
2628
private static IEnumerable<PluginPair> _contextMenuPlugins;
2729

2830
public static List<PluginPair> AllPlugins { get; private set; }
@@ -194,7 +196,7 @@ public static async Task InitializePluginsAsync()
194196
{
195197
try
196198
{
197-
var milliseconds = await Stopwatch.DebugAsync($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>",
199+
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Init method time cost for <{pair.Metadata.Name}>",
198200
() => pair.Plugin.InitAsync(new PluginInitContext(pair.Metadata, API)));
199201

200202
pair.Metadata.InitTime += milliseconds;
@@ -266,7 +268,7 @@ public static async Task<List<Result>> QueryForPluginAsync(PluginPair pair, Quer
266268

267269
try
268270
{
269-
var milliseconds = await Stopwatch.DebugAsync($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}",
271+
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
270272
async () => results = await pair.Plugin.QueryAsync(query, token).ConfigureAwait(false));
271273

272274
token.ThrowIfCancellationRequested();

Flow.Launcher.Core/Plugin/PluginsLoader.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,17 @@
1111
#pragma warning restore IDE0005
1212
using Flow.Launcher.Infrastructure.UserSettings;
1313
using Flow.Launcher.Plugin;
14-
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
1514

1615
namespace Flow.Launcher.Core.Plugin
1716
{
1817
public static class PluginsLoader
1918
{
19+
private static readonly string ClassName = nameof(PluginsLoader);
20+
21+
// We should not initialize API in static constructor because it will create another API instance
22+
private static IPublicAPI api = null;
23+
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
24+
2025
public static List<PluginPair> Plugins(List<PluginMetadata> metadatas, PluginsSettings settings)
2126
{
2227
var dotnetPlugins = DotNetPlugins(metadatas);
@@ -59,8 +64,7 @@ private static IEnumerable<PluginPair> DotNetPlugins(List<PluginMetadata> source
5964

6065
foreach (var metadata in metadatas)
6166
{
62-
var milliseconds = Stopwatch.Debug(
63-
$"|PluginsLoader.DotNetPlugins|Constructor init cost for {metadata.Name}", () =>
67+
var milliseconds = API.StopwatchLogDebug(ClassName, $"Constructor init cost for {metadata.Name}", () =>
6468
{
6569
Assembly assembly = null;
6670
IAsyncPlugin plugin = null;

Flow.Launcher.Infrastructure/Image/ImageLoader.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,20 @@
77
using System.Threading.Tasks;
88
using System.Windows.Media;
99
using System.Windows.Media.Imaging;
10-
using Flow.Launcher.Infrastructure.Logger;
10+
using CommunityToolkit.Mvvm.DependencyInjection;
1111
using Flow.Launcher.Infrastructure.Storage;
12+
using Flow.Launcher.Plugin;
1213

1314
namespace Flow.Launcher.Infrastructure.Image
1415
{
1516
public static class ImageLoader
1617
{
18+
// We should not initialize API in static constructor because it will create another API instance
19+
private static IPublicAPI api = null;
20+
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
21+
22+
private static readonly string ClassName = nameof(ImageLoader);
23+
1724
private static readonly ImageCache ImageCache = new();
1825
private static SemaphoreSlim storageLock { get; } = new SemaphoreSlim(1, 1);
1926
private static BinaryStorage<List<(string, bool)>> _storage;
@@ -47,15 +54,14 @@ public static async Task InitializeAsync()
4754

4855
_ = Task.Run(async () =>
4956
{
50-
await Stopwatch.NormalAsync("|ImageLoader.Initialize|Preload images cost", async () =>
57+
await API.StopwatchLogInfoAsync(ClassName, "Preload images cost", async () =>
5158
{
5259
foreach (var (path, isFullImage) in usage)
5360
{
5461
await LoadAsync(path, isFullImage);
5562
}
5663
});
57-
Log.Info(
58-
$"|ImageLoader.Initialize|Number of preload images is <{ImageCache.CacheSize()}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
64+
API.LogInfo(ClassName, $"Number of preload images is <{ImageCache.CacheSize()}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
5965
});
6066
}
6167

@@ -71,7 +77,7 @@ await _storage.SaveAsync(ImageCache.EnumerateEntries()
7177
}
7278
catch (System.Exception e)
7379
{
74-
Log.Exception($"|ImageLoader.SaveAsync|Failed to save image cache to file", e);
80+
API.LogException(ClassName, "Failed to save image cache to file", e);
7581
}
7682
finally
7783
{
@@ -166,8 +172,8 @@ private static async ValueTask<ImageResult> LoadInternalAsync(string path, bool
166172
}
167173
catch (System.Exception e2)
168174
{
169-
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e);
170-
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2);
175+
API.LogException(ClassName, $"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e);
176+
API.LogException(ClassName, $"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2);
171177

172178
ImageSource image = ImageCache[Constant.MissingImgIcon, false];
173179
ImageCache[path, false] = image;

Flow.Launcher.Infrastructure/Stopwatch.cs

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Threading.Tasks;
43
using Flow.Launcher.Infrastructure.Logger;
54

65
namespace Flow.Launcher.Infrastructure
76
{
87
public static class Stopwatch
98
{
10-
private static readonly Dictionary<string, long> Count = new Dictionary<string, long>();
11-
private static readonly object Locker = new object();
129
/// <summary>
1310
/// This stopwatch will appear only in Debug mode
1411
/// </summary>
@@ -62,36 +59,5 @@ public static async Task<long> NormalAsync(string message, Func<Task> action)
6259
Log.Info(info);
6360
return milliseconds;
6461
}
65-
66-
67-
68-
public static void StartCount(string name, Action action)
69-
{
70-
var stopWatch = new System.Diagnostics.Stopwatch();
71-
stopWatch.Start();
72-
action();
73-
stopWatch.Stop();
74-
var milliseconds = stopWatch.ElapsedMilliseconds;
75-
lock (Locker)
76-
{
77-
if (Count.ContainsKey(name))
78-
{
79-
Count[name] += milliseconds;
80-
}
81-
else
82-
{
83-
Count[name] = 0;
84-
}
85-
}
86-
}
87-
88-
public static void EndCount()
89-
{
90-
foreach (var key in Count.Keys)
91-
{
92-
string info = $"{key} already cost {Count[key]}ms";
93-
Log.Debug(info);
94-
}
95-
}
9662
}
9763
}

Flow.Launcher.Plugin/Interfaces/IPublicAPI.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,5 +473,31 @@ public interface IPublicAPI
473473
/// </param>
474474
/// <returns></returns>
475475
public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false);
476+
477+
/// <summary>
478+
/// Log debug message of the time taken to execute a method
479+
/// Message will only be logged in Debug mode
480+
/// </summary>
481+
/// <returns>The time taken to execute the method in milliseconds</returns>
482+
public long StopwatchLogDebug(string className, string message, Action action, [CallerMemberName] string methodName = "");
483+
484+
/// <summary>
485+
/// Log debug message of the time taken to execute a method asynchronously
486+
/// Message will only be logged in Debug mode
487+
/// </summary>
488+
/// <returns>The time taken to execute the method in milliseconds</returns>
489+
public Task<long> StopwatchLogDebugAsync(string className, string message, Func<Task> action, [CallerMemberName] string methodName = "");
490+
491+
/// <summary>
492+
/// Log info message of the time taken to execute a method
493+
/// </summary>
494+
/// <returns>The time taken to execute the method in milliseconds</returns>
495+
public long StopwatchLogInfo(string className, string message, Action action, [CallerMemberName] string methodName = "");
496+
497+
/// <summary>
498+
/// Log info message of the time taken to execute a method asynchronously
499+
/// </summary>
500+
/// <returns>The time taken to execute the method in milliseconds</returns>
501+
public Task<long> StopwatchLogInfoAsync(string className, string message, Func<Task> action, [CallerMemberName] string methodName = "");
476502
}
477503
}

Flow.Launcher/App.xaml.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using Flow.Launcher.ViewModel;
2222
using Microsoft.Extensions.DependencyInjection;
2323
using Microsoft.Extensions.Hosting;
24-
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
2524

2625
namespace Flow.Launcher
2726
{
@@ -35,6 +34,8 @@ public partial class App : IDisposable, ISingleInstanceApp
3534

3635
#region Private Fields
3736

37+
private static readonly string ClassName = nameof(App);
38+
3839
private static bool _disposed;
3940
private MainWindow _mainWindow;
4041
private readonly MainViewModel _mainVM;
@@ -136,7 +137,7 @@ public static void Main()
136137

137138
private async void OnStartup(object sender, StartupEventArgs e)
138139
{
139-
await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
140+
await API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>
140141
{
141142
// Because new message box api uses MessageBoxEx window,
142143
// if it is created and closed before main window is created, it will cause the application to exit.
@@ -313,7 +314,7 @@ protected virtual void Dispose(bool disposing)
313314
_disposed = true;
314315
}
315316

316-
Stopwatch.Normal("|App.Dispose|Dispose cost", () =>
317+
API.StopwatchLogInfo(ClassName, "Dispose cost", () =>
317318
{
318319
Log.Info("|App.Dispose|Begin Flow Launcher dispose ----------------------------------------------------");
319320

Flow.Launcher/PublicAPIInstance.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
using Flow.Launcher.ViewModel;
3232
using JetBrains.Annotations;
3333
using Squirrel;
34+
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
3435

3536
namespace Flow.Launcher
3637
{
@@ -431,6 +432,18 @@ public void InstallPlugin(UserPlugin plugin, string zipFilePath) =>
431432
public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false) =>
432433
PluginManager.UninstallPluginAsync(pluginMetadata, removePluginSettings);
433434

435+
public long StopwatchLogDebug(string className, string message, Action action, [CallerMemberName] string methodName = "") =>
436+
Stopwatch.Debug($"|{className}.{methodName}|{message}", action);
437+
438+
public Task<long> StopwatchLogDebugAsync(string className, string message, Func<Task> action, [CallerMemberName] string methodName = "") =>
439+
Stopwatch.DebugAsync($"|{className}.{methodName}|{message}", action);
440+
441+
public long StopwatchLogInfo(string className, string message, Action action, [CallerMemberName] string methodName = "") =>
442+
Stopwatch.Normal($"|{className}.{methodName}|{message}", action);
443+
444+
public Task<long> StopwatchLogInfoAsync(string className, string message, Func<Task> action, [CallerMemberName] string methodName = "") =>
445+
Stopwatch.NormalAsync($"|{className}.{methodName}|{message}", action);
446+
434447
#endregion
435448

436449
#region Private Methods

Plugins/Flow.Launcher.Plugin.Program/Main.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,13 @@
66
using System.Threading;
77
using System.Threading.Tasks;
88
using System.Windows.Controls;
9-
using Flow.Launcher.Infrastructure.Logger;
109
using Flow.Launcher.Infrastructure.UserSettings;
1110
using Flow.Launcher.Plugin.Program.Programs;
1211
using Flow.Launcher.Plugin.Program.Views;
1312
using Flow.Launcher.Plugin.Program.Views.Models;
1413
using Flow.Launcher.Plugin.SharedCommands;
1514
using Microsoft.Extensions.Caching.Memory;
1615
using Path = System.IO.Path;
17-
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
1816

1917
namespace Flow.Launcher.Plugin.Program
2018
{
@@ -32,6 +30,8 @@ public class Main : ISettingProvider, IAsyncPlugin, IPluginI18n, IContextMenu, I
3230

3331
internal static PluginInitContext Context { get; private set; }
3432

33+
private static readonly string ClassName = nameof(Main);
34+
3535
private static readonly List<Result> emptyResults = new();
3636

3737
private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 };
@@ -109,7 +109,7 @@ public async Task<List<Result>> QueryAsync(Query query, CancellationToken token)
109109
}
110110
catch (OperationCanceledException)
111111
{
112-
Log.Debug("|Flow.Launcher.Plugin.Program.Main|Query operation cancelled");
112+
Context.API.LogDebug(ClassName, "Query operation cancelled");
113113
return emptyResults;
114114
}
115115
finally
@@ -188,7 +188,7 @@ public async Task InitAsync(PluginInitContext context)
188188

189189
var _win32sCount = 0;
190190
var _uwpsCount = 0;
191-
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", async () =>
191+
await Context.API.StopwatchLogInfoAsync(ClassName, "Preload programs cost", async () =>
192192
{
193193
var pluginCacheDirectory = Context.CurrentPluginMetadata.PluginCacheDirectoryPath;
194194
FilesFolders.ValidateDirectory(pluginCacheDirectory);
@@ -253,8 +253,8 @@ static void MoveFile(string sourcePath, string destinationPath)
253253
_uwpsCount = _uwps.Count;
254254
_uwpsLock.Release();
255255
});
256-
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32sCount}>");
257-
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwpsCount}>");
256+
Context.API.LogInfo(ClassName, $"Number of preload win32 programs <{_win32sCount}>");
257+
Context.API.LogInfo(ClassName, $"Number of preload uwps <{_uwpsCount}>");
258258

259259
var cacheEmpty = _win32sCount == 0 || _uwpsCount == 0;
260260

@@ -295,7 +295,7 @@ public static async Task IndexWin32ProgramsAsync()
295295
}
296296
catch (Exception e)
297297
{
298-
Log.Exception("|Flow.Launcher.Plugin.Program.Main|Failed to index Win32 programs", e);
298+
Context.API.LogException(ClassName, "Failed to index Win32 programs", e);
299299
}
300300
finally
301301
{
@@ -320,7 +320,7 @@ public static async Task IndexUwpProgramsAsync()
320320
}
321321
catch (Exception e)
322322
{
323-
Log.Exception("|Flow.Launcher.Plugin.Program.Main|Failed to index Uwp programs", e);
323+
Context.API.LogException(ClassName, "Failed to index Uwp programs", e);
324324
}
325325
finally
326326
{
@@ -332,12 +332,12 @@ public static async Task IndexProgramsAsync()
332332
{
333333
var win32Task = Task.Run(async () =>
334334
{
335-
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32ProgramsAsync);
335+
await Context.API.StopwatchLogInfoAsync(ClassName, "Win32Program index cost", IndexWin32ProgramsAsync);
336336
});
337337

338338
var uwpTask = Task.Run(async () =>
339339
{
340-
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|UWPProgram index cost", IndexUwpProgramsAsync);
340+
await Context.API.StopwatchLogInfoAsync(ClassName, "UWPProgram index cost", IndexUwpProgramsAsync);
341341
});
342342

343343
await Task.WhenAll(win32Task, uwpTask).ConfigureAwait(false);

0 commit comments

Comments
 (0)