Skip to content

Client hangs (possibly due to large library) #99

Closed

Description

@gabrielelucci

Not sure what I am doing wrong here, but the app (built through Flatpak as per instructions) keeps hanging on startup indefinitely while consuming a very high amount of CPU.

My MPD server is deployed as a container, for which I built my own custom image that one can find here: https://gitlab.com/gabrielelucci/mpd-container. The server can be controlled by other clients such as Plattenalbum. My configuration is pretty standard, but maybe I'm missing something?

I tried launching the app from the terminal to check the logs, but nothing of interest seems shows up:

❯ flatpak run io.github.htkhiem.Euphonica

(process:2): GLib-WARNING **: 15:05:18.285: ../glib/goption.c:2303: ignoring no-arg, optional-arg or filename flags (34) on option of arg-type 0 in entry (null):minimized
Creating a new Euphonica instance...
Channel name: de3cde742fd047fcb0ed3cebda002fef

(euphonica:2): Adwaita-CRITICAL **: 15:05:18.402: Unable to find object 'append_queue_text' for setter
Loading placeholder texture...
Player controller: entering foreground mode
Connecting to TCP socket localhost:6600
[KeepAlive] There is no client currently running. Won't ping.
Local metadata DB version: 1
NoEntry
Connecting to TCP socket localhost:6600
Loading placeholder texture...

(euphonica:2): Gtk-WARNING **: 15:05:25.020: Trying to measure GtkLabel 0x56390b72fa50 for width of 33, but it needs at least 73
MPD does not have cover for folder St. Vincent/2017 - MASSEDUCTION (CD, Caroline International, LVR00223)/, will try fetching from external providers.
MPD does not have cover for folder Sepultura/2017 - Machine Messiah (CD, Nuclear Blast)/, will try fetching from external providers.
MPD does not have cover for folder Die Antwoord/2016 - Mount Ninji and da Nice Time Kid (Digital Media, Zef Recordz)/, will try fetching from external providers.
MPD does not have cover for folder Kerri Chandler/2006 - Nite Grooves Essentials (CD, Delfi Sound Inc., MDMA-001)/, will try fetching from external providers.

My library is managed by beets, and mpc stats returns the following:

Artists:   2295
Albums:    1733
Songs:    23021

Play Time:    0 days, 0:05:34
Uptime:       0 days, 0:05:32
DB Updated:   Sat Jul 26 23:05:58 2025
DB Play Time: 69 days, 20:26:59

If I turn off the MPD server, the app starts up correctly, but as soon as I start it up it hangs again.
Is there some additional info I can look for that might be useful in debugging the issue?

