[gimp] app: add memory group to the dashboard



commit 8d0766c1fce68c85587ed9644838b8e3e5fc2b6b
Author: Ell <ell_se yahoo com>
Date:   Tue Jun 19 12:34:42 2018 -0400

    app: add memory group to the dashboard
    
    The memory group shows memory-usage information: the currently used
    memory size, the available physical memory size, and the total
    physical memory size.  It can also show the tile-cache size, for
    comparison against the other memory stats.  The memory group is
    active but contracted by default.
    
    Note that the upper-bound of the meter is the physical memory size,
    so the memory usage may be > 100% when GIMP uses the swap.
    
    This is currently implemented for *nix systems with Linux-like
    procfs, and Windows.

 app/widgets/gimpdashboard.c | 397 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 354 insertions(+), 43 deletions(-)
---
diff --git a/app/widgets/gimpdashboard.c b/app/widgets/gimpdashboard.c
index 376686e28b..2e2942fe04 100644
--- a/app/widgets/gimpdashboard.c
+++ b/app/widgets/gimpdashboard.c
@@ -26,13 +26,23 @@
 #include <gio/gio.h>
 #include <gtk/gtk.h>
 
+#ifdef G_OS_WIN32
+#include <windows.h>
+#define HAVE_CPU_GROUP
+#define HAVE_MEMORY_GROUP
+#else /* ! G_OS_WIN32 */
 #ifdef HAVE_SYS_TIMES_H
 #include <sys/times.h>
 #define HAVE_CPU_GROUP
-#elif defined (G_OS_WIN32)
-#include <windows.h>
-#define HAVE_CPU_GROUP
-#endif
+#endif /* HAVE_SYS_TIMES_H */
+#if defined (HAVE_UNISTD_H) && defined (HAVE_FCNTL_H)
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef _SC_PAGE_SIZE
+#define HAVE_MEMORY_GROUP
+#endif /* _SC_PAGE_SIZE */
+#endif /* HAVE_UNISTD_H && HAVE_FCNTL_H */
+#endif /* ! G_OS_WIN32 */
 
 #include "libgimpbase/gimpbase.h"
 #include "libgimpmath/gimpmath.h"
@@ -41,6 +51,7 @@
 #include "widgets-types.h"
 
 #include "core/gimp.h"
+#include "core/gimp-utils.h"
 
 #include "gimpactiongroup.h"
 #include "gimpdocked.h"
@@ -94,6 +105,13 @@ typedef enum
   VARIABLE_CPU_ACTIVE_TIME,
 #endif
 
+#ifdef HAVE_MEMORY_GROUP
+  /* memory */
+  VARIABLE_MEMORY_USED,
+  VARIABLE_MEMORY_AVAILABLE,
+  VARIABLE_MEMORY_SIZE,
+#endif
+
   /* misc */
   VARIABLE_MIPMAPED,
 
@@ -121,6 +139,9 @@ typedef enum
   GROUP_SWAP,
 #ifdef HAVE_CPU_GROUP
   GROUP_CPU,
+#endif
+#ifdef HAVE_MEMORY_GROUP
+  GROUP_MEMORY,
 #endif
   GROUP_MISC,
 
@@ -153,11 +174,13 @@ struct _VariableInfo
 
 struct _FieldInfo
 {
-  Variable variable;
-  gboolean default_active;
-  gboolean show_in_header;
-  Variable meter_variable;
-  gint     meter_value;
+  Variable     variable;
+  const gchar *title;
+  gboolean     default_active;
+  gboolean     show_in_header;
+  Variable     meter_variable;
+  gint         meter_value;
+  gboolean     meter_cumulative;
 };
 
 struct _GroupInfo
@@ -293,6 +316,15 @@ static void       gimp_dashboard_reset_cpu_active_time       (GimpDashboard
                                                               Variable             variable);
 #endif /* HAVE_CPU_GROUP */
 
+#ifdef HAVE_MEMORY_GROUP
+static void       gimp_dashboard_sample_memory_used          (GimpDashboard       *dashboard,
+                                                              Variable             variable);
+static void       gimp_dashboard_sample_memory_available     (GimpDashboard       *dashboard,
+                                                              Variable             variable);
+static void       gimp_dashboard_sample_memory_size          (GimpDashboard       *dashboard,
+                                                              Variable             variable);
+#endif /* HAVE_MEMORY_GROUP */
+
 static void       gimp_dashboard_sample_object               (GimpDashboard       *dashboard,
                                                               GObject             *object,
                                                               Variable             variable);
@@ -459,6 +491,37 @@ static const VariableInfo variables[] =
 #endif /* HAVE_CPU_GROUP */
 
 
