Repository navigation
Description
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
htkhiem commentedon Jul 29, 2025
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?
gabrielelucci commentedon Jul 29, 2025
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
htkhiem commentedon Jul 29, 2025
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.
gabrielelucci commentedon Jul 29, 2025
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
htkhiem commentedon Jul 29, 2025
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.
gabrielelucci commentedon Jul 29, 2025
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!
htkhiem commentedon Jul 29, 2025
By the way, did you really disable all album art downloads? The settings for these are a bit scattered:
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.
gabrielelucci commentedon Jul 29, 2025
This is what I tried:
Additional info about my library:
beet statsreturns the following:I'm gonna check for corrupted files next.
htkhiem commentedon Jul 29, 2025
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.
gabrielelucci commentedon Jul 29, 2025
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.
htkhiem commentedon Jul 30, 2025
After a bit of digging in GTK4's source code, turns out the number of listitems (delegates, that is) in
GtkGridViewis (GTK_GRID_VIEW_MAX_VISIBLE_ROWS+ 2) *max-columns.The above formula is implemented in GtkListBase.set_anchor_max_widgets, an undocumented (?) function.
GtkGridViewcalls 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-columnsinstead of the number of columns currently on screen. As per an earlier "fix" to let the Album View scale to wider displays, we hardcodedmax-columnsto 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-columnsto overcome all of this.sonicv6 commentedon Jul 30, 2025
Haha that's my bad, did not expect that behaviour. No idea why they'd design it that way honestly.
htkhiem commentedon Jul 30, 2025
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
GdkTextureswill 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.gabrielelucci commentedon Jul 30, 2025
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.
htkhiem commentedon Aug 1, 2025
@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.
6 remaining items
htkhiem commentedon Aug 2, 2025
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.
Soliness613 commentedon Aug 2, 2025
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!
htkhiem commentedon Aug 2, 2025
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!
Soliness613 commentedon Aug 2, 2025
@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 :(
htkhiem commentedon Aug 2, 2025
That commit isn't in the main branch yet. You have to checkout
refactor/max-columnsand 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.
Soliness613 commentedon Aug 2, 2025
that makes sense
htkhiem commentedon Aug 2, 2025
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?
Soliness613 commentedon Aug 2, 2025
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.
htkhiem commentedon Aug 3, 2025
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.
Soliness613 commentedon Aug 3, 2025
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.
gabrielelucci commentedon Aug 3, 2025
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!htkhiem commentedon Aug 3, 2025
Thanks a tonne for your support, looks like we can release this into main now.
@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:
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+.
htkhiem commentedon Aug 3, 2025
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.