From 30111e5cf6ff5a7766296ac2579a98c16e7cc7c1 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 2 Jun 2018 11:07:27 +0200
Subject: Computed the initial lines width using all threads.

---
 src/analysis/binary.c       |  10 ++
 src/glibext/gbuffercache.c  |  10 +-
 src/glibext/gbuffercache.h  |   2 +-
 src/glibext/gbufferview.c   |  26 ++--
 src/glibext/gwidthtracker.c | 361 +++++++++++++++++++++++++++++++++++++++++++-
 src/glibext/gwidthtracker.h |   7 +
 6 files changed, 395 insertions(+), 21 deletions(-)

diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 15ec403..54ad89b 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -1625,6 +1625,7 @@ static bool g_loaded_binary_analyze(GLoadedBinary *binary, wgroup_id_t gid, GtkS
     const char *arch;                       /* Architecture d'exécution    */
     const char *desc;                       /* Description humaine associée*/
     GProcContext *context;                  /* Contexte de suivi dédié     */
+    GWidthTracker *tracker;                 /* Gestionnaire de largeur     */
 
     /* Interprétation du format associé */
 
@@ -1663,8 +1664,17 @@ static bool g_loaded_binary_analyze(GLoadedBinary *binary, wgroup_id_t gid, GtkS
     g_binary_format_complete_analysis(format, gid, status);
 
     if (!is_batch_mode())
+    {
         output_disassembly(binary, context, status, &binary->disass_cache);
 
+        tracker = g_buffer_cache_get_width_tracker(binary->disass_cache);
+
+        g_width_tracker_build_initial_cache(tracker, gid, status);
+
+        g_object_unref(G_OBJECT(tracker));
+
+    }
+
     result = true;
 
  glba_exit:
diff --git a/src/glibext/gbuffercache.c b/src/glibext/gbuffercache.c
index a627238..66ecf27 100644
--- a/src/glibext/gbuffercache.c
+++ b/src/glibext/gbuffercache.c
@@ -784,9 +784,15 @@ size_t g_buffer_cache_count_lines(const GBufferCache *cache)
 *                                                                             *
 ******************************************************************************/
 
-const GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *cache)
+GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *cache)
 {
-    return cache->tracker;
+    GWidthTracker *result;                  /* Instance à retourner    *   */
+
+    result = cache->tracker;
+
+    g_object_ref(G_OBJECT(result));
+
+    return result;
 
 }
 
diff --git a/src/glibext/gbuffercache.h b/src/glibext/gbuffercache.h
index c00e0f2..dbd3237 100644
--- a/src/glibext/gbuffercache.h
+++ b/src/glibext/gbuffercache.h
@@ -72,7 +72,7 @@ gint g_buffer_cache_get_text_position(const GBufferCache *);
 size_t g_buffer_cache_count_lines(const GBufferCache *);
 
 /* Fournit un lien vers la structure de suivi de largeurs. */
-const GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *);
+GWidthTracker *g_buffer_cache_get_width_tracker(const GBufferCache *);
 
 /* Insère un générateur dans des lignes à une position donnée. */
 void g_buffer_cache_insert_at(GBufferCache *, size_t, GLineGenerator *, bool, bool);
diff --git a/src/glibext/gbufferview.c b/src/glibext/gbufferview.c
index c212672..af7d7ac 100644
--- a/src/glibext/gbufferview.c
+++ b/src/glibext/gbufferview.c
@@ -45,12 +45,7 @@ struct _GBufferView
     size_t first;                           /* Indice de la première ligne */
     size_t last;                            /* Indice de la dernière ligne */
 
-    union
-    {
-        const GWidthTracker *ext_tracker;   /* Suivi externe des largeurs  */
-        GWidthTracker *int_tracker;         /* Suivi interne des largeurs  */
-        GWidthTracker *tracker;             /* Suivi pour usage interne    */
-    };
+    GWidthTracker *tracker;                 /* Suivi des largeurs          */
 
 };
 
