Skip to content

Thunar (indirectly) does blocking D-Bus calls for every file in thunar_folder_finished

Tested with thunar 4.16.11 (Xfce 4.16) packaged by Arch Linux.

I was switching between list and icon view with ctrl-1/ctrl-3 in a folder with ~150 files, and it took a noticeable amount of time (0.5sec). So I profiled thunar with perf and found that a lot of time was spent alternating between the main thread and dbus thread. The hot path on the main thread is:

thunar_folder_finished
thunar_file_reload
g_local_file_query_info
_g_local_file_info_get
g_daemon_vfs_local_file_add_info
meta_lookup_cache_lookup_path
get_tree_for_device
gvfs_metadata_call_get_tree_from_device_sync
g_dbus_proxy_call_sync

Everything between _g_local_file_info_get and get_tree_for_device supports passing a pointer to a cache for the most recent device queried, but the entrypoint g_local_file_query_info creates a fresh cache (GLocalParentFileInfo) every time. With dbus-monitor I confirmed that the query and reply are the same every time:

[... many more ...]
method return time=1666655820.862265 sender=:1.62 -> destination=:1.427 serial=50086 reply_serial=1865
   string "uuid-86cd9bc4-d9fc-457d-a15c-798915671c62"
method call time=1666655820.862695 sender=:1.427 -> destination=:1.62 serial=1866 path=/org/gtk/vfs/metadata; interface=org.gtk.vfs.Metadata; member=GetTreeFromDevice
   uint32 254
   uint32 2
method return time=1666655820.863090 sender=:1.62 -> destination=:1.427 serial=50087 reply_serial=1866
   string "uuid-86cd9bc4-d9fc-457d-a15c-798915671c62"
method call time=1666655820.863522 sender=:1.427 -> destination=:1.62 serial=1867 path=/org/gtk/vfs/metadata; interface=org.gtk.vfs.Metadata; member=GetTreeFromDevice
   uint32 254
   uint32 2
[... many more ...]

I also attached with gdb and used these breakpoints

(gdb) dprintf _g_local_file_info_get, "_g_local_file_info_get parent_info=%p parent_info->extra_data=%p\n", parent_info, parent_info->extra_data
(gdb) dprintf g_dbus_proxy_call_sync, "g_dbus_proxy_call_sync\n"
(gdb) dprintf thunar_folder_finished, "thunar_folder_finished\n"
(gdb) dprintf thunar_file_reload, "thunar_file_reload\n"

which gives a trace like

[... many cached requests not coming from thunar_folder_finished ...]
_g_local_file_info_get parent_info=0x7fffe800b5b8 parent_info->extra_data=0x7fffe806db20
_g_local_file_info_get parent_info=0x7fffe800b5b8 parent_info->extra_data=0x7fffe806db20
_g_local_file_info_get parent_info=0x7fffe800b5b8 parent_info->extra_data=0x7fffe806db20
_g_local_file_info_get parent_info=0x7fffe800b5b8 parent_info->extra_data=0x7fffe806db20
thunar_folder_finished
thunar_file_reload
_g_local_file_info_get parent_info=0x7fffffffde40 parent_info->extra_data=(nil)
g_dbus_proxy_call_sync
thunar_file_reload
_g_local_file_info_get parent_info=0x7fffffffde40 parent_info->extra_data=(nil)
g_dbus_proxy_call_sync
thunar_file_reload
_g_local_file_info_get parent_info=0x7fffffffde40 parent_info->extra_data=(nil)
g_dbus_proxy_call_sync
thunar_file_reload
_g_local_file_info_get parent_info=0x7fffffffde40 parent_info->extra_data=(nil)
g_dbus_proxy_call_sync
[... many uncached requests ...]

Though the issue is in gio/gvfs, it might be possible to side-step this in thunar (by calling g_local_file_query_info less?). I don't know the APIs well enough to say.