kikipoulet / SukiUI

UI Theme for AvaloniaUI
MIT License
1.14k stars 99 forks source link

High CPU usage issues #167

Open Cardroid opened 2 months ago

Cardroid commented 2 months ago

Describe the bug I'm currently working on a program that draws audio plots. I'm aware of the high CPU utilization because of the work of drawing cool animations.

However, the program seems to be constantly drawing new frames on a still screen (even when there is no user input). CPU seems to be being wasted unnecessarily due to continuous frame refreshes. How can we improve it?

To Reproduce Steps to reproduce the behavior:

  1. Apply the Suki library and run the program.

Expected behavior CPU utilization should be close to 0% on a still screen without events

Screenshots without SukiUI low cpu CPU usage: 0% ~ 1%

with SukiUI high cpu CPU usage: 5% ~ 6%

Environment

The plotting library used ScottPlot

kikipoulet commented 2 months ago

Hi,

Unfortunately I noticed this behavior a few times ago. The problem is that it does not seem to be one thing in particular that trigger this, but the overall complexity of the logical tree. It's not just removing the dynamic background, or the dialog grid, that can solve this, everything that we use "add" a little complexity and it ends at 4-5%, even on my machine.

Well, it was my observation at least. But performance is a feature, and I kept that problem in my mind, it does not seem normal anyway. I think you maybe found more with the rendering observations, so if I summary well, SukiUI suddenly renders insane amount of frame there and there when normally it would cap at 30 fps ?

Moreover, can you try to use SukiUI theme without using SukiWindow to see what it produces ? just to see if it changes something, I suspect that the SukiWindow is the source of 90% of the performance problem.

It would be great if we find a way to fix this actually πŸ‘

Cardroid commented 2 months ago

Thank you for your answer. πŸ‘

I also want to continue using this wonderful library. After the development of the core BM, I will investigate it.

This is just my guess... I think it's related to background animation. (when I see a lot of GC calls at the beginning of the program running)

kikipoulet commented 2 months ago

Thanks for your kind words.

I don't think it's related to the background animation because it's just at startup, and removing it doesn't change anything, but maybe the fps mystery is related

kikipoulet commented 2 months ago

Just did a few test. The weird thing is that if you create a new project and add just one button without even suing SukiWindow, the CPU usage will already be +/- 3%. So the +/-5% of the SukiDemo project is quite normal after seeing that. It just seems that the existence of SukiUI trigger this πŸ˜Άβ€πŸŒ«οΈ

I wonder if it's about how styles or resources are declared or included ? Maybe there is a more optimized way ?

Can you confirm that just using a button in a blank window produce +/-3% CPU too ?

CyLuGh commented 2 months ago

My guess would be the BlurBackground.

I’ve just done a search in code to see if there was any ICustomDrawOperation. I used this in the past to draw a component with skia, and it also resulted in such CPU usage. It does not seem to execute only when the component is invalidated, it’s constantly being called to draw.

CyLuGh commented 2 months ago

The work around I found at the time is here: https://github.com/CyLuGh/HierarchyGrid/blob/main/src/HierarchyGrid.Avalonia/SKXamlCanvas.axaml.cs

It's a control that behaves mostly like the WPF SKCanvas. If I manage to find some time, I'll see if it solves the problem here, but you're free to try if I'm too slow ;)

kikipoulet commented 2 months ago

The BlurBackground isn't use anymore because it wasn't as efficient as I wanted it to be. So basically the file can be completely removed, and I've just tested SukiDemo whith it removed it logically doesn't change anything, so unfortunately it's not the reason.

The weird thing is that just using a button in a "normal avalonia" window already trigger 3-4%.

kikipoulet commented 2 months ago

I did few tests. It's interesting to create a simple window with a button and switch from simpletheme to SukiTheme in App.axaml without changing anything. The Suki variant needs more CPU, +/- 1.5 while SimpleTheme needs +/- 0.5%.

Just for a button. I noticed that few details could be optimized. I probably should remove some boxshadow in some controls because removing shadow from the button free a little percentage. Removing the custom font release some, removing cornerradius too .. Actually every single thing adds a little percentage.

So, it's more a bad news actually, because there is no miracle. At this point I think there are 3 things that could help :

kikipoulet commented 1 month ago

For reference/reminder, slight performance optimisation could be achieved by using more CompositionAnimations instead of transitions, like this example for GlassCard :

animation

The main problem is that not everything can be animated with CompositionAnimations, but it is reasonable to think about :

Cardroid commented 1 month ago

It's good to see it improving little by little. πŸ‘

I'm also attempting to trace the cause of this issue, but it seems like high CPU utilization and redrawing the frame are other issues.

As you mentioned, the complexity of the visual tree seems to be the main culprit for increasing CPU utilization. (Even if I removed the controls that I estimated would be heavy, such as background controls, etc., from the demo project, the same results were seen.) Unfortunately, I couldn't find where the trigger to redraw the frame was coming from. Tracking stack traces didn't provide any useful clues. πŸ₯²

sirdoombox commented 1 week ago

I've spent a little time looking into this as well, took a variety of snapshots in dotTrace and nothing jumps out at me from our end specific to anything we've implemented. Even after the inclusion of the ICustomDrawOperation needed to render the new dynamic background, I noticed little to no increase in CPU usage.

The only thing I have noticed is that WindowImpl.AppWndProc seems to pop up with a fairly high time, fairly often. That would generally point to an overly complex visual tree and inefficient messaging though it doesn't necessarily confirm either.

I'm reasonably concerned about this, we haven't really noticed any decreases in performance recently so there has to be some fundamental issues that are hanging around but it's hard to track down what precisely. I think the most productive use of time would be to try and convert every existing control and style to use the ControlTheme to minimise the need for selectors to be so widely used and flatten the visual tree wherever it's possible as well as investigating any alternative more efficient ways to deal with property change behaviours instead of using observables (though I believe this is the accepted way).

Major things like not hosting everything inside the SukiHost and simply having it draw on top may help, though it might be an idea to look at something a bit more mature like Material.Avalonia to see how they've implemented things as they have a large number of fairly complex controls and styles yet perform far better out of the box.

Maruhl commented 1 week ago

Hi, I on the other hand don't have an unusual CPU load but more GPU load.

I open the demo and the GPU load jumps from 2%->6~7%. Something is constantly triggered to repaint.

grafik

I then looked further for fun, and ended up with "SukiBackground". If I comment out the code in the "SukiWindow" - the GPU load still remains low. I also don't know if there are different loads for the users due to different CPU's and GPU's. Maybe I am completely wrong. I just wanted to throw it into the room.

sirdoombox commented 1 week ago

Yep GPU utilisation for the SukiBackground is much more preferable to CPU load, it was a conscious choice to start offloading some of the heavier visual aspects off to something much more designed for it. The GPU scales much, much better for things like this and leveraging hardware acceleration I believe was the right choice.

Really our only focus should be on the CPU and getting that as low as possible. There are probably optimisations that will improve GPU utilisation in SkiaSharp 3 but I'm not that concerned. SukiUI is very visually rich and as long as the appropriate hardware is being used to do a lot of heavy lifting then I'm a lot more comfortable with that personally.

I have gotten SukiUI running with SkiaSharp 3 preview locally and there's no major improvements, seems to be a fairly minor bump in fps but GPU/CPU utilisation seems to be mostly stable.