fyne-io / fyne

Cross platform GUI toolkit in Go inspired by Material Design
https://fyne.io/
Other
24.46k stars 1.36k forks source link

v2.3.0 Performance and Memory issues #3499

Open Sharrnah opened 1 year ago

Sharrnah commented 1 year ago

Checklist

Describe the bug

I think everything might be related, so i am not opening Bugs for Performance and memory usage seperately:

I am using the exact same Code. Only change is using v.2.3.0 instead of v2.2.4 from Fyne.

Things i noticed:

Memory usage might be related to font rendering changes in the new release. And since i am using a rather large font to be able to render all possible characters from around 200 languages, this might be the result.

I am embedding and using Go Noto font: see https://github.com/satbyy/go-noto-universal

How to reproduce

Can be reproduced by building my project: https://github.com/Sharrnah/whispering-ui

But i guess its a general issue with the new release.

Screenshots

Fyne v2.2.4: fyne_v2 2 4

Fyne v2.3.0: fyne_v2 3 0

Example code

func main() {
    a := app.NewWithID("whispering")
    a.SetIcon(Resources.ResourceAppIconPng)

    a.Settings().SetTheme(&AppTheme{})

    w := a.NewWindow("Whispering Tiger")
    w.SetMaster()
    w.CenterOnScreen()
        //...
}

// theme.go
package main

import (
    "fyne.io/fyne/v2"
    "fyne.io/fyne/v2/theme"
    "image/color"
    "whispering-tiger-ui/Resources"
)

var (
    orange            = &color.NRGBA{R: 198, G: 123, B: 0, A: 255}
    orangeTransparent = &color.NRGBA{R: 198, G: 123, B: 0, A: 180}
)

type AppTheme struct{}

var _ fyne.Theme = (*AppTheme)(nil)

func (m AppTheme) Color(name fyne.ThemeColorName, variant fyne.ThemeVariant) color.Color {
    switch name {
    case theme.ColorNamePrimary:
        return orange
    case theme.ColorNameScrollBar:
        return orangeTransparent
    }

    variant = theme.VariantDark

    return theme.DefaultTheme().Color(name, variant)
}
func (m AppTheme) Icon(name fyne.ThemeIconName) fyne.Resource {
    return theme.DefaultTheme().Icon(name)
}

func (m AppTheme) Font(style fyne.TextStyle) fyne.Resource {
    return Resources.ResourceGoNotoTtf
}

func (m AppTheme) Size(name fyne.ThemeSizeName) float32 {
    return theme.DefaultTheme().Size(name)
}

Fyne version

2.3.0

Go compiler version

1.19.3

Operating system

Windows

Operating system version

Windows 10

Additional Information

No response

Jacalz commented 1 year ago

Looks like a possible duplicate of https://github.com/fyne-io/fyne/issues/3401

Sharrnah commented 1 year ago

But it's a lot more than double the used memory as mentioned in #3401

Sharrnah commented 1 year ago

Just as an update: tried v2.3.2 today. Memory usage after the update to v2.3.2 of fyne still increases exponentially when loading the font as resource into a custom theme.

Is perfectly fine and usable with v2.2.4

andydotxyz commented 1 year ago

Many of the text memory improvements were not back-ported to the release branch. There is a lot of new code in the replacement render which we didn't feel was sufficiently stable to release alongside the other fixes.

andydotxyz commented 1 year ago

It would be helpful if you could test against develop and see how it compares.

Sharrnah commented 1 year ago

thanks. tried the develop branch. no real noticable difference. the memory consumption maybe went down from ~1015mb to around 990mb. which is still way more then on v2.2.4.

dweymouth commented 1 year ago

I am running into memory issues as well with text-heavy UI elements. For example scrolling back and forth through a List widget with RichText rows displaying single lines of text, even when the data model only has 100 or so rows and it's displaying the same data over and over, causes memory to go up by hundreds of MB.

Edit: just tested with GoNotoCurrent.ttf from the Noto Universal repo @Sharrnah linked in the issue description. My app is completely unusable with that font even when bundling it in vs. setting it via the FYNE_FONT env variable. Memory use 1+GB within showing a few UI screens, and textual list scrolling is so laggy as to make it unusable.

Bluebugs commented 1 year ago

@dweymouth are you setting a font for your app too or using the default?

dweymouth commented 1 year ago

I was not setting a font initially, just using the default, on 2.3.1, and ran into the huge memory use scrolling through a textual list with ~100 rows. However it wasn't so bad as to make scrolling unsmooth despite the huge memory use.

Then I tried bundling and using the GoNotoCurrent.ttf font, which I would like to be able to do since my app has to render arbitrary Unicode strings, and it was just totally unusable in 2.3.1. Memory of 1+Gig after moving through just a few UI screens, anything rendering text would lag and scrolling through textual lists pretty much impossible.

If I downgrade to 2.2.4, I don't really have any issues even with the GoNotoCurrent.ttf. Though memory is a bit high I guess but reasonable.