+#ifdef HAVE_MEMORY_GROUP
+  /* memory variables */
+
+  [VARIABLE_MEMORY_USED] =
+  { .name             = "memory-used",
+    .title            = NC_("dashboard-variable", "Used"),
+    .description      = N_("Amount of memory used by the process"),
+    .type             = VARIABLE_TYPE_SIZE,
+    .color            = {0.8, 0.5, 0.2, 1.0},
+    .sample_func      = gimp_dashboard_sample_memory_used
+  },
+
+  [VARIABLE_MEMORY_AVAILABLE] =
+  { .name             = "memory-available",
+    .title            = NC_("dashboard-variable", "Available"),
+    .description      = N_("Amount of available physical memory"),
+    .type             = VARIABLE_TYPE_SIZE,
+    .color            = {0.8, 0.5, 0.2, 0.4},
+    .sample_func      = gimp_dashboard_sample_memory_available
+  },
+
+  [VARIABLE_MEMORY_SIZE] =
+  { .name             = "memory-size",
+    .title            = NC_("dashboard-variable", "Size"),
+    .description      = N_("Physical memory size"),
+    .type             = VARIABLE_TYPE_SIZE,
+    .sample_func      = gimp_dashboard_sample_memory_size
+  },
+#endif /* HAVE_MEMORY_GROUP */
+
+
   /* misc variables */
 
   [VARIABLE_MIPMAPED] =
