mirror of
https://github.com/Flow-Launcher/Flow.Launcher.git
synced 2026-03-11 08:54:32 +00:00
Merge pull request #3429 from Jack251970/stopwatch_api
New API Function from Stopwatch & Improve Program Plugin
This commit is contained in:
commit
c7303611a2
8 changed files with 77 additions and 59 deletions
|
|
@ -23,6 +23,8 @@ namespace Flow.Launcher.Core.Plugin
|
|||
/// </summary>
|
||||
public static class PluginManager
|
||||
{
|
||||
private static readonly string ClassName = nameof(PluginManager);
|
||||
|
||||
private static IEnumerable<PluginPair> _contextMenuPlugins;
|
||||
|
||||
public static List<PluginPair> AllPlugins { get; private set; }
|
||||
|
|
@ -194,7 +196,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
{
|
||||
try
|
||||
{
|
||||
var milliseconds = await Stopwatch.DebugAsync($"|PluginManager.InitializePlugins|Init method time cost for <{pair.Metadata.Name}>",
|
||||
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Init method time cost for <{pair.Metadata.Name}>",
|
||||
() => pair.Plugin.InitAsync(new PluginInitContext(pair.Metadata, API)));
|
||||
|
||||
pair.Metadata.InitTime += milliseconds;
|
||||
|
|
@ -266,7 +268,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
try
|
||||
{
|
||||
var milliseconds = await Stopwatch.DebugAsync($"|PluginManager.QueryForPlugin|Cost for {metadata.Name}",
|
||||
var milliseconds = await API.StopwatchLogDebugAsync(ClassName, $"Cost for {metadata.Name}",
|
||||
async () => results = await pair.Plugin.QueryAsync(query, token).ConfigureAwait(false));
|
||||
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
|
|
|||
|
|
@ -11,12 +11,17 @@ using Flow.Launcher.Infrastructure.Logger;
|
|||
#pragma warning restore IDE0005
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin;
|
||||
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
||||
|
||||
namespace Flow.Launcher.Core.Plugin
|
||||
{
|
||||
public static class PluginsLoader
|
||||
{
|
||||
private static readonly string ClassName = nameof(PluginsLoader);
|
||||
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
public static List<PluginPair> Plugins(List<PluginMetadata> metadatas, PluginsSettings settings)
|
||||
{
|
||||
var dotnetPlugins = DotNetPlugins(metadatas);
|
||||
|
|
@ -59,8 +64,7 @@ namespace Flow.Launcher.Core.Plugin
|
|||
|
||||
foreach (var metadata in metadatas)
|
||||
{
|
||||
var milliseconds = Stopwatch.Debug(
|
||||
$"|PluginsLoader.DotNetPlugins|Constructor init cost for {metadata.Name}", () =>
|
||||
var milliseconds = API.StopwatchLogDebug(ClassName, $"Constructor init cost for {metadata.Name}", () =>
|
||||
{
|
||||
Assembly assembly = null;
|
||||
IAsyncPlugin plugin = null;
|
||||
|
|
|
|||
|
|
@ -7,13 +7,20 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||
using Flow.Launcher.Infrastructure.Storage;
|
||||
using Flow.Launcher.Plugin;
|
||||
|
||||
namespace Flow.Launcher.Infrastructure.Image
|
||||
{
|
||||
public static class ImageLoader
|
||||
{
|
||||
// We should not initialize API in static constructor because it will create another API instance
|
||||
private static IPublicAPI api = null;
|
||||
private static IPublicAPI API => api ??= Ioc.Default.GetRequiredService<IPublicAPI>();
|
||||
|
||||
private static readonly string ClassName = nameof(ImageLoader);
|
||||
|
||||
private static readonly ImageCache ImageCache = new();
|
||||
private static SemaphoreSlim storageLock { get; } = new SemaphoreSlim(1, 1);
|
||||
private static BinaryStorage<List<(string, bool)>> _storage;
|
||||
|
|
@ -47,15 +54,14 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
|
||||
_ = Task.Run(async () =>
|
||||
{
|
||||
await Stopwatch.NormalAsync("|ImageLoader.Initialize|Preload images cost", async () =>
|
||||
await API.StopwatchLogInfoAsync(ClassName, "Preload images cost", async () =>
|
||||
{
|
||||
foreach (var (path, isFullImage) in usage)
|
||||
{
|
||||
await LoadAsync(path, isFullImage);
|
||||
}
|
||||
});
|
||||
Log.Info(
|
||||
$"|ImageLoader.Initialize|Number of preload images is <{ImageCache.CacheSize()}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
|
||||
API.LogInfo(ClassName, $"Number of preload images is <{ImageCache.CacheSize()}>, Images Number: {ImageCache.CacheSize()}, Unique Items {ImageCache.UniqueImagesInCache()}");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -71,7 +77,7 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
Log.Exception($"|ImageLoader.SaveAsync|Failed to save image cache to file", e);
|
||||
API.LogException(ClassName, "Failed to save image cache to file", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -166,8 +172,8 @@ namespace Flow.Launcher.Infrastructure.Image
|
|||
}
|
||||
catch (System.Exception e2)
|
||||
{
|
||||
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e);
|
||||
Log.Exception($"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2);
|
||||
API.LogException(ClassName, $"|ImageLoader.Load|Failed to get thumbnail for {path} on first try", e);
|
||||
API.LogException(ClassName, $"|ImageLoader.Load|Failed to get thumbnail for {path} on second try", e2);
|
||||
|
||||
ImageSource image = ImageCache[Constant.MissingImgIcon, false];
|
||||
ImageCache[path, false] = image;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
|
||||
|
|
@ -7,8 +6,6 @@ namespace Flow.Launcher.Infrastructure
|
|||
{
|
||||
public static class Stopwatch
|
||||
{
|
||||
private static readonly Dictionary<string, long> Count = new Dictionary<string, long>();
|
||||
private static readonly object Locker = new object();
|
||||
/// <summary>
|
||||
/// This stopwatch will appear only in Debug mode
|
||||
/// </summary>
|
||||
|
|
@ -62,36 +59,5 @@ namespace Flow.Launcher.Infrastructure
|
|||
Log.Info(info);
|
||||
return milliseconds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void StartCount(string name, Action action)
|
||||
{
|
||||
var stopWatch = new System.Diagnostics.Stopwatch();
|
||||
stopWatch.Start();
|
||||
action();
|
||||
stopWatch.Stop();
|
||||
var milliseconds = stopWatch.ElapsedMilliseconds;
|
||||
lock (Locker)
|
||||
{
|
||||
if (Count.ContainsKey(name))
|
||||
{
|
||||
Count[name] += milliseconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
Count[name] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void EndCount()
|
||||
{
|
||||
foreach (var key in Count.Keys)
|
||||
{
|
||||
string info = $"{key} already cost {Count[key]}ms";
|
||||
Log.Debug(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -473,5 +473,31 @@ namespace Flow.Launcher.Plugin
|
|||
/// </param>
|
||||
/// <returns></returns>
|
||||
public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false);
|
||||
|
||||
/// <summary>
|
||||
/// Log debug message of the time taken to execute a method
|
||||
/// Message will only be logged in Debug mode
|
||||
/// </summary>
|
||||
/// <returns>The time taken to execute the method in milliseconds</returns>
|
||||
public long StopwatchLogDebug(string className, string message, Action action, [CallerMemberName] string methodName = "");
|
||||
|
||||
/// <summary>
|
||||
/// Log debug message of the time taken to execute a method asynchronously
|
||||
/// Message will only be logged in Debug mode
|
||||
/// </summary>
|
||||
/// <returns>The time taken to execute the method in milliseconds</returns>
|
||||
public Task<long> StopwatchLogDebugAsync(string className, string message, Func<Task> action, [CallerMemberName] string methodName = "");
|
||||
|
||||
/// <summary>
|
||||
/// Log info message of the time taken to execute a method
|
||||
/// </summary>
|
||||
/// <returns>The time taken to execute the method in milliseconds</returns>
|
||||
public long StopwatchLogInfo(string className, string message, Action action, [CallerMemberName] string methodName = "");
|
||||
|
||||
/// <summary>
|
||||
/// Log info message of the time taken to execute a method asynchronously
|
||||
/// </summary>
|
||||
/// <returns>The time taken to execute the method in milliseconds</returns>
|
||||
public Task<long> StopwatchLogInfoAsync(string className, string message, Func<Task> action, [CallerMemberName] string methodName = "");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@ using Flow.Launcher.Plugin;
|
|||
using Flow.Launcher.ViewModel;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
||||
|
||||
namespace Flow.Launcher
|
||||
{
|
||||
|
|
@ -35,6 +34,8 @@ namespace Flow.Launcher
|
|||
|
||||
#region Private Fields
|
||||
|
||||
private static readonly string ClassName = nameof(App);
|
||||
|
||||
private static bool _disposed;
|
||||
private MainWindow _mainWindow;
|
||||
private readonly MainViewModel _mainVM;
|
||||
|
|
@ -136,7 +137,7 @@ namespace Flow.Launcher
|
|||
|
||||
private async void OnStartup(object sender, StartupEventArgs e)
|
||||
{
|
||||
await Stopwatch.NormalAsync("|App.OnStartup|Startup cost", async () =>
|
||||
await API.StopwatchLogInfoAsync(ClassName, "Startup cost", async () =>
|
||||
{
|
||||
// Because new message box api uses MessageBoxEx window,
|
||||
// if it is created and closed before main window is created, it will cause the application to exit.
|
||||
|
|
@ -313,7 +314,7 @@ namespace Flow.Launcher
|
|||
_disposed = true;
|
||||
}
|
||||
|
||||
Stopwatch.Normal("|App.Dispose|Dispose cost", () =>
|
||||
API.StopwatchLogInfo(ClassName, "Dispose cost", () =>
|
||||
{
|
||||
Log.Info("|App.Dispose|Begin Flow Launcher dispose ----------------------------------------------------");
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ using Flow.Launcher.Plugin.SharedCommands;
|
|||
using Flow.Launcher.ViewModel;
|
||||
using JetBrains.Annotations;
|
||||
using Squirrel;
|
||||
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
||||
|
||||
namespace Flow.Launcher
|
||||
{
|
||||
|
|
@ -431,6 +432,18 @@ namespace Flow.Launcher
|
|||
public Task UninstallPluginAsync(PluginMetadata pluginMetadata, bool removePluginSettings = false) =>
|
||||
PluginManager.UninstallPluginAsync(pluginMetadata, removePluginSettings);
|
||||
|
||||
public long StopwatchLogDebug(string className, string message, Action action, [CallerMemberName] string methodName = "") =>
|
||||
Stopwatch.Debug($"|{className}.{methodName}|{message}", action);
|
||||
|
||||
public Task<long> StopwatchLogDebugAsync(string className, string message, Func<Task> action, [CallerMemberName] string methodName = "") =>
|
||||
Stopwatch.DebugAsync($"|{className}.{methodName}|{message}", action);
|
||||
|
||||
public long StopwatchLogInfo(string className, string message, Action action, [CallerMemberName] string methodName = "") =>
|
||||
Stopwatch.Normal($"|{className}.{methodName}|{message}", action);
|
||||
|
||||
public Task<long> StopwatchLogInfoAsync(string className, string message, Func<Task> action, [CallerMemberName] string methodName = "") =>
|
||||
Stopwatch.NormalAsync($"|{className}.{methodName}|{message}", action);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Methods
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Controls;
|
||||
using Flow.Launcher.Infrastructure.Logger;
|
||||
using Flow.Launcher.Infrastructure.UserSettings;
|
||||
using Flow.Launcher.Plugin.Program.Programs;
|
||||
using Flow.Launcher.Plugin.Program.Views;
|
||||
|
|
@ -14,7 +13,6 @@ using Flow.Launcher.Plugin.Program.Views.Models;
|
|||
using Flow.Launcher.Plugin.SharedCommands;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Path = System.IO.Path;
|
||||
using Stopwatch = Flow.Launcher.Infrastructure.Stopwatch;
|
||||
|
||||
namespace Flow.Launcher.Plugin.Program
|
||||
{
|
||||
|
|
@ -32,6 +30,8 @@ namespace Flow.Launcher.Plugin.Program
|
|||
|
||||
internal static PluginInitContext Context { get; private set; }
|
||||
|
||||
private static readonly string ClassName = nameof(Main);
|
||||
|
||||
private static readonly List<Result> emptyResults = new();
|
||||
|
||||
private static readonly MemoryCacheOptions cacheOptions = new() { SizeLimit = 1560 };
|
||||
|
|
@ -109,7 +109,7 @@ namespace Flow.Launcher.Plugin.Program
|
|||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
Log.Debug("|Flow.Launcher.Plugin.Program.Main|Query operation cancelled");
|
||||
Context.API.LogDebug(ClassName, "Query operation cancelled");
|
||||
return emptyResults;
|
||||
}
|
||||
finally
|
||||
|
|
@ -188,7 +188,7 @@ namespace Flow.Launcher.Plugin.Program
|
|||
|
||||
var _win32sCount = 0;
|
||||
var _uwpsCount = 0;
|
||||
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|Preload programs cost", async () =>
|
||||
await Context.API.StopwatchLogInfoAsync(ClassName, "Preload programs cost", async () =>
|
||||
{
|
||||
var pluginCacheDirectory = Context.CurrentPluginMetadata.PluginCacheDirectoryPath;
|
||||
FilesFolders.ValidateDirectory(pluginCacheDirectory);
|
||||
|
|
@ -253,8 +253,8 @@ namespace Flow.Launcher.Plugin.Program
|
|||
_uwpsCount = _uwps.Count;
|
||||
_uwpsLock.Release();
|
||||
});
|
||||
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload win32 programs <{_win32sCount}>");
|
||||
Log.Info($"|Flow.Launcher.Plugin.Program.Main|Number of preload uwps <{_uwpsCount}>");
|
||||
Context.API.LogInfo(ClassName, $"Number of preload win32 programs <{_win32sCount}>");
|
||||
Context.API.LogInfo(ClassName, $"Number of preload uwps <{_uwpsCount}>");
|
||||
|
||||
var cacheEmpty = _win32sCount == 0 || _uwpsCount == 0;
|
||||
|
||||
|
|
@ -295,7 +295,7 @@ namespace Flow.Launcher.Plugin.Program
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception("|Flow.Launcher.Plugin.Program.Main|Failed to index Win32 programs", e);
|
||||
Context.API.LogException(ClassName, "Failed to index Win32 programs", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -320,7 +320,7 @@ namespace Flow.Launcher.Plugin.Program
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Exception("|Flow.Launcher.Plugin.Program.Main|Failed to index Uwp programs", e);
|
||||
Context.API.LogException(ClassName, "Failed to index Uwp programs", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
@ -332,12 +332,12 @@ namespace Flow.Launcher.Plugin.Program
|
|||
{
|
||||
var win32Task = Task.Run(async () =>
|
||||
{
|
||||
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|Win32Program index cost", IndexWin32ProgramsAsync);
|
||||
await Context.API.StopwatchLogInfoAsync(ClassName, "Win32Program index cost", IndexWin32ProgramsAsync);
|
||||
});
|
||||
|
||||
var uwpTask = Task.Run(async () =>
|
||||
{
|
||||
await Stopwatch.NormalAsync("|Flow.Launcher.Plugin.Program.Main|UWPProgram index cost", IndexUwpProgramsAsync);
|
||||
await Context.API.StopwatchLogInfoAsync(ClassName, "UWPProgram index cost", IndexUwpProgramsAsync);
|
||||
});
|
||||
|
||||
await Task.WhenAll(win32Task, uwpTask).ConfigureAwait(false);
|
||||
|
|
|
|||
Loading…
Reference in a new issue