-
Notifications
You must be signed in to change notification settings - Fork 150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
High CPU usage issues #167
Comments
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 👍 |
Thank you for your answer. 👍 I also want to continue using this wonderful library. 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) |
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 |
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%. 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 ? |
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. |
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 ;) |
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%. |
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 :
|
For reference/reminder, slight performance optimisation could be achieved by using more CompositionAnimations instead of transitions, like this example for GlassCard : The main problem is that not everything can be animated with CompositionAnimations, but it is reasonable to think about :
|
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.) |
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 The only thing I have noticed is that 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 Major things like not hosting everything inside the |
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%. 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. |
Yep GPU utilisation for the 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. |
@kikipoulet I think i find what ploblem,but i'm not sure changing that will making another issues, I try it by myself the Cpu and Gpu nearly 0. |
Hi @ShawnXu97 , Actually, removing the call doesn't seem to change anything, except for the "animated background" functionality I think. @sirdoombox do you confirm ? Maybe we should just call the function when AnimationEnabled property is True ? Or I completely miss it ? During my test I don't notice any changes when removing it. |
I notice that the loading control have an incomplete animation if removing this, it seems to be the only problem. |
@kikipoulet I'm happy it helped~ about animation doesn't work maybe can try to add some Timer refresh the call to active it, I think the call is keep to draw new frame .but that will be low performance,maybe rebuild a new loading controll is better? |
Initially, SkiaSharp was used to draw our custom background. I guess this line is for the "Animated Background" option that is not a big problem to drop or render like that only in this case. It's a feature not even referenced in our documentation because honestly not a lot of peoples will use it. However, we recently used SkiaSharp too for the loading control because of a memory leak bug when using Inifinite Animation in Avalonia ( AvaloniaUI/Avalonia#17192 ) which, by the way, is quite a problem for the framework. But I'm not worried, the consistent CPU % leak was more a problem than a loading control, we'll just wait for sirdoombox who knows this part way better than me to see if there is a way to render loading at 60fps only, and correct the background to render only when a style change occurs, or if we look for another solution for the loading control to let the background render only at style changes and solve this issue. |
I've taken a quick look at this and indeed the invalidate visual call is a bit of a heavy hitter, unfortunately I can't find a way around it. The animations are entirely reliant on the invalidation of the visual. Trying to disable the invalidation when animations are disabled also requires a separate call to the UI thread and actually performs worse. I've tried a few things including changes to the priority and running a separate task at a much higher interval but it bumps into the same UI thread issue and ends up performing worse. I feel we're a sticky situation where any animations reliant on The only solution I see to this in the short term is finding a way to render the loading icon in a traditional way and completely removing animated effects from SukiUI. However there may be some obvious thing I'm missing which is causing such a noticeable hit to performance. (I will add a sidenote that as it stands I only see rare peaks of 5%-6% CPU usage and mostly hovering in the ~2% area in the demo app.) |
@sirdoombox Cpu using isn't the worse,When i use it the Gpu will 20%~30% on some device , I know the device is not very well but if i want to use it ,this is a big ploblem. I'm try debug the code,I think the call making Render is a loop ,the render isn't finish, the next render call is running , Is there any way to make the Render only render it self? PS: In this way i think it will refresh the whole window. |
The Unfortunately the problem is solely the
Unless there's something obvious I'm missing, Animation support will necessarily come with a pretty hefty performance hit because of that invalidate visual call, and any attempted solutions to disable the invalidate visual call when animations are disabled causes worse performance again as a separate UI thread invocation to grab the state of the The only solution to this particular performance woe is removal of animations entirely for the background, and of course a new approach to |
Completely agree, thanks for your time and sorry for the skia loading control we're already dropping 🫣 We can then disable skiasharp animations because of performance priority, disable the background animation in SukiDemo, and I'll just find a new trick for a loading control, I'm not worried about that. @ShawnXu97 if you want you can make the PR that just comment the InvalidateVisual call as you found it, otherwise I'll do it later. |
I will investigate SkiaSharp 3.0 as well if I get some time and go a bit more in depth to see if there are any improvements there, though I doubt it. I am happy to either strip out animations entirely from the underlying API or simply add some extra steps to allow people to force them on if they are happy to eat the performance cost (and I'll put this in the docs too) - it will also allow us to keep trying fixes and track improvements going forward. |
We must be careful with SkiaSharp 3.0 because when I tried it it was incompatible with some important libraries like LiveCharts that a lot of peoples (and I) use that are still on 2.8, it's kind of annoying |
I certainly wouldn't bring it into production but it would be nice to know if it's an issue that will eventually be solved or if it's a limit in Avalonia, would help plan around the feature for the future. I should have some time maybe this evening to fix up the underlying API to make animations a bit harder to enable with more warnings, I might also look to switch to attached properties for the background because duplicating properties in |
@sirdoombox @kikipoulet Unfortunately, we were working in the wrong direction from the beginning. After re reading the code, I found that ShaderToyrenderer and Loading are both inherited from Avalonia We don't need to deal with the issue of dynamic background anymore, just remove Dispatcher UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background); And by continuously calling the InvalidateVisual() method in ShaderToyrenderer and Loading, all issues were resolved! I didn't submit the PR directly because the method I wrote may not be very good, and I need to determine whether it is in rendering, otherwise it should not be called again, so I still need to trouble the two of you to handle it. |
It seems to move the problem. As a loading control is embedded in every Button control, the same behavior will happen in every page with a button. InvalidateVisual in Loading : Invalidate Visual disabled : However, it's normal that disabling the animation use less CPU, it's just that it seems a little excessive and maybe a pure avalonia animation will cost less, or maybe embed it better in the button. I will take a look and compare it with Avalonia animations to have more informations to base our decision on. |
@sirdoombox @kikipoulet @sirdoombox I am not familiar with exact implementation of rendering effects for SukiUI, but I might be able to share some useful information.
And of course, if re-triggering rendering is not necessary, it's much desired to avoid invalidating anything. |
So I compared with a loading control animated with Avalonia Animationand it seems to be quite comparable with skiasharp implementation : So I guess the plan can be :
Edit : fixed button/busyarea loading control in fae64e5, now no unnecessary loading control is attached and processing until loading property is true. Still need to make a clean skiasharp implementation or fallback to simple avalonia animation as no memory leak (#245) will happen unless genereting thousand of loading buttons. |
Utilising the I've taken a quick look at the I feel as if I'm getting a bit out of my wheelhouse here, rendering is not really something I'm super familiar with. |
If you need your background to continuously render, i.e. animating, then yes - you will need to invalidate it each frame. Normal It still will re-draw the app, but this time all work will be done on Render thread only, reusing most of the operations from previous frames. |
Note, it's forced by modern GPU based rendering APIs, like DX11/OpenGL, where it's easier to re-draw whole scene, then re-draw particular rectangle. But we do support the latter for embedded devices with framebuffer rendering. |
I quickly switched over to The underlying I think animated backgrounds are pretty much an impossibility in Avalonia at the moment, the need to redraw the entire window when a control at the very back covering the entire window is invalidated is just too big of a performance hit, 20% utilisation on a high end modern GPU isn't really reasonable for a simple visual feature on a desktop app. I'll rewrite everything internally to use |
This should be largely resolved at this point. Obviously enabling animations still has a pretty big impact on performance but the default state of SukiUI should now be significantly more performant with the switch to The only outstanding issues are that the I think the issue should stay open until |
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:
Expected behavior
CPU utilization should be close to 0% on a still screen without events
Screenshots
without SukiUI
CPU usage: 0% ~ 1%
with SukiUI
CPU usage: 5% ~ 6%
Environment
The plotting library used ScottPlot
The text was updated successfully, but these errors were encountered: