changeset 2281:1bb9002801e5

Limit the number of roster computations/redraws per second This reduces CPU time and greatly improve performance with very large rosters (e.g. >1000 items).
author Mikael Berthe <mikael@lilotux.net>
date Sun, 25 Sep 2016 15:07:24 +0200
parents f1eebfdd6db7
children dc1b123d63d5
files mcabber/mcabber/hooks.c mcabber/mcabber/main.c mcabber/mcabber/roster.c mcabber/mcabber/screen.c
diffstat 4 files changed, 58 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/mcabber/hooks.c	Sat Sep 24 12:31:13 2016 +0200
+++ b/mcabber/mcabber/hooks.c	Sun Sep 25 15:07:24 2016 +0200
@@ -44,6 +44,8 @@
   guint     hid;
 } hook_list_data_t;
 
+extern int build_buddylist;
+
 static GHashTable *hk_handler_hash = NULL;
 
 //  _new_hook_id()
@@ -567,8 +569,7 @@
 
   roster_setstatus(bjid, rn, prio, status, status_msg, timestamp,
                    role_none, affil_none, NULL);
-  buddylist_build();
-  update_roster = TRUE;
+  build_buddylist = TRUE;
   hlog_write_status(bjid, timestamp, status, status_msg);
 
 #ifdef MODULES_ENABLE
--- a/mcabber/mcabber/main.c	Sat Sep 24 12:31:13 2016 +0200
+++ b/mcabber/mcabber/main.c	Sun Sep 25 15:07:24 2016 +0200
@@ -28,6 +28,7 @@
 #include <glib.h>
 #include <config.h>
 #include <poll.h>
+#include <time.h>
 #include <errno.h>
 
 #include "caps.h"
@@ -66,8 +67,11 @@
 static bool sigwinch;
 #endif
 
+extern int build_buddylist;
+
 static bool terminate_ui;
 GMainContext *main_context;
+static guint refresh_timeout_id;
 
 static struct termios *backup_termios;
 
@@ -377,6 +381,13 @@
   return keyboard_activity();
 }
 
+static gboolean refresh_timeout_cb(gpointer data) {
+   // Only called once, to trigger a refresh if needed
+   // so reset ID and return false.
+  refresh_timeout_id = 0;
+  return FALSE;
+}
+
 static GSourceFuncs mcabber_source_funcs = {
   mcabber_source_prepare,
   mcabber_source_check,
@@ -483,6 +494,10 @@
     }
   }
 
+  /* Initialize buddylist update timestamp */
+  struct timespec last_ui_update;
+  clock_gettime(CLOCK_MONOTONIC, &last_ui_update);
+
   /* Initialize PGP system
      We do it before ncurses initialization because we may need to request
      a passphrase. */
@@ -555,6 +570,9 @@
     scr_LogPrint(LPRINT_DEBUG, "Entering into main loop...");
 
     while(!terminate_ui) {
+      int64_t timediff;
+      struct timespec now;
+
       if (g_main_context_iteration(main_context, TRUE) == FALSE)
         keyboard_activity();
 #ifdef USE_SIGWINCH
@@ -563,9 +581,36 @@
         sigwinch = FALSE;
       }
 #endif
-      if (update_roster)
-        scr_draw_roster();
-      scr_do_update();
+
+      // Compute time in ms since last buddylist/screen update
+      clock_gettime(CLOCK_MONOTONIC, &now);
+      timediff = (((now.tv_sec - last_ui_update.tv_sec)  * 1.0e9) +
+                  (now.tv_nsec - last_ui_update.tv_nsec)) / 1.0e6;
+
+      if (timediff <= 200) {
+        // Trigger a timeout in 1s to make sure no refresh will be missed
+        if (!refresh_timeout_id) {
+          refresh_timeout_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT,
+                                     1, refresh_timeout_cb, NULL, NULL);
+        }
+      } else if ((build_buddylist || update_roster)) {
+        // More than 200ms
+        if (build_buddylist || update_roster) {
+          if (build_buddylist) {
+            buddylist_build();
+            update_roster = TRUE;
+          }
+          if (update_roster) {
+            scr_draw_roster();
+            scr_do_update();
+            last_ui_update = now;
+          }
+        } else {
+          // No roster change; minimum screen update
+          update_panels();
+          doupdate();
+        }
+      }
     }
 
     g_source_destroy(mc_source);
--- a/mcabber/mcabber/roster.c	Sat Sep 24 12:31:13 2016 +0200
+++ b/mcabber/mcabber/roster.c	Sun Sep 25 15:07:24 2016 +0200
@@ -23,6 +23,8 @@
 #include "utils.h"
 #include "hooks.h"
 
+int build_buddylist;
+
 extern void hlog_save_state(void);
 
 char *strrole[] = {   /* Should match enum in roster.h */
@@ -1032,6 +1034,8 @@
   // current_buddy initialization
   if (!current_buddy || (g_list_position(buddylist, current_buddy) == -1))
     current_buddy = g_list_first(buddylist);
+
+  build_buddylist = FALSE;
 }
 
 //  buddy_hide_group(roster, hide)
--- a/mcabber/mcabber/screen.c	Sat Sep 24 12:31:13 2016 +0200
+++ b/mcabber/mcabber/screen.c	Sun Sep 25 15:07:24 2016 +0200
@@ -68,6 +68,8 @@
 
 #define DEFAULT_ATTENTION_CHAR '!'
 
+extern int build_buddylist;
+
 const char *LocaleCharSet = "C";
 
 static unsigned short int Log_Win_Height;
@@ -2538,7 +2540,7 @@
   }
   // We should rebuild the buddylist but not everytime
   if (!(buddylist_get_filter() & 1<<prev_st))
-    buddylist_build();
+    build_buddylist = TRUE;
   update_roster = TRUE;
 }