Activity

  1. htkhiem commented on Jul 29, 2025

    @htkhiem
    Owner

    Thanks for the detailed bug report. This sounds more like something looping infinitely to me. When it hangs in the terminal is that about all it'd print, or would it rapid-fire debug messages?

  2. gabrielelucci commented on Jul 29, 2025

    @gabrielelucci
    Author

    No debug messages. I tried waiting (even an hour or so), but it stays like this indefinitely.

    Screencast.From.2025-07-29.15-26-47.compressed.mp4
  3. htkhiem commented on Jul 29, 2025

    @htkhiem
    Owner

    If it's convenient for you, can you try copying just a few songs to a folder separate from your main library, point MPD to it, update its DB, then launch Euphonica again? We should debug whether this hanging is caused by library size or something else.

  4. gabrielelucci commented on Jul 29, 2025

    @gabrielelucci
    Author

    Seems to be it, relaunched with a limited library and doesn't hang. This could point towards library size but could even be some specific file that's possibly corrupted or weird. MPD doesn't seem to complain about anything though. One thing I tried doing is disabling the background download of images, since I imagine it's a very heavy operation and not even required since I use beets for that, but the result is the same.

    Screencast.From.2025-07-29.15-54-46.compressed.-1.mp4
  5. htkhiem commented on Jul 29, 2025

    @htkhiem
    Owner

    The background downloading is off the main thread (as are most of the metadata-related operations). So far the only thing that can hang the main thread is the SQLite metadata DB (the main thread has to make calls to it to fetch album art paths), so I'll investigate there. I'll try to mock a larger library to debug on my side.

  6. gabrielelucci commented on Jul 29, 2025

    @gabrielelucci
    Author

    Alright, let me know if you need additional info! The app seems really cool; I've been looking for a pretty MPD client for years!

  7. htkhiem commented on Jul 29, 2025

    @htkhiem
    Owner

    By the way, did you really disable all album art downloads? The settings for these are a bit scattered:

    • In the Connections tab, there's one for MPD itself
    • In the Integrations tab, there's one for each supported provider. To be sure just scroll down and disable all providers outright.

    I've just set up a 30,000-song, 2000-album, 1000-artist mock library (full of 1-second sine wave MP3s, with album, artist & albumartist tags, without any embedded art or cover file, organised in an artist/album/song files folder hierarchy just like Beets). Each "artist" has two "albums", each of which in turn contains 15 "songs". The app does lag quite badly on startup (first start takes around 5-10s to calm down, subsequent starts only 1s). I'm beginning to suspect it's the album art downloading & resulting SQLite after all, hence the question above.

    Update: I've just thrown in a cover file for each of the album folders & re-enabled MPD albumart download. It still doesn't hang for more than a few seconds (same as before, and album arts keep getting downloaded in a piecemeal manner). Looks like it isn't the SQLite code either.

  8. gabrielelucci commented on Jul 29, 2025

    @gabrielelucci
    Author

    This is what I tried:

    1. stop MPD server
    2. delete the app's Flatpak data
    3. start the app without connecting to MPD
    4. go to preferences, disable all downloads, both in MPD preferences and in the integrations tab.
    5. start MPD server, refresh connect the app
    6. app is fine for a minute or two, eventually the "dialog of death" appears
    7. restart the app, hangs in the same way as before

    Additional info about my library:

    • it's mostly made of flac files
    • beet stats returns the following:
    Tracks: 23021
    Total time: 10.0 weeks
    Approximate total size: 728.0 GiB
    Artists: 2297
    Albums: 1759
    Album artists: 594
    

    I'm gonna check for corrupted files next.

  9. htkhiem commented on Jul 29, 2025

    @htkhiem
    Owner

    There is one bug that I haven't been able to fix since the early days: despite what the GTK GridView claims to do, it has always generated one widget for each list item (album for example) instead of recycling them when I tried to count the number of active AlbumCell instances. For instance, if you have 1,759 albums, it will generate 1,759 AlbumCell widgets instead of a few tens of them. Now that I've almost ruled out the cache code (which runs on its own thread anyway) I think it's the only bottleneck left.

  10. gabrielelucci commented on Jul 29, 2025

    @gabrielelucci
    Author

    It could be. Memory consumption looks a bit suspicious; while the app is hung, it keeps increasing continuously reaching 2-3 GB after a few minutes. I also see quite high CPU usage on 8 out of my 16 cores. It really looks like some kind of loop and/or memory leak.

  11. htkhiem commented on Jul 30, 2025

    @htkhiem
    Owner

    After a bit of digging in GTK4's source code, turns out the number of listitems (delegates, that is) in GtkGridView is (GTK_GRID_VIEW_MAX_VISIBLE_ROWS + 2) * max-columns.

    The above formula is implemented in GtkListBase.set_anchor_max_widgets, an undocumented (?) function. GtkGridView calls it here.

    The idea was probably to allow initialisation of enough widgets to fill the visible portion plus one row waiting in each "stage wing" in the absolute worst case scenario. This is really subpar in that it's always multiplied by max-columns instead of the number of columns currently on screen. As per an earlier "fix" to let the Album View scale to wider displays, we hardcoded max-columns to 9999, effectively allowing up to 319,936 AlbumCells to be instantiated. Of course this would tank performance...

    I've just tried setting it back to 10 with the above synthetic library and the thing correctly limited itself to creating just ~300 AlbumCells rebinding as I scroll through the view. This also eliminated the heavy lag on startup. But 10 might not be enough for wider screens, so I'll make this a user-configurable setting, with ample warning.

    Not sure if that'll fix your hanging, but it's something we need to fix anyway.

    EDIT: in the future we can probably dynamically calculate the number of visible columns (since our AlbumCells have fixed widths) and set it to max-columns to overcome all of this.

  12. sonicv6 commented on Jul 30, 2025

    @sonicv6
    Contributor

    Haha that's my bad, did not expect that behaviour. No idea why they'd design it that way honestly.

  13. htkhiem commented on Jul 30, 2025

    @htkhiem
    Owner

    Haha that's my bad, did not expect that behaviour. No idea why they'd design it that way honestly.

    I guess it's probably to avoid complexities with dynamically adjusting the number of widgets to keep in memory. The fact that this was undocumented didn't help either. Maybe I'll open an issue on their GitLab when I have some time.

    However, it seems the hanging is caused by the Stretto cache being thrashed instead. The code currently does not send the cover arts directly from disk to the widgets. They have to at least be in the cache first. When I tried shrinking the Stretto size limit down to a tiny one, I could finally replicate the hanging and the obscene CPU usage too.

    The reason behind my usage of Stretto was to avoid duplicates in that multiple widgets showing the same image can reuse the same texture in VRAM. The problem is a huge album grid will require loading from disk as we scroll continuously through it, as there is no texture reuse possible. If we were to preload everything into an in-memory cache, that would defeat the purpose of LRU. Also, in the end there aren't that many duplicated textures. In the worst case of all songs in the queue having the same album art, we'd only be loading a few hundred 128px thumbnails in.

    I think I'll just drop the whole idea of having the Stretto cache, refactor the current off-thread image loading code to send the read image directly to widgets, and cut down on code complexity there. Once no longer referred to by any widget the GdkTextures will be dropped from memory. There will also be one less dependency crate to compile. This will obviously result in higher disk & VRAM usage, but hopefully not by enough to annoy anyone. In my testing loading ~300 thumbnails from an old HDD upon startup was near-instantaneous anyway.

  14. gabrielelucci commented on Jul 30, 2025

    @gabrielelucci
    Author

    So, I tried building the flatpak from the branch you posted, and it doesn't hang as bad as before, so it seems you're on the correct path! It still hangs if I scroll really fast down the albums section. I still have downloads disabled.

  15. htkhiem commented on Aug 1, 2025

    @htkhiem
    Owner

    @gabrielelucci I've just added a Stretto cache bypass path which should fix the hangup (a10d3d4). Can you try building that branch again?

    It fixes the hangup at least with my synthetic library.

    Perhaps I'll just replace Stretto with a simpler LRU cache without any fancy admission/eviction policies. This app lets you scroll through a bazillion album arts quickly so it's reasonable to treat new insertions as most valuable. Currently Stretto rejects all new insertions as not valuable enough once it is full.

  16. 6 remaining items

  17. htkhiem commented on Aug 2, 2025

    @htkhiem
    Owner

    Still haven't managed to repro the initial hang yet :(. If it is convenient to you, can you run a profiler & see what's holding things up on startup? The simplest way is to run sysprof but that logs the entire system, so take care to only include Euphonica's own stack trace and flame graph.

    On another note, it did hang badly when the cached images are deleted (causing it to update the SQLite image path table in panic and locking things up) so I added a few commits there, but still not perfect. The workaround is to provide a safe cache delete function that deletes both the SQLite side and the files on disk at the same time (+ add warnings to discourage the user from manually deleting the folder). Not sure if you've ever done this though.

  18. Soliness613 commented on Aug 2, 2025

    @Soliness613

    Having the same issue in arch 6.15.8.

    Inteeestingly, everything was working until i ran beets and got some more album art etc. now that i have done that, it hangs! what a bummer. I see it hang after about 10 seconds, stuck using ~600m of memory and maxing 3 of my cpu cores.

    I love the project, so im anxious for a fix! thanks for the work youve done so far!

  19. htkhiem commented on Aug 2, 2025

    @htkhiem
    Owner

    Just fixed a bunch of regressions introduced by the recent embedded art support (forgot to reimplement skip logic for album arts we have failed to download before).

    But a bigger change is that the internal Sqlite DB is now using WAL journaling mode, which means writes shouldn't block reads anymore. Reads were performed by the main thread, which without WAL could get blocked by the background thread rapid-firing updates.

    All in all please try commit 1675d38 and see if the performance is any better (it did for me). Thanks for your time!

  20. Soliness613 commented on Aug 2, 2025

    @Soliness613

    @htkhiem wow, thanks for the speedy response! will the AUR-hosted version be the same as 1675d38, or do i need to try directly from github?
    For the record, im testing on about ~10K files worth of my library. i don't imagine the problem has anythign to do with the actual audio of the files, just managing the metadata? Either way, getting your hands on a library as large might help reproduce the hangs we are seeing.
    Update: just tried again with the meson build, and had roughly the same outcome :(

  21. htkhiem commented on Aug 2, 2025

    @htkhiem
    Owner

    That commit isn't in the main branch yet. You have to checkout refactor/max-columns and build there. The commit I mentioned is the latest commit of that branch. You can probably modify the PKGBUILD to build it.

    As described above, this branch's been tested on a 30K-file, 2,000-album, 1000-artist synthetic library to good results. The original performance bottleneck doesn't depend on file count but on distinct album and artist count instead.

  22. Soliness613 commented on Aug 2, 2025

    @Soliness613

    that makes sense

  23. htkhiem commented on Aug 2, 2025

    @htkhiem
    Owner

    In case it still hangs with that commit, would you mind describing how it ran up until the hang? For example did it start to show several albums, stutters, then hangs, or did it hang straight from the moment the window appeared? What did it print in the console?

  24. Soliness613 commented on Aug 2, 2025

    @Soliness613

    It worked great off of that commit! 🤞

    loaded everything and running smooth. I will try gradually increasing my library size and report back if/when it chokes! thanks so much!

    Also going to try it out on some other devices and will report back.

  25. htkhiem commented on Aug 3, 2025

    @htkhiem
    Owner

    Please do test & report back!

    Due to the urgency of this bug I might merge this later today & release as v0.96.2. Doing so will close this issue, which I think is justified since its main focus is the complete freezing & high CPU usage instead of milder slowdowns. Please feel free to open new issues for them, or reopen this one if freezing occurs again.

  26. Soliness613 commented on Aug 3, 2025

    @Soliness613

    testing commit 1675d38 on a laptop with these specs:
    CPU: Intel(R) Core(TM) i5-5200U (4) @ 2.70 GHz
    Memory: 7.67 GiB

    and a 24,925-track library, which is mounted via sshfs. It is chugging a bit but honestly impressive all things considered. Got one full-freeze, but then it came back to life.

  27. gabrielelucci commented on Aug 3, 2025

    @gabrielelucci
    Author

    I just tested the latest commit from the refactor/max-columns, it seems it works flawlessly now! The app is instantly responsive. I even tried deleting the Flatpak data and starting fresh, no chokes at all! Nice job!

  28. htkhiem commented on Aug 3, 2025

    @htkhiem
    Owner

    Thanks a tonne for your support, looks like we can release this into main now.

    It is chugging a bit but honestly impressive all things considered. Got one full-freeze, but then it came back to life.

    @Soliness613 An i5-5200U isn't a powerhouse but is still somewhat capable, so I won't put the blame on it just yet. It might be the GPU though, as GTK 4.16+ runs on Vulkan by default and I still think it's slower than OpenGL. You might want to launch Euphonica with the NGL renderer to see if that improves things:

    GSK_RENDERER=ngl euphonica

    Case in point: the visualiser still runs faster on the old GL renderer. In Vulkan the app fails to hit my monitor's refresh rate when maximised, and sysprof shows the main load to be the NVIDIA driver, suggesting some overhead there. Things were also like this when the blur effect was implemented via GSK's inbuilt blur effect instead of the current static texture approach.

    As long as the freeze doesn't last forever it shouldn't be the scope of this specific issue though. I'll still try to track down performance issues as I go.

    EDIT: changing instructions to use the NGL renderer instead, since the old GL renderer was removed from GTK 4.18+.

  29. htkhiem commented on Aug 3, 2025

    @htkhiem
    Owner

    Small update: the queue fetch code still runs on the main thread. It's one of the oldest pieces of code in this thing and obviously is run on startup. There's even my own TODO comment about moving it to a background thread...

    So yea, that might be one of if not THE reason behind @Soliness613's freezes on startup. I'm opening a new issue for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions