Project

General

Profile

Actions

Bug #2186

open

GTK4 Client consumme 100% CPU (at least on debian with GTK 4.18)

Added by Caeies Caeies about 6 hours ago. Updated about 5 hours ago.

Status:
New
Priority:
Normal
Assignee:
-
Category:
gtk4-client
Target version:
Start date:
08/30/2026
Due date:
% Done:

0%

Estimated time:

Description

I found that among other issues, the GTK4 client was eating 100% of the CPU.

Digging around with GDB pinpoint to a cascade of events. I solve it by blocking/unblocking them in plrdlg.c (from code version 3.2.5) :

 866 void real_players_dialog_update(void *unused)
 867 {
 868   GtkTreeModel *model;
 869   GtkTreeIter iter;
 870   int selected;
 871 
 872   if (NULL == players_dialog_shell) {
 873     return;
 874   }
 875 
 876   /* Save the selection. */
 877   if (gtk_tree_selection_get_selected(players_selection, &model, &iter)) {
 878     gtk_tree_model_get(model, &iter, PLR_DLG_COL_ID, &selected, -1);
 879   } else {
 880     selected = -1;
 881   }
 882 
 883   g_signal_handlers_block_by_func(players_selection, G_CALLBACK(selection_callback), NULL);
 884   gtk_list_store_clear(players_dialog_store);
 885   players_iterate(pplayer) {
 886     if (!player_should_be_shown(pplayer)) {
 887       continue;
 888     }
 889     gtk_list_store_append(players_dialog_store, &iter);
 890     fill_row(players_dialog_store, &iter, pplayer);
 891     if (player_number(pplayer) == selected) {
 892       /* Restore the selection. */
 893       gtk_tree_selection_select_iter(players_selection, &iter);
 894     }
 895   } players_iterate_end;
 896 
 897   update_views();
 898   g_signal_handlers_unblock_by_func(players_selection, G_CALLBACK(selection_callback), NULL);                                                                                                                  
 899 }

running the new version so CPU back to normal ...
As I am not an expert in GUI, I let you decide if this is the right fix or not :).

Best regards.

Actions #1

Updated by Caeies Caeies about 5 hours ago

Looks Like I was a little bit optimistic ... While this fix drastically lower the number of spawn threads, it doesn't solve all the issues ...

I had to do more fixes:

replace the add_idle_callback function which looks like infinite loop for GTK4 code by animation_tick_cb function like (remove in pages.c and edit gui_main.c):

 227 static gboolean animation_tick_cb(GtkWidget *widget, GdkFrameClock *frame_clock, gpointer user_data);
...
1519   gtk_widget_add_tick_callback(map_canvas, animation_tick_cb, NULL, NULL);
...
2447 static gboolean animation_tick_cb(GtkWidget *widget,
2448                                   GdkFrameClock *frame_clock,
2449                                   gpointer user_data)
2450 {
2451     if (get_current_client_page() == PAGE_GAME) {
2452             update_animation();
2453     }
2454       return G_SOURCE_CONTINUE;
2455 }

and for the add_idle_callback(main_message_area_resize, NULL); one (in pages.c):

3605     //add_idle_callback(main_message_area_resize, NULL);                                                                                                                                                       
3606     main_message_area_resize(NULL);


and in gui_main.c:
 362 void main_message_area_resize(void *data)                                                                                                                                                                      
 363 {
 364   if (get_current_client_page() == PAGE_GAME) {
 365     static int old_width = 0, old_height = 0;
 366     int width = gtk_widget_get_width(GTK_WIDGET(main_message_area));
 367     int height = gtk_widget_get_height(GTK_WIDGET(main_message_area));
 368 
 369     if (width != old_width
 370         || height != old_height) {
 371       chatline_scroll_to_bottom(TRUE);
 372       old_width = width;
 373       old_height = height; 
 374     }
 375 
 376     // add_idle_callback(main_message_area_resize, NULL);
 377   }
 378 }
...
2076   /* Assumes client_state is set */
2077   timer_id = g_timeout_add(TIMER_INTERVAL, timer_callback, NULL);
2078     
2079   g_signal_connect_swapped(main_message_area, "notify::default-width",                                                                                                                                         
2080                                    G_CALLBACK(main_message_area_resize), NULL);
2081   g_signal_connect_swapped(main_message_area, "notify::default-height",
2082                                    G_CALLBACK(main_message_area_resize), NULL);
2083 }   
...

With these changes, the GUI is much more reactive and consume only a very low CPU. NOTE: I guess that the same kind of adaptation should be done for the network ping case, but that's for later :).

Hope this is clear.

Actions #2

Updated by Caeies Caeies about 5 hours ago

Oups, forget to add this amend my initial correction by (in plrdlg.c):

 866 void real_players_dialog_update(void *unused)
 867 {
 868   GtkTreeModel *model;
 869   GtkTreeIter iter;
 870   int selected;
 871 
 872   if (NULL == players_dialog_shell) {
 873     return;
 874   }
 875 
 876   /* Save the selection. */
 877   if (gtk_tree_selection_get_selected(players_selection, &model, &iter)) {
 878     gtk_tree_model_get(model, &iter, PLR_DLG_COL_ID, &selected, -1);
 879   } else {
 880     selected = -1;
 881   }
 882 
 883   g_object_freeze_notify(G_OBJECT(players_dialog_store));
 884   g_signal_handlers_block_by_func(players_selection, G_CALLBACK(selection_callback), NULL);
 885   gtk_list_store_clear(players_dialog_store);
 886   players_iterate(pplayer) {
 887     if (!player_should_be_shown(pplayer)) {
 888       continue;
 889     }
 890     gtk_list_store_append(players_dialog_store, &iter);
 891     fill_row(players_dialog_store, &iter, pplayer);
 892     if (player_number(pplayer) == selected) {
 893       /* Restore the selection. */
 894       gtk_tree_selection_select_iter(players_selection, &iter);
 895     }
 896   } players_iterate_end;
 897 
 898   update_views();
 899   g_signal_handlers_unblock_by_func(players_selection, G_CALLBACK(selection_callback), NULL);
 900   g_object_thaw_notify(G_OBJECT(players_dialog_store));                                                                                                                                                        
 901 }

Would be better to generate a patch I guess. Let me know.

Actions

Also available in: Atom PDF