@@ -484,26 +547,26 @@ static const GroupInfo groups[] =
     .meter_limit      = VARIABLE_CACHE_LIMIT,
     .fields           = (const FieldInfo[])
                         {
-                          { .variable       = VARIABLE_CACHE_OCCUPIED,
-                            .default_active = TRUE,
-                            .show_in_header = TRUE,
-                            .meter_value    = 2
+                          { .variable         = VARIABLE_CACHE_OCCUPIED,
+                            .default_active   = TRUE,
+                            .show_in_header   = TRUE,
+                            .meter_value      = 2
                           },
-                          { .variable       = VARIABLE_CACHE_MAXIMUM,
-                            .default_active = FALSE,
-                            .meter_value    = 1
+                          { .variable         = VARIABLE_CACHE_MAXIMUM,
+                            .default_active   = FALSE,
+                            .meter_value      = 1
                           },
-                          { .variable       = VARIABLE_CACHE_LIMIT,
-                            .default_active = TRUE
+                          { .variable         = VARIABLE_CACHE_LIMIT,
+                            .default_active   = TRUE
                           },
 
                           { VARIABLE_SEPARATOR },
 
-                          { .variable       = VARIABLE_CACHE_COMPRESSION,
-                            .default_active = FALSE
+                          { .variable         = VARIABLE_CACHE_COMPRESSION,
+                            .default_active   = FALSE
                           },
-                          { .variable       = VARIABLE_CACHE_HIT_MISS,
-                            .default_active = FALSE
+                          { .variable         = VARIABLE_CACHE_HIT_MISS,
+                            .default_active   = FALSE
                           },
 
                           {}
@@ -522,17 +585,17 @@ static const GroupInfo groups[] =
     .meter_led        = VARIABLE_SWAP_BUSY,
     .fields           = (const FieldInfo[])
                         {
-                          { .variable       = VARIABLE_SWAP_OCCUPIED,
-                            .default_active = TRUE,
-                            .show_in_header = TRUE,
-                            .meter_value    = 2
+                          { .variable         = VARIABLE_SWAP_OCCUPIED,
+                            .default_active   = TRUE,
+                            .show_in_header   = TRUE,
+                            .meter_value      = 2
                           },
-                          { .variable       = VARIABLE_SWAP_SIZE,
-                            .default_active = TRUE,
-                            .meter_value    = 1
+                          { .variable         = VARIABLE_SWAP_SIZE,
+                            .default_active   = TRUE,
+                            .meter_value      = 1
                           },
-                          { .variable       = VARIABLE_SWAP_LIMIT,
-                            .default_active = TRUE
+                          { .variable         = VARIABLE_SWAP_LIMIT,
+                            .default_active   = TRUE
                           },
 
                           {}
@@ -551,18 +614,18 @@ static const GroupInfo groups[] =
     .meter_led        = VARIABLE_CPU_ACTIVE,
     .fields           = (const FieldInfo[])
                         {
-                          { .variable       = VARIABLE_CPU_USAGE,
-                            .default_active = TRUE,
-                            .show_in_header = TRUE,
-                            .meter_value    = 2
+                          { .variable         = VARIABLE_CPU_USAGE,
+                            .default_active   = TRUE,
+                            .show_in_header   = TRUE,
+                            .meter_value      = 2
                           },
 
                           { VARIABLE_SEPARATOR },
 
-                          { .variable       = VARIABLE_CPU_ACTIVE_TIME,
-                            .default_active = FALSE,
-                            .meter_variable = VARIABLE_CPU_ACTIVE,
-                            .meter_value    = 1
+                          { .variable         = VARIABLE_CPU_ACTIVE_TIME,
+                            .default_active   = FALSE,
+                            .meter_variable   = VARIABLE_CPU_ACTIVE,
+                            .meter_value      = 1
                           },
 
                           {}
@@ -570,6 +633,46 @@ static const GroupInfo groups[] =
   },
 #endif /* HAVE_CPU_GROUP */
 
+#ifdef HAVE_MEMORY_GROUP
+  /* memory group */
+  [GROUP_MEMORY] =
+  { .name             = "memory",
+    .title            = NC_("dashboard-group", "Memory"),
+    .description      = N_("Memory usage"),
+    .default_active   = TRUE,
+    .default_expanded = FALSE,
+    .has_meter        = TRUE,
+    .meter_limit      = VARIABLE_MEMORY_SIZE,
+    .fields           = (const FieldInfo[])
+                        {
+                          { .variable         = VARIABLE_CACHE_OCCUPIED,
+                            .title            = NC_("dashboard-variable", "Cache"),
+                            .default_active   = FALSE,
+                            .meter_value      = 3
+                          },
+
+                          { VARIABLE_SEPARATOR },
+
+                          { .variable         = VARIABLE_MEMORY_USED,
+                            .default_active   = TRUE,
+                            .show_in_header   = TRUE,
+                            .meter_value      = 2,
+                            .meter_cumulative = TRUE
+                          },
+                          { .variable         = VARIABLE_MEMORY_AVAILABLE,
+                            .default_active   = TRUE,
+                            .meter_value      = 1,
+                            .meter_cumulative = TRUE
+                          },
+                          { .variable         = VARIABLE_MEMORY_SIZE,
+                            .default_active   = TRUE
+                          },
+
+                          {}
+                        }
+  },
+#endif /* HAVE_MEMORY_GROUP */
+
   /* misc group */
   [GROUP_MISC] =
   { .name             = "misc",
@@ -764,7 +867,9 @@ gimp_dashboard_init (GimpDashboard *dashboard)
               const VariableInfo *variable_info = &variables[field_info->variable];
 
               item = gtk_check_menu_item_new_with_label (
-                g_dpgettext2 (NULL, "dashboard-variable", variable_info->title));
+                g_dpgettext2 (NULL, "dashboard-variable",
+                              field_info->title ? field_info->title :
+                                                  variable_info->title));
               field_data->menu_item = GTK_CHECK_MENU_ITEM (item);
               gimp_help_set_help_data (item,
                                        g_dgettext (NULL, variable_info->description),
@@ -1344,6 +1449,7 @@ gimp_dashboard_sample (GimpDashboard *dashboard)
               const GroupInfo *group_info = &groups[group];
               GroupData       *group_data = &priv->groups[group];
               gdouble         *sample;
+              gdouble          total      = 0.0;
 
               if (! group_info->has_meter)
                 continue;
@@ -1356,13 +1462,23 @@ gimp_dashboard_sample (GimpDashboard *dashboard)
 
                   if (field_info->meter_value)
                     {
+                      gdouble value;
+
                       if (field_info->meter_variable)
                         variable = field_info->meter_variable;
                       else
                         variable = field_info->variable;
 
-                      sample[field_info->meter_value - 1] =
-                        gimp_dashboard_variable_to_double (dashboard, variable);
+                      value = gimp_dashboard_variable_to_double (dashboard,
+                                                                 variable);
+
+                      if (field_info->meter_cumulative)
+                        {
+                          total += value;
+                          value  = total;
+                        }
+
+                      sample[field_info->meter_value - 1] = value;
                     }
                 }
 
@@ -1790,6 +1906,199 @@ gimp_dashboard_reset_cpu_active_time (GimpDashboard *dashboard,
 
 #endif /* HAVE_CPU_GROUP */
 
+#ifdef HAVE_MEMORY_GROUP
+
+#ifndef G_OS_WIN32
+
+static void
+gimp_dashboard_sample_memory_used (GimpDashboard *dashboard,
+                                   Variable       variable)
+{
+  GimpDashboardPrivate *priv          = dashboard->priv;
+  VariableData         *variable_data = &priv->variables[variable];
+  static gboolean       initialized   = FALSE;
+  static long           page_size;
+  static gint           fd;
+  gchar                 buffer[128];
+  gint                  size;
+  unsigned long long    resident;
+  unsigned long long    shared;
+
+  if (! initialized)
+    {
+      page_size = sysconf (_SC_PAGE_SIZE);
+
+      if (page_size > 0)
+        fd = open ("/proc/self/statm", O_RDONLY);
+
+      initialized = TRUE;
+    }
+
+  variable_data->available = FALSE;
+
+  if (fd < 0)
+    return;
+
+  if (lseek (fd, 0, SEEK_SET))
+    return;
+
+  size = read (fd, buffer, sizeof (buffer) - 1);
+
+  if (size <= 0)
+    return;
+
+  buffer[size] = '\0';
+
+  if (sscanf (buffer, "%*u %llu %llu", &resident, &shared) != 2)
+    return;
+
+  variable_data->available  = TRUE;
+  variable_data->value.size = (guint64) (resident - shared) * page_size;
+}
+
+static void
+gimp_dashboard_sample_memory_available (GimpDashboard *dashboard,
+                                        Variable       variable)
+{
+  GimpDashboardPrivate *priv            = dashboard->priv;
+  VariableData         *variable_data   = &priv->variables[variable];
+  static gboolean       initialized     = FALSE;
+  static gint64         last_check_time = 0;
+  static gint           fd;
+  static guint64        available;
+  static gboolean       has_available   = FALSE;
+  gint64                time;
+
+  if (! initialized)
+    {
+      fd = open ("/proc/meminfo", O_RDONLY);
+
+      initialized = TRUE;
+    }
+
+  variable_data->available = FALSE;
+
+  if (fd < 0)
+    return;
+
+  /* we don't have a config option for limiting the swap size, so we simply
+   * return the free space available on the filesystem containing the swap
+   */
+
+  time = g_get_monotonic_time ();
+
+  if (time - last_check_time >= G_TIME_SPAN_SECOND)
+    {
+      gchar  buffer[512];
+      gint   size;
+      gchar *str;
+
+      last_check_time = time;
+
+      has_available = FALSE;
+
+      if (lseek (fd, 0, SEEK_SET))
+        return;
+
+      size = read (fd, buffer, sizeof (buffer) - 1);
+
+      if (size <= 0)
+        return;
+
+      buffer[size] = '\0';
+
+      str = strstr (buffer, "MemAvailable:");
+
+      if (! str)
+        return;
+
+      available = strtoull (str + 13, &str, 0);
+
+      if (! str)
+        return;
+
+      for (; *str; str++)
+        {
+          if (*str == 'k')
+            {
+              available <<= 10;
+              break;
+            }
+          else if (*str == 'M')
+            {
+              available <<= 20;
+              break;
+            }
+        }
+
+      if (! *str)
+        return;
+
+      has_available = TRUE;
+    }
+
+  if (! has_available)
+    return;
+
+  variable_data->available  = TRUE;
+  variable_data->value.size = available;
+}
+
+#else /* G_OS_WIN32 */
+
+
+static void
+gimp_dashboard_sample_memory_used (GimpDashboard *dashboard,
+                                   Variable       variable)
+{
+  GimpDashboardPrivate        *priv          = dashboard->priv;
+  VariableData                *variable_data = &priv->variables[variable];
+  PPROCESS_MEMORY_COUNTERS_EX  pmc;
+
+  variable_data->available = FALSE;
+
+  if (! GetProcessMemoryInfo (GetCurrentProcess (), &pmc, sizeof (pmc)))
+    return;
+
+  variable_data->available  = TRUE;
+  variable_data->value.size = pmc.PrivateUsage;
+}
+
+static void
+gimp_dashboard_sample_memory_available (GimpDashboard *dashboard,
+                                        Variable       variable)
+{
+  GimpDashboardPrivate *priv          = dashboard->priv;
+  VariableData         *variable_data = &priv->variables[variable];
+  MEMORYSTATUSEX        ms;
+
+  variable_data->available = FALSE;
+
+  ms.dwLength = sizeof (ms);
+
+  if (! GlobalMemoryStatusEx (&ms))
+    return;
+
+  variable_data->available  = TRUE;
+  variable_data->value.size = ms.ullAvailPhys;
+}
+
+
+#endif /* G_OS_WIN32 */
+
+static void
+gimp_dashboard_sample_memory_size (GimpDashboard *dashboard,
+                                   Variable       variable)
+{
+  GimpDashboardPrivate *priv          = dashboard->priv;
+  VariableData         *variable_data = &priv->variables[variable];
+
+  variable_data->value.size = gimp_get_physical_memory_size ();
+  variable_data->available  = variable_data->value.size > 0;
+}
+
+#endif /* HAVE_MEMORY_GROUP */
+
 static void
 gimp_dashboard_sample_object (GimpDashboard *dashboard,
                               GObject       *object,
@@ -2007,7 +2316,9 @@ gimp_dashboard_update_group (GimpDashboard *dashboard,
 
           str = g_strdup_printf ("%s:",
                                  g_dpgettext2 (NULL, "dashboard-variable",
-                                               variable_info->title));
+                                               field_info->title ?
+                                                 field_info->title :
+                                                 variable_info->title));
 
           label = gtk_label_new (str);
           gimp_help_set_help_data (label, description,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]