@@ -173,8 +168,7 @@ static void g_buffer_view_dispose(GBufferView *view)
 {
     g_object_unref(G_OBJECT(view->cache));
 
-    if (!view->unrestricted)
-        g_object_unref(G_OBJECT(view->int_tracker));
+    g_object_unref(G_OBJECT(view->tracker));
 
     G_OBJECT_CLASS(g_buffer_view_parent_class)->dispose(G_OBJECT(view));
 
@@ -400,7 +394,7 @@ GBufferCache *g_buffer_view_get_cache(const GBufferView *view)
 void g_buffer_view_restrict(GBufferView *view, const vmpa2t *start, const vmpa2t *end)
 {
     bool state;                             /* Nouvel état à proclamer     */
-    const GWidthTracker *template;          /* Suivi déjà en place         */
+    GWidthTracker *template;                /* Suivi déjà en place         */
 
     state = (start == NULL || end == NULL);
 
@@ -410,16 +404,16 @@ void g_buffer_view_restrict(GBufferView *view, const vmpa2t *start, const vmpa2t
 
         template = g_buffer_cache_get_width_tracker(view->cache);
 
+        /* Vérification pour le cas particulier du démarrage */
+        if (view->tracker != NULL)
+            g_object_unref(G_OBJECT(view->tracker));
+
         if (view->unrestricted)
         {
-            /* Vérification pour le cas particulier du démarrage */
-            if (view->int_tracker != NULL)
-                g_object_unref(G_OBJECT(view->int_tracker));
-
             view->first = 0;
             view->last = g_buffer_cache_count_lines(view->cache) - 1;
 
-            view->ext_tracker = template;
+            view->tracker = template;
 
         }
 
@@ -431,7 +425,9 @@ void g_buffer_view_restrict(GBufferView *view, const vmpa2t *start, const vmpa2t
             view->first = g_buffer_cache_find_index_by_addr(view->cache, start, true);
             view->last = g_buffer_cache_find_index_by_addr(view->cache, end, false);
 
-            view->ext_tracker = g_width_tracker_new_restricted(template, view->first, view->last);
+            view->tracker = g_width_tracker_new_restricted(template, view->first, view->last);
+
+            g_object_unref(G_OBJECT(template));
 
         }
 
diff --git a/src/glibext/gwidthtracker.c b/src/glibext/gwidthtracker.c
index 82ae65b..181759c 100644
--- a/src/glibext/gwidthtracker.c
+++ b/src/glibext/gwidthtracker.c
@@ -30,8 +30,77 @@
 #include <string.h>
 
 
+#include <i18n.h>
+
+
+#include "delayed-int.h"
 #include "gbuffercache.h"
+#include "../core/global.h"
+
+
+
+/* --------------------------- PRISE DE MESURES INITIALES --------------------------- */
+
+
+/* Procédure de mise à jour des mesures de largeurs (instance) */
+typedef struct _GWidthUpdate
+{
+    GDelayedWork parent;                    /* A laisser en premier        */
+
+    activity_id_t id;                       /* Groupe de progression       */
+
+    GWidthTracker *tracker;                 /* Gestionnaire à manipuler    */
+
+    size_t start;                           /* Premier indice à traiter    */
+    size_t end;                             /* Premier indice à écarter    */
+
+    line_width_summary summary;             /* Largeurs requises suivies   */
+
+} GWidthUpdate;
+
+/* Procédure de mise à jour des mesures de largeurs (classe) */
+typedef struct _GWidthUpdateClass
+{
+    GDelayedWorkClass parent;               /* A laisser en premier        */
+
+} GWidthUpdateClass;
+
+
+#define G_TYPE_WIDTH_UPDATE            g_width_update_get_type()
+#define G_WIDTH_UPDATE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_WIDTH_UPDATE, GWidthUpdate))
+#define G_IS_WIDTH_UPDATE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_WIDTH_UPDATE))
+#define G_WIDTH_UPDATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WIDTH_UPDATE, GWidthUpdateClass))
+#define G_IS_WIDTH_UPDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WIDTH_UPDATE))
+#define G_WIDTH_UPDATE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WIDTH_UPDATE, GWidthUpdateClass))
+
+
+/* Initialise la classe des tâches de mesures de largeurs. */
+static void g_width_update_class_init(GWidthUpdateClass *);
+
+/* Initialise une tâche de mesures de largeurs. */
+static void g_width_update_init(GWidthUpdate *);
+
+/* Supprime toutes les références externes. */
+static void g_width_update_dispose(GWidthUpdate *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_width_update_finalize(GWidthUpdate *);
+
+/* Indique le type défini pour les tâches de mesures de largeurs. */
+GType g_width_update_get_type(void);
+
+/* Crée une tâche de mesures de largeurs. */
+static GWidthUpdate *g_width_update_new(activity_id_t, GWidthTracker *, size_t, size_t);
 
+/* Assure les mesures initiales d'un ensemble de lignes. */
+static void g_width_update_process(GWidthUpdate *, GtkStatusStack *);
+
+/* Récupère les données obtenues lors d'une mesure globale. */
+static void g_width_update_collect(GWidthUpdate *, line_width_summary *);
+
+
+
+/* ---------------------------- RASSEMBLEMENT DE MESURES ---------------------------- */
 
 
 /* Portions de largeurs communes */
@@ -98,6 +167,209 @@ static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *);
 
 
 
+/* ---------------------------------------------------------------------------------- */
+/*                             PRISE DE MESURES INITIALES                             */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour les tâches de mesures de largeurs. */
+G_DEFINE_TYPE(GWidthUpdate, g_width_update, G_TYPE_DELAYED_WORK);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des tâches de mesures de largeurs.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_update_class_init(GWidthUpdateClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GDelayedWorkClass *work;                /* Version en classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_width_update_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_width_update_finalize;
+
+    work = G_DELAYED_WORK_CLASS(klass);
+
+    work->run = (run_task_fc)g_width_update_process;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : update = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une tâche de mesures de largeurs.                 *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_update_init(GWidthUpdate *update)
+{
+    memset(&update->summary, 0, sizeof(line_width_summary));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : update = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_update_dispose(GWidthUpdate *update)
+{
+    g_object_unref(G_OBJECT(update->tracker));
+
+    G_OBJECT_CLASS(g_width_update_parent_class)->dispose(G_OBJECT(update));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : update = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_update_finalize(GWidthUpdate *update)
+{
+    G_OBJECT_CLASS(g_width_update_parent_class)->finalize(G_OBJECT(update));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : id      = identifiant pour signaler la progression courante. *
+*                tracker = gestionnaire de largeurs à consulter.              *
+*                start   = indice de la première ligne à traiter.             *
+*                end     = indice de la première ligne à éviter.              *
+*                                                                             *
+*  Description : Crée une tâche de mesures de largeurs.                       *
+*                                                                             *
+*  Retour      : Tâche créée.                                                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static GWidthUpdate *g_width_update_new(activity_id_t id, GWidthTracker *tracker, size_t start, size_t end)
+{
+    GWidthUpdate *result;                   /* Tâche à retourner           */
+
+    result = g_object_new(G_TYPE_WIDTH_UPDATE, NULL);
+
+    result->id = id;
+
+    g_object_ref(G_OBJECT(tracker));
+    result->tracker = tracker;
+
+    result->start = start;
+    result->end = end;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : update = opération de mesures à mener.                       *
+*                status = barre de statut à tenir informée.                   *
+*                                                                             *
+*  Description : Assure les mesures initiales d'un ensemble de lignes.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_update_process(GWidthUpdate *update, GtkStatusStack *status)
+{
+    line_width_summary *local;              /* Valeurs collectées          */
+    size_t i;                               /* Boucle de parcours #1       */
+    const line_width_summary *summary;      /* Valeurs à intégrer          */
+    BufferLineColumn k;                     /* Boucle de parcours #2       */
+
+    local = &update->summary;
+
+    for (i = update->start; i < update->end; i++)
+    {
+        summary = g_width_tracker_get_up_to_date_widths(update->tracker, i);
+
+        for (k = 0; k < BLC_COUNT; k++)
+            local->max_widths[k] = MAX(local->max_widths[k], summary->max_widths[k]);
+
+        local->merged_width = MAX(local->merged_width, summary->merged_width);
+
+        gtk_status_stack_update_activity_value(status, update->id, 1);
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : update = opération de mesures menée à bien.                  *
+*                global = lieu de centralisation des données globales.        *
+*                                                                             *
+*  Description : Récupère les données obtenues lors d'une mesure globale.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_width_update_collect(GWidthUpdate *update, line_width_summary *global)
+{
+    line_width_summary *local;              /* Valeurs collectées          */
+    BufferLineColumn i;                     /* Boucle de parcours          */
+
+    local = &update->summary;
+
+    for (i = 0; i < BLC_COUNT; i++)
+        global->max_widths[i] = MAX(global->max_widths[i], local->max_widths[i]);
+
+    global->merged_width = MAX(global->merged_width, local->merged_width);
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                              RASSEMBLEMENT DE MESURES                              */
+/* ---------------------------------------------------------------------------------- */
+
+
 /* Détermine le type du gestionnaire de largeurs associées aux lignes. */
 G_DEFINE_TYPE(GWidthTracker, g_width_tracker, G_TYPE_OBJECT);
 
@@ -686,6 +958,89 @@ void g_width_tracker_update_deleted(GWidthTracker *tracker, size_t start, size_t
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : tracker = suivi de largeurs dont le cache est à construire.  *
+*                gid     = groupe de travail impliqué.                        *
+*                status  = barre de statut à tenir informée.                  *
+*                                                                             *
+*  Description : Calcule les largeurs requises par un ensemble de lignes.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_width_tracker_build_initial_cache(GWidthTracker *tracker, wgroup_id_t gid, GtkStatusStack *status)
+{
+    guint runs_count;                       /* Qté d'exécutions parallèles */
+    GWidthUpdate **updates;                 /* Mesures à suivre            */
+    size_t run_size;                        /* Volume réparti par exécution*/
+    GWorkQueue *queue;                      /* Gestionnaire de différés    */
+    activity_id_t id;                       /* Identifiant de progression  */
+    guint i;                                /* Boucle de parcours          */
+    size_t start;                           /* Début de zone de traitement */
+    bool closing;                           /* Détection de fin en amont   */
+    size_t end;                             /* Fin de zone de traitement   */
+
+    assert(!tracker->cached);
+
+    /* Lancement des traitements */
+
+    runs_count = g_get_num_processors();
+
+    updates = (GWidthUpdate **)calloc(runs_count, sizeof(GWidthUpdate *));
+
+    run_size = tracker->count / runs_count;
+
+    queue = get_work_queue();
+
+    id = gtk_status_stack_add_activity(status, _("Computing width of all lines for rendering"), tracker->count);
+
+    for (i = 0; i < runs_count; i++)
+    {
+        start = i * run_size;
+
+        closing = ((i + 1) == runs_count);
+
+        if (closing)
+            end = tracker->count;
+        else
+            end = start + run_size;
+
+        updates[i] = g_width_update_new(id, tracker, start, end);
+
+        g_object_ref(G_OBJECT(updates[i]));
+        g_work_queue_schedule_work(queue, G_DELAYED_WORK(updates[i]), gid);
+
+    }
+
+    g_work_queue_wait_for_completion(queue, gid);
+
+    /* Récupération des aires */
+
+    memset(&tracker->summary, 0, sizeof(line_width_summary));
+
+    for (i = 0; i < runs_count; i++)
+    {
+        g_width_update_collect(updates[i], &tracker->summary);
+
+        g_object_unref(G_OBJECT(updates[i]));
+
+    }
+
+    /* Fin */
+
+    free(updates);
+
+    gtk_status_stack_remove_activity(status, id);
+
+    tracker->cached = true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : tracker = suivi de largeurs à mettre à jour si besoin est.   *
 *                                                                             *
 *  Description : Calcule les largeurs requises par un ensemble de lignes.     *
@@ -705,14 +1060,14 @@ static void g_width_tracker_ensure_valid_required_widths(GWidthTracker *tracker)
 
     if (!tracker->cached)
     {
+        global = &tracker->summary;
+
         /* Réinitialisation */
 
-        memset(&tracker->summary, 0, sizeof(line_width_summary));
+        memset(global, 0, sizeof(line_width_summary));
 
         /* Collecte */
 
-        global = &tracker->summary;
-
         for (i = 0; i < tracker->count; i++)
         {
             summary = g_width_tracker_get_up_to_date_widths(tracker, i);
diff --git a/src/glibext/gwidthtracker.h b/src/glibext/gwidthtracker.h
index 0832467..2d9aef6 100644
--- a/src/glibext/gwidthtracker.h
+++ b/src/glibext/gwidthtracker.h
@@ -29,10 +29,14 @@
 #include <stdbool.h>
 
 
+#include "delayed.h"
 #include "gbufferline.h"
 
 
 
+/* ---------------------------- RASSEMBLEMENT DE MESURES ---------------------------- */
+
+
 /* gbuffercache.h : Tampon pour gestion de lignes optimisée (instance) */
 typedef struct _GBufferCache GBufferCache;
 
@@ -70,6 +74,9 @@ void g_width_tracker_update_added(GWidthTracker *, size_t, size_t);
 /* Prend acte de la suppression de lignes pour les largeurs. */
 void g_width_tracker_update_deleted(GWidthTracker *, size_t, size_t);
 
+/* Calcule les largeurs requises par un ensemble de lignes. */
+void g_width_tracker_build_initial_cache(GWidthTracker *, wgroup_id_t, GtkStatusStack *);
+
 /* Fournit un bon résumé des largeurs en vigueur. */
 const line_width_summary *g_width_tracker_get_width_summary(GWidthTracker *);
 
-- 
cgit v0.11.2-87-g4458