kuiperzone / AvantGarde

Avalonia XAML Preview for Linux and Windows
GNU General Public License v3.0
219 stars 10 forks source link

High CPU usage on Linux #11

Closed hairlesshobo closed 1 year ago

hairlesshobo commented 1 year ago

First off, this project is awesome. I mean seriously, I can't believe it isn't listed in the awesome avalonia directory. I tried Rider and didn't like it nor the price tag, and this works wonderfully with VS Code. Seriously, thank you for such an awesome application.

With that said, I have encountered one thing that I want to run by you and see if this is expected or not. I am developing what is currently a very basic UI and it works great, but the CPU usage seems to be much higher than I would expect it to be. See below for screenshot and system specs. Is this sort of CPU usage expected?

Thanks in advance!

System

CPU: AMD Ryzen 5 3600 (6 core) RAM: 16 GB DDR4 OS: Linux Mint 21

flip@magneto:~$ dotnet --info
.NET SDK:
 Version:   7.0.100
 Commit:    e12b7af219

Runtime Environment:
 OS Name:     linuxmint
 OS Version:  21
 OS Platform: Linux
 RID:         linux-x64
 Base Path:   /usr/share/dotnet/sdk/7.0.100/

Host:
  Version:      7.0.0
  Architecture: x64
  Commit:       d099f075e4

