Thunar performs IO in UI functions
I faced performance issues while using Thunar with my phone
connected by MTP. The Thunar UI froze often and was not very responsive with
scrolling, selecting files and other mere file actions.
I tried to find the cause of issues and it turns out some
UI functions make calls that drill down to IO, and freeze while waiting for IO
to finish.
This is the list of IO calls I found. The tree structure represents the call stack.
* From list model:
thunar_list_model_get_value
`-thunar_file_get_content_type
`-g_file_query_info -- [1]
* From icon renderer:
thunar_icon_renderer_render
`-thunar_icon_factory_load_file_icon
+-thunar_icon_factory_get_show_thumbnail
| `-thunar_file_get_preview_type
| `-g_file_query_filesystem_info -- [2]
+-g_loadable_icon_load -- [3]
`-thunar_file_get_icon_name
`-thunar_file_get_content_type
`-g_file_query_info -- [4]
* From misc UI:
thunar_standard_view_get_property
`-thunar_list_model_get_statusbar_text
`-thunar_g_file_get_free_space
`-g_file_query_filesystem_info -- [5]
<!--split-->
thunar_standard_view_request_thumbnails_real (via g_idle_add)
`-thunar_thumbnailer_begin_job
`-thunar_thumbnailer_file_is_supported
`-thunar_file_get_content_type
<!--split-->
thunar_folder_content_type_loader_idle (via g_idle_add)
`-thunar_file_load_content_type
`-thunar_file_get_content_type
<!--split-->
thunar_path_entry_set_current_file
`-gtk_entry_set_text
...signal "changed"
`-thunar_path_entry_changed
`-thunar_folder_get_for_file
`-thunar_file_watch
`-g_file_monitor
`-g_file_query_file_type
I believe there are other IO calls too, but I haven't found them yet.
(Should I split the issue per case?)
I'd like to solve the issue, but before doing so I wanted to discuss the
solution. I see two approaches to it:
1. Ad-hoc solution
* Prefetch `GFileInfo` with content-type beforehand. This solves [1] and
[4], but slows down folder opening.
* Prefetch file system info in `ThunarFolder` to prevent [2].
* How to deal with [3]? I have no good clues for now.
2. Async model solution
* Create a layer that connects GtkTreeView to async values.
This could be a special column renderer, a custom data function for a list column,
a custom GValue transformation function.
When the value is pending the `get_value` call returns a placeholder (blank or "...");
when the value is ready returns it.
* Use asynchronous `thunar_file_async_get_content_type` in the list model.
This solves [1].
* Move the code from `thunar_icon_renderer_render` to a new
`thunar_file_async_get_icon` that returns the icon asynchronously. This
solves [2] [3] and [4].
This solution increases code complexity because it introduces a new layer
and a notion of async values that can be pending or ready.
For the status bar ([5]) it seems just enough to listen to the
`notify::statusbar-text` signal.
Could any of these
solutions be accepted to the Thunar code? Maybe someone could think up
something better? Because I'm not absolutely happy with the approaches above.
issue