andydotxyz commented 1 year ago

Thanks this context is very helpful. It seems like somewhere a cache is not clearing like it should. Notable that develop is similar, as a few more fixes have gone in there. We clearly have not identified the root cause yet!

andydotxyz commented 1 year ago

With all the new shaping info loaded we knew the starting size would go up a bit - but not like this, and it certainly should not spike with usage.

dweymouth commented 1 year ago

I don't know much about the Fyne internals but it's interesting that bundling the larger font causes such a huge spike even though it's displaying the same set of characters as with the default font. I'm guessing something is getting loaded for each glyph in the font even if that glyph has not been needed yet?

andydotxyz commented 1 year ago

A future change may be able to load a subset of the glyphs. I think we may need to work on that upstream in go-text.

andydotxyz commented 1 year ago

Can you please test against develop and see how things are now we have the go-text leak plugged?

Sharrnah commented 1 year ago

Tested it. Memory usage went down to 730MB. nice improvement. After some clicking around, it only went up to 744mb, but still far from the around 100mb when using v2.2.4.

also opening dropdown boxes with many entries is still much slower than on v2.2.4.

So for now i will still stick with v2.2.4. since having the GoNoto Font is really neccessary for an application that is supposed to also show Japanese or Arabic etc. letters.

andydotxyz commented 1 year ago

There are further improvements on develop thanks to the work of the go-text team.

prokher commented 5 months ago

Colleagues, I am now looking at the same issue. Looks like RichText inside the list consumes enormous amount of RAM and it is continuously growing when data updates. Here is what I see in the profiler. There are maximum of 500 items in the list:

(pprof) top
Showing nodes accounting for 239.18MB, 76.93% of 310.91MB total
Dropped 65 nodes (cum <= 1.55MB)
Showing top 10 nodes out of 148
      flat  flat%   sum%        cum   cum%
   67.50MB 21.71% 21.71%   115.50MB 37.15%  fyne.io/fyne/v2/widget.(*RichText).cachedSegmentVisual
   37.50MB 12.06% 33.77%    37.50MB 12.06%  fyne.io/fyne/v2/canvas.NewText
      25MB  8.04% 41.81%       25MB  8.04%  fyne.io/fyne/v2/canvas.NewRectangle (inline)
   24.50MB  7.88% 49.69%    24.50MB  7.88%  fyne.io/fyne/v2/widget.(*Hyperlink).syncSegments
   21.50MB  6.92% 56.61%    33.74MB 10.85%  fyne.io/fyne/v2/widget.NewRichText (inline)
   18.86MB  6.07% 62.68%    18.86MB  6.07%  github.com/go-text/typesetting/opentype/loader.(*Loader).findTableBuffer
   17.81MB  5.73% 68.40%   163.57MB 52.61%  fyne.io/fyne/v2/internal/cache.Renderer
    9.50MB  3.06% 71.46%       32MB 10.29%  fyne.io/fyne/v2/widget.(*markdownRenderer).Render.func1
    8.50MB  2.73% 74.19%     8.50MB  2.73%  fyne.io/fyne/v2/widget.NewHyperlinkWithStyle (inline)
    8.50MB  2.73% 76.93%     8.50MB  2.73%  net/url.parse

adding a print fmt.Printf("len(visualCache)=%d\n", len(t.visualCache)) into cachedSegmentVisual indicates constant growth of items in the visualCache collection.

Hope this helps somehow to fix the issue. At the moment it would be nice to have at least a workaround. Is there any?

andydotxyz commented 5 months ago

As every single item is new the cached textures will grow until not needed any more... After a minute we start evicting textures from the cache. Have you looked at memory usage over a longer period to see if it starts to re-use allocated memory?

In 2.5 we move to a more efficient text render cache which will significantly reduce this.

prokher commented 5 months ago

Have you looked at memory usage over a longer period to see if it starts to re-use allocated memory?

That is exactly how I detected the leak. I figured out that the program started with 150Mb consumption ate more than 3Gb in approx 10 hours. I can perform more profiling if you wish, just give me a hint what to look at.

andydotxyz commented 5 months ago

Oh wow that is painful! Thanks for reporting, though it makes me think this is not the same issue as the one reported by OP. It looks like the RichText segment re-use is no longer clearing which was not the problem. It might be worth opening a new issue.

prokher commented 5 months ago

Oh wow that is painful! Thanks for reporting, though it makes me think this is not the same issue as the one reported by OP. It looks like the RichText segment re-use is no longer clearing which was not the problem. It might be worth opening a new issue.

Just created a new one with an example main.go which clearly reveals the issue: https://github.com/fyne-io/fyne/issues/4723.

andydotxyz commented 5 months ago

Thanks for that @prokher

andydotxyz commented 5 months ago

To the OP, can you please test against the v2.4.4 release if you have time? There are still more optimisations going in to develop as well, but I am trying to understand where the baseline has got to.