.NET SDKs installed:
  7.0.100 [/usr/share/dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 7.0.0 [/usr/share/dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 7.0.0 [/usr/share/dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  DOTNET_ROOT       [/usr/share/dotnet]

global.json file:
  Not found

Learn more:
  https://aka.ms/dotnet/info

Download .NET:
  https://aka.ms/dotnet/download

Screenshots

image image

Last but definitely not least, is there somewhere I can donate as a "thank you" for the work you've already put into this? I checked the README and open collective and didn't find anything.

hairlesshobo commented 1 year ago

I pulled the source back and built it myself and ran it from CLI and this time I have a nice log to work with. It looks like the issue may actually be in my code and not in that of AvantGarde.. I have attached a copy of part of the log below, the log was flooding as fast as the terminal could update with the FRAME number incrementing each time.

Gonna do some more digging and get back to you.

MainWindow.OpenSolution
/home/flip/projects/family-history/manager/FamilyHistoryManager.sln
SolutionCache.AssignTo
SolutionCacheItem.AssignTo
Matched solution: /home/flip/projects/family-history/manager/FamilyHistoryManager.sln
Project cache count: 4
Solution project count: 4
Matched project: FoxHollow.FHM
Matched project: FoxHollow.FHM.Core
Matched project: FoxHollow.FHM.Shared
Matched project: FoxHollow.FHM.UI
Matched: /home/flip/projects/family-history/manager/FamilyHistoryManager.sln
MainWindow.SelectionChangedHandler
NEW SELECTED: FoxHollow.FHM.csproj
MainWindow.UpdateLoader
RemoteLoader.Update
RemoteLoader.UpdateThread
RemoteLoader.InvokePreviewReady
PreviewPane.Update
Payload: none
PreviewControl.Update
PAYLOAD: 
IsEmpty: True
Dimension: 
Error: 
PreviewPane.Update
Payload: none
PreviewControl.Update
PAYLOAD: 
IsEmpty: True
Dimension: 
Error: 
Write settings
WRITE WIDTH: 1229
MainWindow.SelectionChangedHandler
NEW SELECTED: ProcessTiffWindow.axaml
MainWindow.UpdateLoader
RemoteLoader.Update
RemoteLoader.UpdateThread
Root Name: Window
Is window
RemoteLoader.StartHostNoSync
AppAssembly: /home/flip/projects/family-history/manager/bin/FHM.dll
GetFreePort
Port: 33195
Process started OK
Connection received
Send scale: 1
Connection OK
RemoteLoader.SendXaml
AssemblyPath: /home/flip/projects/family-history/manager/bin/FHM.dll
XamlFileProjectPath: /Views/ProcessTiffWindow.axaml
RemoteLoader.MessageHandler
Message type: StartDesignerSessionMessage
RemoteLoader.MessageHandler
Message type: RequestViewportResizeMessage
RemoteLoader.MessageHandler
Message type: RequestViewportResizeMessage
RemoteLoader.MessageHandler
Message type: FrameMessage
FRAME: 1, 900 x 550 px, 1980000 bytes
factory null: False
IsImmediate: False
RemoteLoader.ToBitmap
Create bitmap
RemoteLoader.InvokePreviewReady
PreviewPane.Update
Payload: Xaml
PreviewControl.Update
PAYLOAD: ProcessTiffWindow.axaml
IsEmpty: False
Dimension: 900, 550
Error: 
Closed
RemoteLoader.MessageHandler
Message type: RequestViewportResizeMessage
RemoteLoader.MessageHandler
Message type: UpdateXamlResultMessage
UPDATE
Exception: Unable to resolve service of type 'ILogger`1'
Error: System.InvalidOperationException: Unable to resolve service of type 'ILogger`1'
   at FoxHollow.FHM.UI.Classes.Extensions.GetRequiredService[T](IReadonlyDependencyResolver resolver, String contract) in /home/flip/projects/family-history/manager/source/FoxHollow.FHM.UI/Classes/Extensions.cs:line 10
   at FoxHollow.FHM.UI.Views.ProcessTiffWindow.OnOpened(EventArgs e) in /home/flip/projects/family-history/manager/source/FoxHollow.FHM.UI/Views/ProcessTiffWindow.axaml.cs:line 68
   at Avalonia.Controls.Window.ShowCore(Window owner) in /_/src/Avalonia.Controls/Window.cs:line 725
   at Avalonia.Controls.Window.Show() in /_/src/Avalonia.Controls/Window.cs:line 606
   at Avalonia.DesignerSupport.DesignWindowLoader.LoadDesignerWindow(String xaml, String assemblyPath, String xamlFileProjectPath) in /_/src/Avalonia.DesignerSupport/DesignWindowLoader.cs:line 114
   at Avalonia.DesignerSupport.Remote.RemoteDesignerEntryPoint.<>c__DisplayClass17_0.<OnTransportMessage>b__0() in /_/src/Avalonia.DesignerSupport/Remote/RemoteDesignerEntryPoint.cs:line 248
Line number: 
Line Position: 
Failed
RemoteLoader.InvokePreviewReady
PreviewPane.Update
Payload: Xaml
PreviewControl.Update
PAYLOAD: ProcessTiffWindow.axaml
IsEmpty: True
Dimension: 
Error: Unable to resolve service of type 'ILogger`1'
Error line: 0
RemoteLoader.MessageHandler
Message type: FrameMessage
FRAME: 2, 900 x 550 px, 1980000 bytes
factory null: False
IsImmediate: False
RemoteLoader.ToBitmap
Create bitmap
RemoteLoader.InvokePreviewReady
PreviewPane.Update
Payload: Xaml
PreviewControl.Update
PAYLOAD: ProcessTiffWindow.axaml
IsEmpty: False
Dimension: 900, 550
Error: 
RemoteLoader.MessageHandler
Message type: FrameMessage
FRAME: 3, 900 x 550 px, 1980000 bytes
factory null: False
IsImmediate: False
RemoteLoader.ToBitmap
Create bitmap
RemoteLoader.InvokePreviewReady
PreviewPane.Update
Payload: Xaml
PreviewControl.Update
PAYLOAD: ProcessTiffWindow.axaml
IsEmpty: False
Dimension: 900, 550
Error: 
hairlesshobo commented 1 year ago

OK I fixed the ILogger related error but I still see the high cpu usage, even when displaying a basic window created by the avalonia.window dotnet template. I still see a massive flood of logs in the terminal anytime a view is open and constant CPU usage:

IsImmediate: True
RemoteLoader.MessageHandler
Message type: FrameMessage
FRAME: 4110, 800 x 450 px, 1440000 bytes
factory null: False
IsImmediate: True
RemoteLoader.MessageHandler
Message type: FrameMessage
FRAME: 4111, 800 x 450 px, 1440000 bytes
factory null: False
IsImmediate: True
RemoteLoader.MessageHandler
Message type: FrameMessage
FRAME: 4112, 800 x 450 px, 1440000 bytes
factory null: False
IsImmediate: True
RemoteLoader.MessageHandler
Message type: FrameMessage
FRAME: 4113, 800 x 450 px, 1440000 bytes
factory null: False
IsImmediate: True
kuiperzone commented 1 year ago

Hi,

Thank you for the feedback. I may quote you on my CV someday!

I'm certainly planning on an update with the release of Avalonia 11 and will look into this

What actually happens regarding previews is this:

Avalonia ships with an application called the "Preview Host". This is what loads your assembly and generates previews of your windows. Avant Garde launches the Preview Host and connects to it over a socket. This is the log you are seeing above. Avant Garde sends mouse movements and clicks down the wire to the Preview Host and the host sends back bitmaps in response.

I wouldn't be too surprised that there is a relatively high CPU load associated with this, but certainly I will take a look at it. The problem may not be at my end, however.

Out of interest, I'd spent several months trying to develop Avant Garde to load in and display project assemblies itself, but had run into difficulties regarding assembly versioning etc. It was then that I discovered the existence of the Avalonia Preview Host application which had been written to support IDE plugins. I recall that I was rather surprised that mouse interactions could be sent over the socket and preview updates sent back in response. However, on reflection, I'm not sure there was any better way of doing things.

hairlesshobo commented 1 year ago

I have a trial of Rider still, I will try out this same project I'm working on using the preview plugin they have built for Rider and see if there is similar cpu usage coming from the Avalonia Preview Host. For the record, AvantGarde is certainly still usable for me with this level of cpu usage. This reminds me of a project in the past where I had a while { } block running a conditional repeatedly without some sort of small delay injected. I think in the past I fixed this with like a 1ms Task.Delay call in my loop. Not saying this is even relevant here, but it's what first came to mind.

Gotta forgive me, not sure what "CV" means in this context. But hey, always happy to share praise where it is due.

kuiperzone commented 1 year ago

Could you try clicking on "Disable Events" with regard cpu usuage:

image

Also, yes do let me know if you get a similar usage with Rider. Cheers.

hairlesshobo commented 1 year ago

OK so I just tried the disable events, and it did not make a difference.. directly. I noticed something fascinating, however.. if events are disabled and I constantly move the mouse around the preview of my window in Avant Garde, cpu usage drops tremendously.. the moment the mouse stops moving, the cpu usage shoots back up!

Is there a chance that there is a loop somewhere on your side waiting for mouse movement to send back to the preview host and when there's nothing to handle, it's chewing threw extra cpu cycles?

kuiperzone commented 1 year ago

Just tried it. I'm not seeing any particularly high load. Do you have a test project I could use?

image

kuiperzone commented 1 year ago

however.. if events are disabled and I constantly move the mouse around the preview of my window in Avant Garde, cpu usage drops tremendously.. the moment the mouse stops moving, the cpu usage shoots back up!

Yes, that's interesting. And annoying...

I was working on something else. I'll end up investigating this now. Lol! :)

hairlesshobo commented 1 year ago

OK so I just tried it using the source code of Avant Garde and I don't have the high CPU usage. I am using avalonia 11 preview 5 so perhaps the problem is on the avalonia side. Let me try downgrading to the latest stable avalonia and see if it makes a difference.

hairlesshobo commented 1 year ago

Yeah so it is definitely related to Avalonia 11 preview 5 that I am running.. I created a base Avalonia MVVM app using the dotnet templates and CPU usage was super low.. I upgraded that to preview 5, and boom, high cpu usage. I have attached the project in case you are curious to play with it yourself.

avalonia-11-test.tar.gz

kuiperzone commented 1 year ago

Yes, with a simple Hello World app built with 11 preview 5, we get:

image

But if we make a few trivial mods to the project in order to get it to build against Avalona 10.18, when viewed with the same build of Avalonia, we get:

image

hairlesshobo commented 1 year ago

Did you try the constant mouse movement over the preview window on avalonia 11 preview 5, with events ~disabled~ enabled in Avant Garde?

~Edit: I can't reproduce that behavior with the sample app I provided, only on my main app. Hmm...~

Edit 2: Sorry, Friday is rotting my brain, apparently. I mixed that up.. Events need to be ENABLED and constant mouse movement and cpu usage drops while the mouse is moving.

kuiperzone commented 1 year ago

I've attached the project that builds against Avalonia 10.18. Had to disable ViewLocator class in order to get it to build, otherwise the same. This is the second screenshot above.

avalonia-test.zip

Will try your suggestion now.

kuiperzone commented 1 year ago

Yes, there is a noticeable drop in CPU usage with continuous mouse movements over the preview window.

kuiperzone commented 1 year ago

Can you confirm whether there is similar issue when built against 11 P5 and previewed through Rider?

hairlesshobo commented 1 year ago

I just loaded both projects (one at a time, of course) in Rider, the one against 10.18 and then the one against 11 preview 5 and I could not see a noticeable difference in CPU load between the two

kuiperzone commented 1 year ago

I also note that the Preview Host for 11 P5 no longer seems to accept fully qualified image paths in the XML. Selecting the "Prefetch Assets" option seems to break the preview.

kuiperzone commented 1 year ago

I just loaded both projects (one at a time, of course) in Rider, the one against 10.18 and then the one against 11 preview 5 and I could not see a noticeable difference in CPU load between the two

OK. Thanks

hairlesshobo commented 1 year ago

OK check this out, I think this is the problem here..

https://github.com/AvaloniaUI/Avalonia/issues/10203

kuiperzone commented 1 year ago

Yes, that looks like it.

hairlesshobo commented 1 year ago

so that brings me to my last question from above... anywhere I can donate? :)

kuiperzone commented 1 year ago

I'm afraid not. I never created to the project as a way to garner donations and I don't want the hassle of informing my accountant and paying tax. I created it for my own use on Linux and I'm glad you like it!

hairlesshobo commented 1 year ago

Fair enough. Know that I greatly appreciate your work and I hope that I am able to give back in some way some day!

kuiperzone commented 1 year ago

Seems fine now with 0.10.21 and 11.0.0.