gimp/app/widgets/gimpdashboard.c

4661 lines
149 KiB
C
Raw Normal View History

/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995-1999 Spencer Kimball and Peter Mattis
*
* gimpdashboard.c
* Copyright (C) 2017 Ell
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
#include <stdarg.h>
#include <gegl.h>
#include <gio/gio.h>
#include <gtk/gtk.h>
#ifdef G_OS_WIN32
#include <windows.h>
#include <psapi.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
#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"
#include "libgimpwidgets/gimpwidgets.h"
#include "widgets-types.h"
#include "core/gimp.h"
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
#include "core/gimp-gui.h"
#include "core/gimp-utils.h"
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
#include "core/gimp-parallel.h"
#include "core/gimpasync.h"
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
#include "core/gimpbacktrace.h"
#include "core/gimpwaitable.h"
#include "gimpactiongroup.h"
#include "gimpdocked.h"
#include "gimpdashboard.h"
#include "gimpdialogfactory.h"
#include "gimphelp-ids.h"
#include "gimpmeter.h"
#include "gimpsessioninfo-aux.h"
#include "gimpuimanager.h"
#include "gimpwidgets-utils.h"
#include "gimpwindowstrategy.h"
#include "gimp-intl.h"
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
#include "gimp-version.h"
#define DEFAULT_UPDATE_INTERVAL GIMP_DASHBOARD_UPDATE_INTERVAL_0_25_SEC
#define DEFAULT_HISTORY_DURATION GIMP_DASHBOARD_HISTORY_DURATION_60_SEC
#define DEFAULT_LOW_SWAP_SPACE_WARNING TRUE
#define LOW_SWAP_SPACE_WARNING_ON /* swap occupied is above */ 0.90 /* of swap limit */
#define LOW_SWAP_SPACE_WARNING_OFF /* swap occupied is below */ 0.85 /* of swap limit */
#define CPU_ACTIVE_ON /* individual cpu usage is above */ 0.75
#define CPU_ACTIVE_OFF /* individual cpu usage is below */ 0.25
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
#define LOG_VERSION 1
#define LOG_SAMPLE_FREQUENCY 10 /* samples per second */
typedef enum
{
VARIABLE_NONE,
FIRST_VARIABLE,
/* cache */
VARIABLE_CACHE_OCCUPIED = FIRST_VARIABLE,
VARIABLE_CACHE_MAXIMUM,
VARIABLE_CACHE_LIMIT,
VARIABLE_CACHE_COMPRESSION,
VARIABLE_CACHE_HIT_MISS,
/* swap */
VARIABLE_SWAP_OCCUPIED,
VARIABLE_SWAP_SIZE,
VARIABLE_SWAP_LIMIT,
VARIABLE_SWAP_QUEUED,
VARIABLE_SWAP_QUEUE_STALLS,
VARIABLE_SWAP_QUEUE_FULL,
VARIABLE_SWAP_READ,
VARIABLE_SWAP_READ_THROUGHPUT,
VARIABLE_SWAP_WRITTEN,
VARIABLE_SWAP_WRITE_THROUGHPUT,
VARIABLE_SWAP_COMPRESSION,
#ifdef HAVE_CPU_GROUP
/* cpu */
VARIABLE_CPU_USAGE,
VARIABLE_CPU_ACTIVE,
VARIABLE_CPU_ACTIVE_TIME,
#endif
#ifdef HAVE_MEMORY_GROUP
/* memory */
VARIABLE_MEMORY_USED,
VARIABLE_MEMORY_AVAILABLE,
VARIABLE_MEMORY_SIZE,
#endif
/* misc */
VARIABLE_MIPMAPED,
VARIABLE_ASYNC_RUNNING,
N_VARIABLES,
VARIABLE_SEPARATOR
} Variable;
typedef enum
{
VARIABLE_TYPE_BOOLEAN,
VARIABLE_TYPE_INTEGER,
VARIABLE_TYPE_SIZE,
VARIABLE_TYPE_SIZE_RATIO,
VARIABLE_TYPE_INT_RATIO,
VARIABLE_TYPE_PERCENTAGE,
VARIABLE_TYPE_DURATION,
VARIABLE_TYPE_RATE_OF_CHANGE
} VariableType;
typedef enum
{
FIRST_GROUP,
GROUP_CACHE = FIRST_GROUP,
GROUP_SWAP,
#ifdef HAVE_CPU_GROUP
GROUP_CPU,
#endif
#ifdef HAVE_MEMORY_GROUP
GROUP_MEMORY,
#endif
GROUP_MISC,
N_GROUPS
} Group;
typedef struct _VariableInfo VariableInfo;
typedef struct _FieldInfo FieldInfo;
typedef struct _GroupInfo GroupInfo;
typedef struct _VariableData VariableData;
typedef struct _FieldData FieldData;
typedef struct _GroupData GroupData;
typedef void (* VariableFunc) (GimpDashboard *dashboard,
Variable variable);
struct _VariableInfo
{
const gchar *name;
const gchar *title;
const gchar *description;
VariableType type;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gboolean exclude_from_log;
GimpRGB color;
VariableFunc sample_func;
VariableFunc reset_func;
gconstpointer data;
};
struct _FieldInfo
{
Variable variable;
const gchar *title;
gboolean default_active;
gboolean show_in_header;
Variable meter_variable;
gint meter_value;
gboolean meter_cumulative;
};
struct _GroupInfo
{
const gchar *name;
const gchar *title;
const gchar *description;
gboolean default_active;
gboolean default_expanded;
gboolean has_meter;
Variable meter_limit;
const Variable *meter_led;
const FieldInfo *fields;
};
struct _VariableData
{
gboolean available;
union
{
gboolean boolean;
gint integer;
guint64 size; /* in bytes */
struct
{
guint64 antecedent;
guint64 consequent;
} size_ratio;
struct
{
gint antecedent;
gint consequent;
} int_ratio;
gdouble percentage; /* from 0 to 1 */
gdouble duration; /* in seconds */
gdouble rate_of_change; /* in source units per second */
} value;
gpointer data;
gsize data_size;
};
struct _FieldData
{
2017-12-31 10:43:47 -05:00
gboolean active;
GtkCheckMenuItem *menu_item;
GtkLabel *value_label;
};
struct _GroupData
{
gint n_fields;
gint n_meter_values;
gboolean active;
gdouble limit;
GtkToggleAction *action;
GtkExpander *expander;
GtkLabel *header_values_label;
GtkButton *menu_button;
GtkMenu *menu;
GimpMeter *meter;
GtkGrid *grid;
FieldData *fields;
};
struct _GimpDashboardPrivate
{
Gimp *gimp;
VariableData variables[N_VARIABLES];
GroupData groups[N_GROUPS];
GThread *thread;
GMutex mutex;
GCond cond;
gboolean quit;
gboolean update_now;
gint update_idle_id;
gint low_swap_space_idle_id;
GimpDashboardUpdateInteval update_interval;
GimpDashboardHistoryDuration history_duration;
gboolean low_swap_space_warning;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
GOutputStream *log_output;
GError *log_error;
gint64 log_start_time;
gint log_sample_frequency;
gint log_n_samples;
gint log_n_markers;
VariableData log_variables[N_VARIABLES];
gboolean log_include_backtrace;
GimpBacktrace *log_backtrace;
GHashTable *log_addresses;
GtkWidget *log_record_button;
GtkLabel *log_add_marker_label;
};
/* local function prototypes */
static void gimp_dashboard_docked_iface_init (GimpDockedInterface *iface);
static void gimp_dashboard_constructed (GObject *object);
static void gimp_dashboard_dispose (GObject *object);
static void gimp_dashboard_finalize (GObject *object);
static void gimp_dashboard_map (GtkWidget *widget);
static void gimp_dashboard_unmap (GtkWidget *widget);
static void gimp_dashboard_set_aux_info (GimpDocked *docked,
GList *aux_info);
static GList * gimp_dashboard_get_aux_info (GimpDocked *docked);
static gboolean gimp_dashboard_group_expander_button_press (GimpDashboard *dashboard,
GdkEventButton *bevent,
GtkWidget *widget);
static void gimp_dashboard_group_action_toggled (GimpDashboard *dashboard,
GtkToggleAction *action);
static void gimp_dashboard_field_menu_item_toggled (GimpDashboard *dashboard,
GtkCheckMenuItem *item);
static gpointer gimp_dashboard_sample (GimpDashboard *dashboard);
static gboolean gimp_dashboard_update (GimpDashboard *dashboard);
static gboolean gimp_dashboard_low_swap_space (GimpDashboard *dashboard);
static void gimp_dashboard_sample_function (GimpDashboard *dashboard,
Variable variable);
static void gimp_dashboard_sample_gegl_config (GimpDashboard *dashboard,
Variable variable);
static void gimp_dashboard_sample_gegl_stats (GimpDashboard *dashboard,
Variable variable);
static void gimp_dashboard_sample_variable_changed (GimpDashboard *dashboard,
Variable variable);
static void gimp_dashboard_sample_variable_rate_of_change (GimpDashboard *dashboard,
Variable variable);
static void gimp_dashboard_sample_swap_limit (GimpDashboard *dashboard,
Variable variable);
#ifdef HAVE_CPU_GROUP
static void gimp_dashboard_sample_cpu_usage (GimpDashboard *dashboard,
Variable variable);
static void gimp_dashboard_sample_cpu_active (GimpDashboard *dashboard,
Variable variable);
static void gimp_dashboard_sample_cpu_active_time (GimpDashboard *dashboard,
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);
static void gimp_dashboard_update_groups (GimpDashboard *dashboard);
static void gimp_dashboard_update_group (GimpDashboard *dashboard,
Group group);
static void gimp_dashboard_update_group_values (GimpDashboard *dashboard,
Group group);
static void gimp_dashboard_group_set_active (GimpDashboard *dashboard,
Group group,
gboolean active);
static void gimp_dashboard_field_set_active (GimpDashboard *dashboard,
Group group,
gint field,
gboolean active);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
static void gimp_dashboard_reset_unlocked (GimpDashboard *dashboard);
static void gimp_dashboard_reset_variables (GimpDashboard *dashboard);
2018-06-21 04:03:19 -04:00
static gpointer gimp_dashboard_variable_get_data (GimpDashboard *dashboard,
Variable variable,
gsize size);
static gboolean gimp_dashboard_variable_to_boolean (GimpDashboard *dashboard,
Variable variable);
static gdouble gimp_dashboard_variable_to_double (GimpDashboard *dashboard,
Variable variable);
static gchar * gimp_dashboard_field_to_string (GimpDashboard *dashboard,
Group group,
gint field,
gboolean full);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
static gboolean gimp_dashboard_log_printf (GimpDashboard *dashboard,
const gchar *format,
...) G_GNUC_PRINTF (2, 3);
static gboolean gimp_dashboard_log_print_escaped (GimpDashboard *dashboard,
const gchar *string);
static gint64 gimp_dashboard_log_time (GimpDashboard *dashboard);
static void gimp_dashboard_log_sample (GimpDashboard *dashboard,
gboolean variables_changed);
static void gimp_dashboard_log_update_highlight (GimpDashboard *dashboard);
static void gimp_dashboard_log_update_n_markers (GimpDashboard *dashboard);
static void gimp_dashboard_log_write_address_map (GimpAsync *async,
GimpDashboard *dashboard);
static gboolean gimp_dashboard_field_use_meter_underlay (Group group,
gint field);
static gchar * gimp_dashboard_format_rate_of_change (const gchar *value);
static gchar * gimp_dashboard_format_value (VariableType type,
gdouble value);
static void gimp_dashboard_label_set_text (GtkLabel *label,
const gchar *text);
/* static variables */
static const VariableInfo variables[] =
{
/* cache variables */
[VARIABLE_CACHE_OCCUPIED] =
{ .name = "cache-occupied",
.title = NC_("dashboard-variable", "Occupied"),
.description = N_("Tile cache occupied size"),
.type = VARIABLE_TYPE_SIZE,
.color = {0.3, 0.6, 0.3, 1.0},
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "tile-cache-total"
},
[VARIABLE_CACHE_MAXIMUM] =
{ .name = "cache-maximum",
.title = NC_("dashboard-variable", "Maximum"),
.description = N_("Maximal tile cache occupied size"),
.type = VARIABLE_TYPE_SIZE,
.color = {0.3, 0.7, 0.8, 1.0},
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "tile-cache-total-max"
},
[VARIABLE_CACHE_LIMIT] =
{ .name = "cache-limit",
.title = NC_("dashboard-variable", "Limit"),
.description = N_("Tile cache size limit"),
.type = VARIABLE_TYPE_SIZE,
.sample_func = gimp_dashboard_sample_gegl_config,
.data = "tile-cache-size"
},
[VARIABLE_CACHE_COMPRESSION] =
{ .name = "cache-compression",
.title = NC_("dashboard-variable", "Compression"),
.description = N_("Tile cache compression ratio"),
.type = VARIABLE_TYPE_SIZE_RATIO,
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "tile-cache-total\0"
"tile-cache-total-uncloned"
},
[VARIABLE_CACHE_HIT_MISS] =
{ .name = "cache-hit-miss",
.title = NC_("dashboard-variable", "Hit/Miss"),
.description = N_("Tile cache hit/miss ratio"),
.type = VARIABLE_TYPE_INT_RATIO,
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "tile-cache-hits\0"
"tile-cache-misses"
},
/* swap variables */
[VARIABLE_SWAP_OCCUPIED] =
{ .name = "swap-occupied",
.title = NC_("dashboard-variable", "Occupied"),
.description = N_("Swap file occupied size"),
.type = VARIABLE_TYPE_SIZE,
.color = {0.8, 0.2, 0.2, 1.0},
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "swap-total"
},
[VARIABLE_SWAP_SIZE] =
{ .name = "swap-size",
.title = NC_("dashboard-variable", "Size"),
.description = N_("Swap file size"),
.type = VARIABLE_TYPE_SIZE,
.color = {0.8, 0.6, 0.4, 1.0},
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "swap-file-size"
},
[VARIABLE_SWAP_LIMIT] =
{ .name = "swap-limit",
.title = NC_("dashboard-variable", "Limit"),
.description = N_("Swap file size limit"),
.type = VARIABLE_TYPE_SIZE,
.sample_func = gimp_dashboard_sample_swap_limit,
},
[VARIABLE_SWAP_QUEUED] =
{ .name = "swap-queued",
.title = NC_("dashboard-variable", "Queued"),
.description = N_("Size of data queued for writing to the swap"),
.type = VARIABLE_TYPE_SIZE,
.color = {0.8, 0.8, 0.2, 0.5},
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "swap-queued-total"
},
[VARIABLE_SWAP_QUEUE_STALLS] =
{ .name = "swap-queue-stalls",
.title = NC_("dashboard-variable", "Queue stalls"),
.description = N_("Number of times the writing to the swap has been "
"stalled, due to a full queue"),
.type = VARIABLE_TYPE_INTEGER,
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "swap-queue-stalls"
},
[VARIABLE_SWAP_QUEUE_FULL] =
{ .name = "swap-queue-full",
.title = NC_("dashboard-variable", "Queue full"),
.description = N_("Whether the swap queue is full"),
.type = VARIABLE_TYPE_BOOLEAN,
.sample_func = gimp_dashboard_sample_variable_changed,
.data = GINT_TO_POINTER (VARIABLE_SWAP_QUEUE_STALLS)
},
[VARIABLE_SWAP_READ] =
{ .name = "swap-read",
/* Translators: this is the past participle form of "read",
* as in "total amount of data read from the swap".
*/
.title = NC_("dashboard-variable", "Read"),
.description = N_("Total amount of data read from the swap"),
.type = VARIABLE_TYPE_SIZE,
.color = {0.2, 0.4, 1.0, 0.4},
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "swap-read-total"
},
[VARIABLE_SWAP_READ_THROUGHPUT] =
{ .name = "swap-read-throughput",
.title = NC_("dashboard-variable", "Read throughput"),
.description = N_("The rate at which data is read from the swap"),
.type = VARIABLE_TYPE_RATE_OF_CHANGE,
.color = {0.2, 0.4, 1.0, 1.0},
.sample_func = gimp_dashboard_sample_variable_rate_of_change,
.data = GINT_TO_POINTER (VARIABLE_SWAP_READ)
},
[VARIABLE_SWAP_WRITTEN] =
{ .name = "swap-written",
/* Translators: this is the past participle form of "write",
* as in "total amount of data written to the swap".
*/
.title = NC_("dashboard-variable", "Written"),
.description = N_("Total amount of data written to the swap"),
.type = VARIABLE_TYPE_SIZE,
.color = {0.8, 0.3, 0.2, 0.4},
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "swap-write-total"
},
[VARIABLE_SWAP_WRITE_THROUGHPUT] =
{ .name = "swap-write-throughput",
.title = NC_("dashboard-variable", "Write throughput"),
.description = N_("The rate at which data is written to the swap"),
.type = VARIABLE_TYPE_RATE_OF_CHANGE,
.color = {0.8, 0.3, 0.2, 1.0},
.sample_func = gimp_dashboard_sample_variable_rate_of_change,
.data = GINT_TO_POINTER (VARIABLE_SWAP_WRITTEN)
},
[VARIABLE_SWAP_COMPRESSION] =
{ .name = "swap-compression",
.title = NC_("dashboard-variable", "Compression"),
.description = N_("Swap compression ratio"),
.type = VARIABLE_TYPE_SIZE_RATIO,
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "swap-total\0"
"swap-total-uncloned"
},
#ifdef HAVE_CPU_GROUP
/* cpu variables */
[VARIABLE_CPU_USAGE] =
{ .name = "cpu-usage",
.title = NC_("dashboard-variable", "Usage"),
.description = N_("Total CPU usage"),
.type = VARIABLE_TYPE_PERCENTAGE,
.color = {0.8, 0.7, 0.2, 1.0},
.sample_func = gimp_dashboard_sample_cpu_usage
},
[VARIABLE_CPU_ACTIVE] =
{ .name = "cpu-active",
.title = NC_("dashboard-variable", "Active"),
.description = N_("Whether the CPU is active"),
.type = VARIABLE_TYPE_BOOLEAN,
.color = {0.9, 0.8, 0.3, 1.0},
.sample_func = gimp_dashboard_sample_cpu_active
},
[VARIABLE_CPU_ACTIVE_TIME] =
{ .name = "cpu-active-time",
.title = NC_("dashboard-variable", "Active"),
.description = N_("Total amount of time the CPU has been active"),
.type = VARIABLE_TYPE_DURATION,
.color = {0.8, 0.7, 0.2, 0.4},
.sample_func = gimp_dashboard_sample_cpu_active_time
},
#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] =
{ .name = "mipmapped",
.title = NC_("dashboard-variable", "Mipmapped"),
.description = N_("Total size of processed mipmapped data"),
.type = VARIABLE_TYPE_SIZE,
.sample_func = gimp_dashboard_sample_gegl_stats,
.data = "zoom-total"
},
[VARIABLE_ASYNC_RUNNING] =
{ .name = "async-running",
.title = NC_("dashboard-variable", "Async"),
.description = N_("Number of ongoing asynchronous operations"),
.type = VARIABLE_TYPE_INTEGER,
.sample_func = gimp_dashboard_sample_function,
.data = gimp_async_get_n_running
}
};
static const GroupInfo groups[] =
{
/* cache group */
[GROUP_CACHE] =
{ .name = "cache",
.title = NC_("dashboard-group", "Cache"),
.description = N_("In-memory tile cache"),
.default_active = TRUE,
.default_expanded = TRUE,
.has_meter = TRUE,
.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_MAXIMUM,
.default_active = FALSE,
.meter_value = 1
},
{ .variable = VARIABLE_CACHE_LIMIT,
.default_active = TRUE
},
{ VARIABLE_SEPARATOR },
{ .variable = VARIABLE_CACHE_COMPRESSION,
.default_active = FALSE
},
{ .variable = VARIABLE_CACHE_HIT_MISS,
.default_active = FALSE
},
{}
}
},
/* swap group */
[GROUP_SWAP] =
{ .name = "swap",
.title = NC_("dashboard-group", "Swap"),
.description = N_("On-disk tile swap"),
.default_active = TRUE,
.default_expanded = TRUE,
.has_meter = TRUE,
.meter_limit = VARIABLE_SWAP_LIMIT,
.meter_led = (const Variable[])
{
VARIABLE_SWAP_QUEUE_FULL,
VARIABLE_SWAP_READ_THROUGHPUT,
VARIABLE_SWAP_WRITE_THROUGHPUT,
VARIABLE_NONE
},
.fields = (const FieldInfo[])
{
{ .variable = VARIABLE_SWAP_OCCUPIED,
.default_active = TRUE,
.show_in_header = TRUE,
.meter_value = 5
},
{ .variable = VARIABLE_SWAP_SIZE,
.default_active = TRUE,
.meter_value = 4
},
{ .variable = VARIABLE_SWAP_LIMIT,
.default_active = TRUE
},
{ VARIABLE_SEPARATOR },
{ .variable = VARIABLE_SWAP_QUEUED,
.default_active = FALSE,
.meter_variable = VARIABLE_SWAP_QUEUE_FULL,
.meter_value = 3
},
{ VARIABLE_SEPARATOR },
{ .variable = VARIABLE_SWAP_READ,
.default_active = FALSE,
.meter_variable = VARIABLE_SWAP_READ_THROUGHPUT,
.meter_value = 2
},
{ .variable = VARIABLE_SWAP_WRITTEN,
.default_active = FALSE,
.meter_variable = VARIABLE_SWAP_WRITE_THROUGHPUT,
.meter_value = 1
},
{ VARIABLE_SEPARATOR },
{ .variable = VARIABLE_SWAP_COMPRESSION,
.default_active = FALSE
},
{}
}
},
#ifdef HAVE_CPU_GROUP
/* cpu group */
[GROUP_CPU] =
{ .name = "cpu",
.title = NC_("dashboard-group", "CPU"),
.description = N_("CPU usage"),
.default_active = TRUE,
.default_expanded = FALSE,
.has_meter = TRUE,
.meter_led = (const Variable[])
{
VARIABLE_CPU_ACTIVE,
VARIABLE_NONE
},
.fields = (const FieldInfo[])
{
{ .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
},
{}
}
},
#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",
.title = NC_("dashboard-group", "Misc"),
.description = N_("Miscellaneous information"),
.default_active = FALSE,
.default_expanded = FALSE,
.has_meter = FALSE,
.fields = (const FieldInfo[])
{
{ .variable = VARIABLE_MIPMAPED,
.default_active = TRUE
},
{ .variable = VARIABLE_ASYNC_RUNNING,
.default_active = TRUE
},
{}
}
},
};
G_DEFINE_TYPE_WITH_CODE (GimpDashboard, gimp_dashboard, GIMP_TYPE_EDITOR,
G_ADD_PRIVATE (GimpDashboard)
G_IMPLEMENT_INTERFACE (GIMP_TYPE_DOCKED,
gimp_dashboard_docked_iface_init))
#define parent_class gimp_dashboard_parent_class
static GimpDockedInterface *parent_docked_iface = NULL;
/* private functions */
static void
gimp_dashboard_class_init (GimpDashboardClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->constructed = gimp_dashboard_constructed;
object_class->dispose = gimp_dashboard_dispose;
object_class->finalize = gimp_dashboard_finalize;
widget_class->map = gimp_dashboard_map;
widget_class->unmap = gimp_dashboard_unmap;
}
static void
gimp_dashboard_init (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv;
GtkWidget *box;
GtkWidget *scrolled_window;
GtkWidget *viewport;
GtkWidget *vbox;
GtkWidget *expander;
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *image;
GtkWidget *menu;
GtkWidget *item;
GtkWidget *frame;
GtkWidget *vbox2;
GtkWidget *meter;
GtkWidget *grid;
GtkWidget *label;
gint content_spacing;
Group group;
gint field;
priv = dashboard->priv = gimp_dashboard_get_instance_private (dashboard);
g_mutex_init (&priv->mutex);
g_cond_init (&priv->cond);
priv->update_interval = DEFAULT_UPDATE_INTERVAL;
priv->history_duration = DEFAULT_HISTORY_DURATION;
priv->low_swap_space_warning = DEFAULT_LOW_SWAP_SPACE_WARNING;
gtk_widget_style_get (GTK_WIDGET (dashboard),
"content-spacing", &content_spacing,
NULL);
/* we put the dashboard inside an event box, so that it gets its own window,
* which reduces the overhead of updating the ui, since it gets updated
* frequently. unfortunately, this means that the dashboard's background
* color may be a bit off for some themes.
*/
box = gtk_event_box_new ();
gtk_box_pack_start (GTK_BOX (dashboard), box, TRUE, TRUE, 0);
gtk_widget_show (box);
/* scrolled window */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (box), scrolled_window);
gtk_widget_show (scrolled_window);
/* viewport */
viewport = gtk_viewport_new (
gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (scrolled_window)),
gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (scrolled_window)));
gtk_viewport_set_shadow_type (GTK_VIEWPORT (viewport), GTK_SHADOW_NONE);
gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
gtk_widget_show (viewport);
/* main vbox */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2 * content_spacing);
gtk_container_add (GTK_CONTAINER (viewport), vbox);
gtk_widget_show (vbox);
/* construct the groups */
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
const GroupInfo *group_info = &groups[group];
GroupData *group_data = &priv->groups[group];
group_data->n_fields = 0;
group_data->n_meter_values = 0;
for (field = 0; group_info->fields[field].variable; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
group_data->n_fields++;
group_data->n_meter_values = MAX (group_data->n_meter_values,
field_info->meter_value);
}
group_data->fields = g_new0 (FieldData, group_data->n_fields);
/* group expander */
expander = gtk_expander_new (NULL);
group_data->expander = GTK_EXPANDER (expander);
gtk_expander_set_expanded (GTK_EXPANDER (expander),
group_info->default_expanded);
gtk_expander_set_label_fill (GTK_EXPANDER (expander), TRUE);
gtk_box_pack_start (GTK_BOX (vbox), expander, FALSE, FALSE, 0);
g_object_set_data (G_OBJECT (expander),
"gimp-dashboard-group", GINT_TO_POINTER (group));
g_signal_connect_swapped (expander, "button-press-event",
G_CALLBACK (gimp_dashboard_group_expander_button_press),
dashboard);
/* group expander label box */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gimp_help_set_help_data (hbox,
g_dgettext (NULL, group_info->description),
NULL);
gtk_expander_set_label_widget (GTK_EXPANDER (expander), hbox);
gtk_widget_show (hbox);
/* group expander label */
label = gtk_label_new (g_dpgettext2 (NULL, "dashboard-group",
group_info->title));
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gimp_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
-1);
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
/* group expander values label */
label = gtk_label_new (NULL);
group_data->header_values_label = GTK_LABEL (label);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 4);
g_object_bind_property (expander, "expanded",
label, "visible",
G_BINDING_SYNC_CREATE |
G_BINDING_INVERT_BOOLEAN);
/* group expander menu button */
button = gtk_button_new ();
group_data->menu_button = GTK_BUTTON (button);
gimp_help_set_help_data (button, _("Select fields"),
NULL);
gtk_widget_set_can_focus (button, FALSE);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
image = gtk_image_new_from_icon_name (GIMP_ICON_MENU_LEFT,
GTK_ICON_SIZE_MENU);
gtk_image_set_pixel_size (GTK_IMAGE (image), 12);
gtk_image_set_from_icon_name (GTK_IMAGE (image), GIMP_ICON_MENU_LEFT,
GTK_ICON_SIZE_MENU);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
/* group menu */
menu = gtk_menu_new ();
group_data->menu = GTK_MENU (menu);
gtk_menu_attach_to_widget (GTK_MENU (menu), button, NULL);
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
FieldData *field_data = &group_data->fields[field];
if (field_info->variable != VARIABLE_SEPARATOR)
{
const VariableInfo *variable_info = &variables[field_info->variable];
item = gtk_check_menu_item_new_with_label (
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),
NULL);
g_object_set_data (G_OBJECT (item),
"gimp-dashboard-group", GINT_TO_POINTER (group));
g_object_set_data (G_OBJECT (item),
"gimp-dashboard-field", GINT_TO_POINTER (field));
g_signal_connect_swapped (item, "toggled",
G_CALLBACK (gimp_dashboard_field_menu_item_toggled),
dashboard);
gimp_dashboard_field_set_active (dashboard, group, field,
field_info->default_active);
}
else
{
item = gtk_separator_menu_item_new ();
}
gtk_menu_shell_append (GTK_MENU_SHELL (menu), item);
gtk_widget_show (item);
}
/* group frame */
frame = gimp_frame_new (NULL);
gtk_container_add (GTK_CONTAINER (expander), frame);
gtk_widget_show (frame);
/* group vbox */
vbox2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2 * content_spacing);
gtk_container_add (GTK_CONTAINER (frame), vbox2);
gtk_widget_show (vbox2);
/* group meter */
if (group_info->has_meter)
{
meter = gimp_meter_new (group_data->n_meter_values);
group_data->meter = GIMP_METER (meter);
gimp_help_set_help_data (meter,
g_dgettext (NULL, group_info->description),
NULL);
gimp_meter_set_history_resolution (GIMP_METER (meter),
priv->update_interval / 1000.0);
gimp_meter_set_history_duration (GIMP_METER (meter),
priv->history_duration / 1000.0);
gtk_box_pack_start (GTK_BOX (vbox2), meter, FALSE, FALSE, 0);
gtk_widget_show (meter);
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
if (field_info->meter_value)
{
const VariableInfo *variable_info = &variables[field_info->variable];
gimp_meter_set_value_color (GIMP_METER (meter),
field_info->meter_value - 1,
&variable_info->color);
if (gimp_dashboard_field_use_meter_underlay (group, field))
{
gimp_meter_set_value_show_in_gauge (GIMP_METER (meter),
field_info->meter_value - 1,
FALSE);
gimp_meter_set_value_interpolation (GIMP_METER (meter),
field_info->meter_value - 1,
GIMP_INTERPOLATION_NONE);
}
}
}
}
/* group grid */
grid = gtk_grid_new ();
group_data->grid = GTK_GRID (grid);
gtk_grid_set_row_spacing (GTK_GRID (grid), content_spacing);
gtk_grid_set_column_spacing (GTK_GRID (grid), 4);
gtk_box_pack_start (GTK_BOX (vbox2), grid, FALSE, FALSE, 0);
gtk_widget_show (grid);
gimp_dashboard_group_set_active (dashboard, group,
group_info->default_active);
gimp_dashboard_update_group (dashboard, group);
}
/* sampler thread
*
* we use a separate thread for sampling, so that data is sampled even when
* the main thread is busy
*/
priv->thread = g_thread_new ("dashboard",
(GThreadFunc) gimp_dashboard_sample,
dashboard);
}
static void
gimp_dashboard_docked_iface_init (GimpDockedInterface *iface)
{
parent_docked_iface = g_type_interface_peek_parent (iface);
if (! parent_docked_iface)
parent_docked_iface = g_type_default_interface_peek (GIMP_TYPE_DOCKED);
iface->set_aux_info = gimp_dashboard_set_aux_info;
iface->get_aux_info = gimp_dashboard_get_aux_info;
}
static void
gimp_dashboard_constructed (GObject *object)
{
GimpDashboard *dashboard = GIMP_DASHBOARD (object);
GimpDashboardPrivate *priv = dashboard->priv;
GimpUIManager *ui_manager;
GimpActionGroup *action_group;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
GtkAction *action;
GtkWidget *button;
GtkWidget *box;
GtkWidget *image;
GtkWidget *label;
Group group;
G_OBJECT_CLASS (parent_class)->constructed (object);
ui_manager = gimp_editor_get_ui_manager (GIMP_EDITOR (dashboard));
action_group = gimp_ui_manager_get_action_group (ui_manager, "dashboard");
/* group actions */
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
const GroupInfo *group_info = &groups[group];
GroupData *group_data = &priv->groups[group];
GimpToggleActionEntry entry = {};
entry.name = g_strdup_printf ("dashboard-group-%s", group_info->name);
entry.label = g_dpgettext2 (NULL, "dashboard-group", group_info->title);
entry.tooltip = g_dgettext (NULL, group_info->description);
entry.help_id = GIMP_HELP_DASHBOARD_GROUPS;
entry.is_active = group_data->active;
gimp_action_group_add_toggle_actions (action_group, "dashboard-groups",
&entry, 1);
action = gimp_ui_manager_find_action (ui_manager, "dashboard", entry.name);
group_data->action = GTK_TOGGLE_ACTION (action);
g_object_set_data (G_OBJECT (action),
"gimp-dashboard-group", GINT_TO_POINTER (group));
g_signal_connect_swapped (action, "toggled",
G_CALLBACK (gimp_dashboard_group_action_toggled),
dashboard);
g_free ((gpointer) entry.name);
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
button = gimp_editor_add_action_button (GIMP_EDITOR (dashboard), "dashboard",
"dashboard-log-record", NULL);
priv->log_record_button = button;
button = gimp_editor_add_action_button (GIMP_EDITOR (dashboard), "dashboard",
"dashboard-log-add-marker",
"dashboard-log-add-empty-marker",
gimp_get_extend_selection_mask (),
NULL);
action = gtk_action_group_get_action (GTK_ACTION_GROUP (action_group),
"dashboard-log-add-marker");
g_object_bind_property (action, "sensitive",
button, "visible",
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
image = g_object_ref (gtk_bin_get_child (GTK_BIN (button)));
gtk_container_remove (GTK_CONTAINER (button), image);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
gtk_container_add (GTK_CONTAINER (button), box);
gtk_widget_set_halign (GTK_WIDGET (box), GTK_ALIGN_CENTER);
gtk_widget_set_valign (GTK_WIDGET (box), GTK_ALIGN_CENTER);
gtk_widget_show (box);
gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0);
g_object_unref (image);
label = gtk_label_new (NULL);
priv->log_add_marker_label = GTK_LABEL (label);
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
gtk_widget_show (label);
button = gimp_editor_add_action_button (GIMP_EDITOR (dashboard), "dashboard",
"dashboard-reset", NULL);
action = gtk_action_group_get_action (GTK_ACTION_GROUP (action_group),
"dashboard-reset");
g_object_bind_property (action, "sensitive",
button, "visible",
G_BINDING_DEFAULT | G_BINDING_SYNC_CREATE);
gimp_action_group_update (action_group, dashboard);
}
static void
gimp_dashboard_dispose (GObject *object)
{
GimpDashboard *dashboard = GIMP_DASHBOARD (object);
GimpDashboardPrivate *priv = dashboard->priv;
if (priv->thread)
{
g_mutex_lock (&priv->mutex);
priv->quit = TRUE;
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->mutex);
g_clear_pointer (&priv->thread, g_thread_join);
}
if (priv->update_idle_id)
{
g_source_remove (priv->update_idle_id);
priv->update_idle_id = 0;
}
if (priv->low_swap_space_idle_id)
{
g_source_remove (priv->low_swap_space_idle_id);
priv->low_swap_space_idle_id = 0;
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gimp_dashboard_log_stop_recording (dashboard, NULL);
2018-06-21 04:03:19 -04:00
gimp_dashboard_reset_variables (dashboard);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
gimp_dashboard_finalize (GObject *object)
{
GimpDashboard *dashboard = GIMP_DASHBOARD (object);
GimpDashboardPrivate *priv = dashboard->priv;
gint i;
for (i = FIRST_GROUP; i < N_GROUPS; i++)
g_free (priv->groups[i].fields);
g_mutex_clear (&priv->mutex);
g_cond_clear (&priv->cond);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
gimp_dashboard_map (GtkWidget *widget)
{
GimpDashboard *dashboard = GIMP_DASHBOARD (widget);
GTK_WIDGET_CLASS (parent_class)->map (widget);
gimp_dashboard_update (dashboard);
}
static void
gimp_dashboard_unmap (GtkWidget *widget)
{
GimpDashboard *dashboard = GIMP_DASHBOARD (widget);
GimpDashboardPrivate *priv = dashboard->priv;
g_mutex_lock (&priv->mutex);
if (priv->update_idle_id)
{
g_source_remove (priv->update_idle_id);
priv->update_idle_id = 0;
}
g_mutex_unlock (&priv->mutex);
GTK_WIDGET_CLASS (parent_class)->unmap (widget);
}
#define AUX_INFO_UPDATE_INTERVAL "update-interval"
#define AUX_INFO_HISTORY_DURATION "history-duration"
#define AUX_INFO_LOW_SWAP_SPACE_WARNING "low-swap-space-warning"
static void
gimp_dashboard_set_aux_info (GimpDocked *docked,
GList *aux_info)
{
GimpDashboard *dashboard = GIMP_DASHBOARD (docked);
GimpDashboardPrivate *priv = dashboard->priv;
gchar *name;
GList *list;
parent_docked_iface->set_aux_info (docked, aux_info);
for (list = aux_info; list; list = g_list_next (list))
{
GimpSessionInfoAux *aux = list->data;
if (! strcmp (aux->name, AUX_INFO_UPDATE_INTERVAL))
{
gint value = atoi (aux->value);
GimpDashboardUpdateInteval update_interval;
for (update_interval = GIMP_DASHBOARD_UPDATE_INTERVAL_0_25_SEC;
update_interval < value &&
update_interval < GIMP_DASHBOARD_UPDATE_INTERVAL_4_SEC;
update_interval *= 2);
gimp_dashboard_set_update_interval (dashboard, update_interval);
}
else if (! strcmp (aux->name, AUX_INFO_HISTORY_DURATION))
{
gint value = atoi (aux->value);
GimpDashboardHistoryDuration history_duration;
for (history_duration = GIMP_DASHBOARD_HISTORY_DURATION_15_SEC;
history_duration < value &&
history_duration < GIMP_DASHBOARD_HISTORY_DURATION_240_SEC;
history_duration *= 2);
gimp_dashboard_set_history_duration (dashboard, history_duration);
}
else if (! strcmp (aux->name, AUX_INFO_LOW_SWAP_SPACE_WARNING))
{
gimp_dashboard_set_low_swap_space_warning (dashboard,
! strcmp (aux->value, "yes"));
}
else
{
Group group;
gint field;
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
const GroupInfo *group_info = &groups[group];
GroupData *group_data = &priv->groups[group];
name = g_strdup_printf ("%s-active", group_info->name);
if (! strcmp (aux->name, name))
{
gboolean active = ! strcmp (aux->value, "yes");
gimp_dashboard_group_set_active (dashboard, group, active);
g_free (name);
goto next_aux_info;
}
g_free (name);
name = g_strdup_printf ("%s-expanded", group_info->name);
if (! strcmp (aux->name, name))
{
gboolean expanded = ! strcmp (aux->value, "yes");
gtk_expander_set_expanded (group_data->expander, expanded);
g_free (name);
goto next_aux_info;
}
g_free (name);
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
if (field_info->variable != VARIABLE_SEPARATOR)
{
const VariableInfo *variable_info = &variables[field_info->variable];
name = g_strdup_printf ("%s-%s-active",
group_info->name,
variable_info->name);
if (! strcmp (aux->name, name))
{
gboolean active = ! strcmp (aux->value, "yes");
gimp_dashboard_field_set_active (dashboard,
group, field,
active);
g_free (name);
goto next_aux_info;
}
g_free (name);
}
}
}
}
next_aux_info: ;
}
gimp_dashboard_update_groups (dashboard);
}
static GList *
gimp_dashboard_get_aux_info (GimpDocked *docked)
{
GimpDashboard *dashboard = GIMP_DASHBOARD (docked);
GimpDashboardPrivate *priv = dashboard->priv;
GList *aux_info;
GimpSessionInfoAux *aux;
gchar *name;
gchar *value;
Group group;
gint field;
aux_info = parent_docked_iface->get_aux_info (docked);
if (priv->update_interval != DEFAULT_UPDATE_INTERVAL)
{
value = g_strdup_printf ("%d", priv->update_interval);
aux = gimp_session_info_aux_new (AUX_INFO_UPDATE_INTERVAL, value);
aux_info = g_list_append (aux_info, aux);
g_free (value);
}
if (priv->history_duration != DEFAULT_HISTORY_DURATION)
{
value = g_strdup_printf ("%d", priv->history_duration);
aux = gimp_session_info_aux_new (AUX_INFO_HISTORY_DURATION, value);
aux_info = g_list_append (aux_info, aux);
g_free (value);
}
if (priv->low_swap_space_warning != DEFAULT_LOW_SWAP_SPACE_WARNING)
{
value = priv->low_swap_space_warning ? "yes" : "no";
aux = gimp_session_info_aux_new (AUX_INFO_LOW_SWAP_SPACE_WARNING, value);
aux_info = g_list_append (aux_info, aux);
}
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
const GroupInfo *group_info = &groups[group];
GroupData *group_data = &priv->groups[group];
gboolean active = group_data->active;
gboolean expanded = gtk_expander_get_expanded (group_data->expander);
if (active != group_info->default_active)
{
name = g_strdup_printf ("%s-active", group_info->name);
value = active ? "yes" : "no";
aux = gimp_session_info_aux_new (name, value);
aux_info = g_list_append (aux_info, aux);
g_free (name);
}
if (expanded != group_info->default_expanded)
{
name = g_strdup_printf ("%s-expanded", group_info->name);
value = expanded ? "yes" : "no";
aux = gimp_session_info_aux_new (name, value);
aux_info = g_list_append (aux_info, aux);
g_free (name);
}
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
FieldData *field_data = &group_data->fields[field];
gboolean active = field_data->active;
if (field_info->variable != VARIABLE_SEPARATOR)
{
const VariableInfo *variable_info = &variables[field_info->variable];
if (active != field_info->default_active)
{
name = g_strdup_printf ("%s-%s-active",
group_info->name,
variable_info->name);
value = active ? "yes" : "no";
aux = gimp_session_info_aux_new (name, value);
aux_info = g_list_append (aux_info, aux);
g_free (name);
}
}
}
}
return aux_info;
}
static gboolean
gimp_dashboard_group_expander_button_press (GimpDashboard *dashboard,
GdkEventButton *bevent,
GtkWidget *widget)
{
GimpDashboardPrivate *priv = dashboard->priv;
Group group;
GroupData *group_data;
GtkAllocation expander_allocation;
GtkAllocation allocation;
group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
"gimp-dashboard-group"));
group_data = &priv->groups[group];
gtk_widget_get_allocation (GTK_WIDGET (group_data->expander),
&expander_allocation);
gtk_widget_get_allocation (GTK_WIDGET (group_data->menu_button),
&allocation);
allocation.x -= expander_allocation.x;
allocation.y -= expander_allocation.y;
2017-12-31 10:43:47 -05:00
if (bevent->button == 1 &&
bevent->x >= allocation.x &&
bevent->x < allocation.x + allocation.width &&
bevent->y >= allocation.y &&
bevent->y < allocation.y + allocation.height)
{
gtk_menu_popup_at_widget (group_data->menu,
GTK_WIDGET (group_data->menu_button),
GDK_GRAVITY_WEST,
GDK_GRAVITY_NORTH_EAST,
(GdkEvent *) bevent);
return TRUE;
}
return FALSE;
}
static void
gimp_dashboard_group_action_toggled (GimpDashboard *dashboard,
GtkToggleAction *action)
{
GimpDashboardPrivate *priv = dashboard->priv;
Group group;
GroupData *group_data;
group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (action),
"gimp-dashboard-group"));
group_data = &priv->groups[group];
group_data->active = gtk_toggle_action_get_active (action);
gimp_dashboard_update_group (dashboard, group);
}
static void
gimp_dashboard_field_menu_item_toggled (GimpDashboard *dashboard,
GtkCheckMenuItem *item)
{
GimpDashboardPrivate *priv = dashboard->priv;
Group group;
GroupData *group_data;
gint field;
FieldData *field_data;
group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item),
"gimp-dashboard-group"));
group_data = &priv->groups[group];
field = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item),
"gimp-dashboard-field"));
field_data = &group_data->fields[field];
field_data->active = gtk_check_menu_item_get_active (item);
gimp_dashboard_update_group (dashboard, group);
}
static gpointer
gimp_dashboard_sample (GimpDashboard *dashboard)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
GimpDashboardPrivate *priv = dashboard->priv;
gint64 last_sample_time = 0;
gint64 last_update_time = 0;
gboolean seen_low_swap_space = FALSE;
g_mutex_lock (&priv->mutex);
while (! priv->quit)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gint64 update_interval;
gint64 sample_interval;
gint64 end_time;
update_interval = priv->update_interval * G_TIME_SPAN_SECOND / 1000;
if (priv->log_output)
sample_interval = G_TIME_SPAN_SECOND / priv->log_sample_frequency;
else
sample_interval = update_interval;
end_time = last_sample_time + sample_interval;
if (! g_cond_wait_until (&priv->cond, &priv->mutex, end_time) ||
priv->update_now)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gint64 time;
gboolean variables_changed = FALSE;
Variable variable;
Group group;
gint field;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
time = g_get_monotonic_time ();
/* sample all variables */
for (variable = FIRST_VARIABLE; variable < N_VARIABLES; variable++)
{
const VariableInfo *variable_info = &variables[variable];
const VariableData *variable_data = &priv->variables[variable];
VariableData prev_variable_data = *variable_data;
variable_info->sample_func (dashboard, variable);
variables_changed = variables_changed ||
memcmp (variable_data, &prev_variable_data,
sizeof (VariableData));
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
/* log sample */
if (priv->log_output)
gimp_dashboard_log_sample (dashboard, variables_changed);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
/* update gui */
if (priv->update_now ||
! priv->log_output ||
time - last_update_time >= update_interval)
{
/* add samples to meters */
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
const GroupInfo *group_info = &groups[group];
GroupData *group_data = &priv->groups[group];
gdouble *sample;
gdouble total = 0.0;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (! group_info->has_meter)
continue;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
sample = g_new (gdouble, group_data->n_meter_values);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (field_info->meter_value)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gdouble value;
if (field_info->meter_variable)
variable = field_info->meter_variable;
else
variable = field_info->variable;
value = gimp_dashboard_variable_to_double (dashboard,
variable);
if (value &&
gimp_dashboard_field_use_meter_underlay (group,
field))
{
value = G_MAXDOUBLE;
}
if (field_info->meter_cumulative)
{
total += value;
value = total;
}
sample[field_info->meter_value - 1] = value;
}
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gimp_meter_add_sample (group_data->meter, sample);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
g_free (sample);
2017-12-31 10:43:47 -05:00
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (variables_changed)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
/* enqueue update source */
if (! priv->update_idle_id &&
gtk_widget_get_mapped (GTK_WIDGET (dashboard)))
{
priv->update_idle_id = g_idle_add_full (
G_PRIORITY_DEFAULT,
(GSourceFunc) gimp_dashboard_update,
dashboard, NULL);
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
/* check for low swap space */
if (priv->low_swap_space_warning &&
priv->variables[VARIABLE_SWAP_OCCUPIED].available &&
priv->variables[VARIABLE_SWAP_LIMIT].available)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
guint64 swap_occupied;
guint64 swap_limit;
swap_occupied = priv->variables[VARIABLE_SWAP_OCCUPIED].value.size;
swap_limit = priv->variables[VARIABLE_SWAP_LIMIT].value.size;
if (! seen_low_swap_space &&
swap_occupied >= LOW_SWAP_SPACE_WARNING_ON * swap_limit)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (! priv->low_swap_space_idle_id)
{
priv->low_swap_space_idle_id =
g_idle_add_full (G_PRIORITY_HIGH,
(GSourceFunc) gimp_dashboard_low_swap_space,
dashboard, NULL);
}
seen_low_swap_space = TRUE;
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
else if (seen_low_swap_space &&
swap_occupied <= LOW_SWAP_SPACE_WARNING_OFF * swap_limit)
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (priv->low_swap_space_idle_id)
{
g_source_remove (priv->low_swap_space_idle_id);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
priv->low_swap_space_idle_id = 0;
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
seen_low_swap_space = FALSE;
}
}
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
priv->update_now = FALSE;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
last_update_time = time;
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
last_sample_time = time;
}
}
g_mutex_unlock (&priv->mutex);
return NULL;
}
static gboolean
gimp_dashboard_update (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv = dashboard->priv;
Group group;
g_mutex_lock (&priv->mutex);
for (group = FIRST_GROUP; group < N_GROUPS; group++)
gimp_dashboard_update_group_values (dashboard, group);
priv->update_idle_id = 0;
g_mutex_unlock (&priv->mutex);
return G_SOURCE_REMOVE;
}
static gboolean
gimp_dashboard_low_swap_space (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv = dashboard->priv;
if (priv->gimp)
{
GdkMonitor *monitor;
gint field;
gtk_expander_set_expanded (priv->groups[GROUP_SWAP].expander, TRUE);
for (field = 0; field < priv->groups[GROUP_SWAP].n_fields; field++)
{
const FieldInfo *field_info = &groups[GROUP_SWAP].fields[field];
if (field_info->variable == VARIABLE_SWAP_OCCUPIED ||
field_info->variable == VARIABLE_SWAP_LIMIT)
{
gimp_dashboard_field_set_active (dashboard,
GROUP_SWAP, field, TRUE);
}
}
gimp_dashboard_update_groups (dashboard);
monitor = gimp_get_monitor_at_pointer ();
gimp_window_strategy_show_dockable_dialog (
GIMP_WINDOW_STRATEGY (gimp_get_window_strategy (priv->gimp)),
priv->gimp,
gimp_dialog_factory_get_singleton (),
monitor,
"gimp-dashboard");
g_mutex_lock (&priv->mutex);
priv->low_swap_space_idle_id = 0;
g_mutex_unlock (&priv->mutex);
}
return G_SOURCE_REMOVE;
}
static void
gimp_dashboard_sample_function (GimpDashboard *dashboard,
Variable variable)
{
GimpDashboardPrivate *priv = dashboard->priv;
const VariableInfo *variable_info = &variables[variable];
VariableData *variable_data = &priv->variables[variable];
#define CALL_FUNC(result_type) \
(((result_type (*) (void)) variable_info->data) ())
switch (variable_info->type)
{
case VARIABLE_TYPE_BOOLEAN:
variable_data->value.boolean = CALL_FUNC (gboolean);
break;
case VARIABLE_TYPE_INTEGER:
variable_data->value.integer = CALL_FUNC (gint);
case VARIABLE_TYPE_SIZE:
variable_data->value.size = CALL_FUNC (guint64);
break;
case VARIABLE_TYPE_PERCENTAGE:
variable_data->value.percentage = CALL_FUNC (gdouble);
break;
case VARIABLE_TYPE_DURATION:
variable_data->value.duration = CALL_FUNC (gdouble);
break;
case VARIABLE_TYPE_RATE_OF_CHANGE:
variable_data->value.rate_of_change = CALL_FUNC (gdouble);
break;
case VARIABLE_TYPE_SIZE_RATIO:
case VARIABLE_TYPE_INT_RATIO:
g_return_if_reached ();
break;
}
#undef CALL_FUNC
variable_data->available = TRUE;
}
static void
gimp_dashboard_sample_gegl_config (GimpDashboard *dashboard,
Variable variable)
{
gimp_dashboard_sample_object (dashboard, G_OBJECT (gegl_config ()), variable);
}
static void
gimp_dashboard_sample_gegl_stats (GimpDashboard *dashboard,
Variable variable)
{
gimp_dashboard_sample_object (dashboard, G_OBJECT (gegl_stats ()), variable);
}
static void
gimp_dashboard_sample_variable_changed (GimpDashboard *dashboard,
Variable variable)
{
GimpDashboardPrivate *priv = dashboard->priv;
const VariableInfo *variable_info = &variables[variable];
VariableData *variable_data = &priv->variables[variable];
Variable var = GPOINTER_TO_INT (variable_info->data);
const VariableData *var_data = &priv->variables[var];
gpointer prev_value = gimp_dashboard_variable_get_data (
dashboard, variable,
sizeof (var_data->value));
if (var_data->available)
{
variable_data->available = TRUE;
variable_data->value.boolean = memcmp (&var_data->value, prev_value,
sizeof (var_data->value)) != 0;
if (variable_data->value.boolean)
memcpy (prev_value, &var_data->value, sizeof (var_data->value));
}
else
{
variable_data->available = FALSE;
}
}
static void
gimp_dashboard_sample_variable_rate_of_change (GimpDashboard *dashboard,
Variable variable)
{
typedef struct
{
gint64 last_time;
gboolean last_available;
gdouble last_value;
} Data;
GimpDashboardPrivate *priv = dashboard->priv;
const VariableInfo *variable_info = &variables[variable];
VariableData *variable_data = &priv->variables[variable];
Variable var = GPOINTER_TO_INT (variable_info->data);
const VariableData *var_data = &priv->variables[var];
Data *data = gimp_dashboard_variable_get_data (
dashboard, variable, sizeof (Data));
gint64 time;
time = g_get_monotonic_time ();
if (time == data->last_time)
return;
variable_data->available = FALSE;
if (var_data->available)
{
gdouble value = gimp_dashboard_variable_to_double (dashboard, var);
if (data->last_available)
{
variable_data->available = TRUE;
variable_data->value.rate_of_change = (value - data->last_value) *
G_TIME_SPAN_SECOND /
(time - data->last_time);
}
data->last_value = value;
}
data->last_time = time;
data->last_available = var_data->available;
}
static void
gimp_dashboard_sample_swap_limit (GimpDashboard *dashboard,
Variable variable)
{
typedef struct
{
guint64 free_space;
gboolean has_free_space;
gint64 last_check_time;
} Data;
GimpDashboardPrivate *priv = dashboard->priv;
VariableData *variable_data = &priv->variables[variable];
Data *data = gimp_dashboard_variable_get_data (
dashboard, variable, sizeof (Data));
gint64 time;
/* 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 - data->last_check_time >= G_TIME_SPAN_SECOND)
{
gchar *swap_dir;
g_object_get (gegl_config (),
"swap", &swap_dir,
NULL);
data->free_space = 0;
data->has_free_space = FALSE;
if (swap_dir)
{
GFile *file;
GFileInfo *info;
file = g_file_new_for_path (swap_dir);
info = g_file_query_filesystem_info (file,
G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
NULL, NULL);
if (info)
{
data->free_space =
g_file_info_get_attribute_uint64 (info,
G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
data->has_free_space = TRUE;
g_object_unref (info);
}
g_object_unref (file);
g_free (swap_dir);
}
data->last_check_time = time;
}
variable_data->available = data->has_free_space;
if (data->has_free_space)
{
variable_data->value.size = data->free_space;
if (priv->variables[VARIABLE_SWAP_SIZE].available)
{
/* the swap limit is the sum of free_space and swap_size, since the
* swap itself occupies space in the filesystem
*/
variable_data->value.size +=
priv->variables[VARIABLE_SWAP_SIZE].value.size;
}
}
}
#ifdef HAVE_CPU_GROUP
#ifdef HAVE_SYS_TIMES_H
static void
gimp_dashboard_sample_cpu_usage (GimpDashboard *dashboard,
Variable variable)
{
typedef struct
{
clock_t prev_clock;
clock_t prev_usage;
} Data;
GimpDashboardPrivate *priv = dashboard->priv;
VariableData *variable_data = &priv->variables[variable];
Data *data = gimp_dashboard_variable_get_data (
dashboard, variable, sizeof (Data));
clock_t curr_clock;
clock_t curr_usage;
struct tms tms;
curr_clock = times (&tms);
if (curr_clock == (clock_t) -1)
{
data->prev_clock = 0;
variable_data->available = FALSE;
return;
}
curr_usage = tms.tms_utime + tms.tms_stime;
if (data->prev_clock && curr_clock != data->prev_clock)
{
variable_data->available = TRUE;
variable_data->value.percentage = (gdouble) (curr_usage - data->prev_usage) /
(curr_clock - data->prev_clock);
variable_data->value.percentage /= g_get_num_processors ();
}
else
{
variable_data->available = FALSE;
}
data->prev_clock = curr_clock;
data->prev_usage = curr_usage;
}
#elif defined (G_OS_WIN32)
static void
gimp_dashboard_sample_cpu_usage (GimpDashboard *dashboard,
Variable variable)
{
typedef struct
{
guint64 prev_time;
guint64 prev_usage;
} Data;
GimpDashboardPrivate *priv = dashboard->priv;
VariableData *variable_data = &priv->variables[variable];
2018-06-28 05:03:55 -04:00
Data *data = gimp_dashboard_variable_get_data (
dashboard, variable, sizeof (Data));
guint64 curr_time;
guint64 curr_usage;
FILETIME system_time;
FILETIME process_creation_time;
FILETIME process_exit_time;
FILETIME process_kernel_time;
FILETIME process_user_time;
if (! GetProcessTimes (GetCurrentProcess (),
&process_creation_time,
&process_exit_time,
&process_kernel_time,
&process_user_time))
{
data->prev_time = 0;
variable_data->available = FALSE;
return;
}
GetSystemTimeAsFileTime (&system_time);
curr_time = ((guint64) system_time.dwHighDateTime << 32) |
(guint64) system_time.dwLowDateTime;
curr_usage = ((guint64) process_kernel_time.dwHighDateTime << 32) |
(guint64) process_kernel_time.dwLowDateTime;
curr_usage += ((guint64) process_user_time.dwHighDateTime << 32) |
(guint64) process_user_time.dwLowDateTime;
if (data->prev_time && curr_time != data->prev_time)
{
variable_data->available = TRUE;
variable_data->value.percentage = (gdouble) (curr_usage - data->prev_usage) /
(curr_time - data->prev_time);
variable_data->value.percentage /= g_get_num_processors ();
}
else
{
variable_data->available = FALSE;
}
data->prev_time = curr_time;
data->prev_usage = curr_usage;
}
#endif /* G_OS_WIN32 */
static void
gimp_dashboard_sample_cpu_active (GimpDashboard *dashboard,
Variable variable)
{
typedef struct
{
gboolean active;
} Data;
GimpDashboardPrivate *priv = dashboard->priv;
VariableData *variable_data = &priv->variables[variable];
Data *data = gimp_dashboard_variable_get_data (
dashboard, variable, sizeof (Data));
gboolean active = FALSE;
if (priv->variables[VARIABLE_CPU_USAGE].available)
{
if (! data->active)
{
active =
priv->variables[VARIABLE_CPU_USAGE].value.percentage *
g_get_num_processors () > CPU_ACTIVE_ON;
}
else
{
active =
priv->variables[VARIABLE_CPU_USAGE].value.percentage *
g_get_num_processors () > CPU_ACTIVE_OFF;
}
variable_data->available = TRUE;
}
else
{
variable_data->available = FALSE;
}
data->active = active;
variable_data->value.boolean = active;
}
static void
gimp_dashboard_sample_cpu_active_time (GimpDashboard *dashboard,
Variable variable)
{
typedef struct
{
gint64 prev_time;
gint64 active_time;
} Data;
GimpDashboardPrivate *priv = dashboard->priv;
VariableData *variable_data = &priv->variables[variable];
Data *data = gimp_dashboard_variable_get_data (
dashboard, variable, sizeof (Data));
gint64 curr_time;
curr_time = g_get_monotonic_time ();
if (priv->variables[VARIABLE_CPU_ACTIVE].available)
{
gboolean active = priv->variables[VARIABLE_CPU_ACTIVE].value.boolean;
if (active && data->prev_time)
data->active_time += curr_time - data->prev_time;
}
data->prev_time = curr_time;
variable_data->available = TRUE;
variable_data->value.duration = data->active_time / 1000000.0;
}
#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 = -1;
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];
PROCESS_MEMORY_COUNTERS_EX pmc = {};
variable_data->available = FALSE;
if (! GetProcessMemoryInfo (GetCurrentProcess (),
(PPROCESS_MEMORY_COUNTERS) &pmc,
sizeof (pmc)) ||
pmc.cb != 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,
Variable variable)
{
GimpDashboardPrivate *priv = dashboard->priv;
GObjectClass *klass = G_OBJECT_GET_CLASS (object);
const VariableInfo *variable_info = &variables[variable];
VariableData *variable_data = &priv->variables[variable];
variable_data->available = FALSE;
switch (variable_info->type)
{
case VARIABLE_TYPE_BOOLEAN:
if (g_object_class_find_property (klass, variable_info->data))
{
variable_data->available = TRUE;
g_object_get (object,
variable_info->data, &variable_data->value.boolean,
NULL);
}
break;
case VARIABLE_TYPE_INTEGER:
if (g_object_class_find_property (klass, variable_info->data))
{
variable_data->available = TRUE;
g_object_get (object,
variable_info->data, &variable_data->value.integer,
NULL);
}
break;
case VARIABLE_TYPE_SIZE:
if (g_object_class_find_property (klass, variable_info->data))
{
variable_data->available = TRUE;
g_object_get (object,
variable_info->data, &variable_data->value.size,
NULL);
}
break;
case VARIABLE_TYPE_SIZE_RATIO:
{
const gchar *antecedent = variable_info->data;
const gchar *consequent = antecedent + strlen (antecedent) + 1;
if (g_object_class_find_property (klass, antecedent) &&
g_object_class_find_property (klass, consequent))
{
variable_data->available = TRUE;
g_object_get (object,
antecedent, &variable_data->value.size_ratio.antecedent,
consequent, &variable_data->value.size_ratio.consequent,
NULL);
}
}
break;
case VARIABLE_TYPE_INT_RATIO:
{
const gchar *antecedent = variable_info->data;
const gchar *consequent = antecedent + strlen (antecedent) + 1;
if (g_object_class_find_property (klass, antecedent) &&
g_object_class_find_property (klass, consequent))
{
variable_data->available = TRUE;
g_object_get (object,
antecedent, &variable_data->value.int_ratio.antecedent,
consequent, &variable_data->value.int_ratio.consequent,
NULL);
}
}
break;
case VARIABLE_TYPE_PERCENTAGE:
if (g_object_class_find_property (klass, variable_info->data))
{
variable_data->available = TRUE;
g_object_get (object,
variable_info->data, &variable_data->value.percentage,
NULL);
}
break;
case VARIABLE_TYPE_DURATION:
if (g_object_class_find_property (klass, variable_info->data))
{
variable_data->available = TRUE;
g_object_get (object,
variable_info->data, &variable_data->value.duration,
NULL);
}
break;
case VARIABLE_TYPE_RATE_OF_CHANGE:
if (g_object_class_find_property (klass, variable_info->data))
{
variable_data->available = TRUE;
g_object_get (object,
variable_info->data, &variable_data->value.rate_of_change,
NULL);
}
break;
}
}
static void
gimp_dashboard_update_groups (GimpDashboard *dashboard)
{
Group group;
for (group = FIRST_GROUP; group < N_GROUPS; group++)
gimp_dashboard_update_group (dashboard, group);
}
static void
gimp_dashboard_update_group (GimpDashboard *dashboard,
Group group)
{
GimpDashboardPrivate *priv = dashboard->priv;
const GroupInfo *group_info = &groups[group];
GroupData *group_data = &priv->groups[group];
gint n_rows;
gboolean add_separator;
gint field;
gtk_widget_set_visible (GTK_WIDGET (group_data->expander),
group_data->active);
if (! group_data->active)
return;
n_rows = 0;
add_separator = FALSE;
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
const FieldData *field_data = &group_data->fields[field];
if (field_info->variable != VARIABLE_SEPARATOR)
{
if (group_info->has_meter && field_info->meter_value)
{
gimp_meter_set_value_active (group_data->meter,
field_info->meter_value - 1,
field_data->active);
}
if (field_data->active)
{
if (add_separator)
{
add_separator = FALSE;
n_rows++;
}
n_rows++;
}
}
else
{
if (n_rows > 0)
add_separator = TRUE;
}
}
gimp_gtk_container_clear (GTK_CONTAINER (group_data->grid));
n_rows = 0;
add_separator = FALSE;
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
FieldData *field_data = &group_data->fields[field];
if (field_info->variable != VARIABLE_SEPARATOR)
{
const VariableInfo *variable_info = &variables[field_info->variable];
GtkWidget *separator;
GtkWidget *color_area;
GtkWidget *label;
const gchar *description;
gchar *str;
if (! field_data->active)
continue;
description = g_dgettext (NULL, variable_info->description);
if (add_separator)
{
separator = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
gtk_widget_set_hexpand (separator, TRUE);
gtk_grid_attach (group_data->grid, separator,
0, n_rows, 3, 1);
gtk_widget_show (separator);
add_separator = FALSE;
n_rows++;
}
if (variable_info->color.a)
{
color_area = gimp_color_area_new (&variable_info->color,
GIMP_COLOR_AREA_FLAT, 0);
gimp_help_set_help_data (color_area, description,
NULL);
gtk_widget_set_size_request (color_area, 5, 5);
gtk_widget_set_valign (color_area, GTK_ALIGN_CENTER);
gtk_grid_attach (group_data->grid, color_area,
0, n_rows, 1, 1);
gtk_widget_show (color_area);
}
str = g_strdup_printf ("%s:",
g_dpgettext2 (NULL, "dashboard-variable",
field_info->title ?
field_info->title :
variable_info->title));
label = gtk_label_new (str);
gimp_help_set_help_data (label, description,
NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_grid_attach (group_data->grid, label,
1, n_rows, 1, 1);
gtk_widget_show (label);
g_free (str);
label = gtk_label_new (NULL);
field_data->value_label = GTK_LABEL (label);
gimp_help_set_help_data (label, description,
NULL);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (group_data->grid, label,
2, n_rows, 1, 1);
gtk_widget_show (label);
n_rows++;
}
else
{
if (n_rows > 0)
add_separator = TRUE;
}
}
g_mutex_lock (&priv->mutex);
gimp_dashboard_update_group_values (dashboard, group);
g_mutex_unlock (&priv->mutex);
}
static void
gimp_dashboard_update_group_values (GimpDashboard *dashboard,
Group group)
{
GimpDashboardPrivate *priv = dashboard->priv;
const GroupInfo *group_info = &groups[group];
GroupData *group_data = &priv->groups[group];
gdouble limit = 0.0;
GString *header_values;
gint field;
if (! group_data->active)
return;
if (group_info->has_meter)
{
if (group_info->meter_limit)
{
const VariableData *variable_data = &priv->variables[group_info->meter_limit];
if (variable_data->available)
{
limit = gimp_dashboard_variable_to_double (dashboard,
group_info->meter_limit);
}
else
{
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
const FieldData *field_data = &group_data->fields[field];
if (field_info->meter_value && field_data->active)
{
gdouble value;
value = gimp_dashboard_variable_to_double (dashboard,
field_info->variable);
limit = MAX (limit, value);
}
}
}
gimp_meter_set_range (group_data->meter, 0.0, limit);
}
if (group_info->meter_led)
{
GimpRGB color = {0.0, 0.0, 0.0, 1.0};
gboolean active = FALSE;
const Variable *var;
for (var = group_info->meter_led; *var; var++)
{
if (gimp_dashboard_variable_to_boolean (dashboard, *var))
{
const VariableInfo *variable_info = &variables[*var];
color.r = MAX (color.r, variable_info->color.r);
color.g = MAX (color.g, variable_info->color.g);
color.b = MAX (color.b, variable_info->color.b);
active = TRUE;
}
}
if (active)
gimp_meter_set_led_color (group_data->meter, &color);
gimp_meter_set_led_active (group_data->meter, active);
}
}
group_data->limit = limit;
header_values = g_string_new (NULL);
for (field = 0; field < group_data->n_fields; field++)
{
const FieldInfo *field_info = &group_info->fields[field];
const FieldData *field_data = &group_data->fields[field];
if (field_data->active)
{
gchar *text;
text = gimp_dashboard_field_to_string (dashboard,
group, field, TRUE);
gimp_dashboard_label_set_text (field_data->value_label, text);
g_free (text);
if (field_info->show_in_header)
{
text = gimp_dashboard_field_to_string (dashboard,
group, field, FALSE);
if (header_values->len > 0)
g_string_append (header_values, ", ");
g_string_append (header_values, text);
g_free (text);
}
}
}
if (header_values->len > 0)
{
g_string_prepend (header_values, "(");
g_string_append (header_values, ")");
}
gimp_dashboard_label_set_text (group_data->header_values_label,
header_values->str);
g_string_free (header_values, TRUE);
}
static void
gimp_dashboard_group_set_active (GimpDashboard *dashboard,
Group group,
gboolean active)
{
GimpDashboardPrivate *priv = dashboard->priv;
GroupData *group_data = &priv->groups[group];
if (active != group_data->active)
{
group_data->active = active;
if (group_data->action)
{
g_signal_handlers_block_by_func (group_data->action,
gimp_dashboard_group_action_toggled,
dashboard);
gtk_toggle_action_set_active (group_data->action, active);
g_signal_handlers_unblock_by_func (group_data->action,
gimp_dashboard_group_action_toggled,
dashboard);
}
}
}
static void
gimp_dashboard_field_set_active (GimpDashboard *dashboard,
Group group,
gint field,
gboolean active)
{
GimpDashboardPrivate *priv = dashboard->priv;
GroupData *group_data = &priv->groups[group];
FieldData *field_data = &group_data->fields[field];
if (active != field_data->active)
{
field_data->active = active;
g_signal_handlers_block_by_func (field_data->menu_item,
gimp_dashboard_field_menu_item_toggled,
dashboard);
gtk_check_menu_item_set_active (field_data->menu_item, active);
g_signal_handlers_unblock_by_func (field_data->menu_item,
gimp_dashboard_field_menu_item_toggled,
dashboard);
}
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
static void
gimp_dashboard_reset_unlocked (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv;
Group group;
priv = dashboard->priv;
gegl_reset_stats ();
gimp_dashboard_reset_variables (dashboard);
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
GroupData *group_data = &priv->groups[group];
if (group_data->meter)
gimp_meter_clear_history (group_data->meter);
}
}
2018-06-21 04:03:19 -04:00
static void
gimp_dashboard_reset_variables (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv = dashboard->priv;
Variable variable;
for (variable = FIRST_VARIABLE; variable < N_VARIABLES; variable++)
{
const VariableInfo *variable_info = &variables[variable];
VariableData *variable_data = &priv->variables[variable];
if (variable_info->reset_func)
variable_info->reset_func (dashboard, variable);
g_clear_pointer (&variable_data->data, g_free);
variable_data->data_size = 0;
}
}
static gpointer
gimp_dashboard_variable_get_data (GimpDashboard *dashboard,
Variable variable,
gsize size)
{
GimpDashboardPrivate *priv = dashboard->priv;
VariableData *variable_data = &priv->variables[variable];
if (variable_data->data_size != size)
{
variable_data->data = g_realloc (variable_data->data, size);
if (variable_data->data_size < size)
2018-06-21 04:03:19 -04:00
{
memset ((guint8 *) variable_data->data + variable_data->data_size,
0, size - variable_data->data_size);
}
variable_data->data_size = size;
}
return variable_data->data;
}
static gboolean
gimp_dashboard_variable_to_boolean (GimpDashboard *dashboard,
Variable variable)
{
GimpDashboardPrivate *priv = dashboard->priv;
const VariableInfo *variable_info = &variables[variable];
const VariableData *variable_data = &priv->variables[variable];
if (variable_data->available)
{
switch (variable_info->type)
{
case VARIABLE_TYPE_BOOLEAN:
return variable_data->value.boolean;
case VARIABLE_TYPE_INTEGER:
return variable_data->value.integer != 0;
case VARIABLE_TYPE_SIZE:
return variable_data->value.size > 0;
case VARIABLE_TYPE_SIZE_RATIO:
return variable_data->value.size_ratio.antecedent != 0 &&
variable_data->value.size_ratio.consequent != 0;
case VARIABLE_TYPE_INT_RATIO:
return variable_data->value.int_ratio.antecedent != 0 &&
variable_data->value.int_ratio.consequent != 0;
case VARIABLE_TYPE_PERCENTAGE:
return variable_data->value.percentage != 0.0;
case VARIABLE_TYPE_DURATION:
return variable_data->value.duration != 0.0;
case VARIABLE_TYPE_RATE_OF_CHANGE:
return variable_data->value.rate_of_change != 0.0;
}
}
return FALSE;
}
static gdouble
gimp_dashboard_variable_to_double (GimpDashboard *dashboard,
Variable variable)
{
GimpDashboardPrivate *priv = dashboard->priv;
const VariableInfo *variable_info = &variables[variable];
const VariableData *variable_data = &priv->variables[variable];
if (variable_data->available)
{
switch (variable_info->type)
{
case VARIABLE_TYPE_BOOLEAN:
return variable_data->value.boolean ? 1.0 : 0.0;
case VARIABLE_TYPE_INTEGER:
return variable_data->value.integer;
case VARIABLE_TYPE_SIZE:
return variable_data->value.size;
case VARIABLE_TYPE_SIZE_RATIO:
if (variable_data->value.size_ratio.consequent)
{
return (gdouble) variable_data->value.size_ratio.antecedent /
(gdouble) variable_data->value.size_ratio.consequent;
}
break;
case VARIABLE_TYPE_INT_RATIO:
if (variable_data->value.int_ratio.consequent)
{
return (gdouble) variable_data->value.int_ratio.antecedent /
(gdouble) variable_data->value.int_ratio.consequent;
}
break;
case VARIABLE_TYPE_PERCENTAGE:
return variable_data->value.percentage;
case VARIABLE_TYPE_DURATION:
return variable_data->value.duration;
case VARIABLE_TYPE_RATE_OF_CHANGE:
return variable_data->value.rate_of_change;
}
}
return 0.0;
}
static gchar *
gimp_dashboard_field_to_string (GimpDashboard *dashboard,
Group group,
gint field,
gboolean full)
{
GimpDashboardPrivate *priv = dashboard->priv;
const GroupInfo *group_info = &groups[group];
const GroupData *group_data = &priv->groups[group];
const FieldInfo *field_info = &group_info->fields[field];
const VariableInfo *variable_info = &variables[field_info->variable];
const VariableData *variable_data = &priv->variables[field_info->variable];
/* Tranlators: "N/A" is an abbreviation for "not available" */
const gchar *str = C_("dashboard-value", "N/A");
gboolean static_str = TRUE;
gboolean show_limit = TRUE;
if (variable_data->available)
{
switch (variable_info->type)
{
case VARIABLE_TYPE_BOOLEAN:
str = variable_data->value.boolean ? C_("dashboard-value", "Yes") :
C_("dashboard-value", "No");
break;
case VARIABLE_TYPE_INTEGER:
str = g_strdup_printf ("%d", variable_data->value.integer);
static_str = FALSE;
break;
case VARIABLE_TYPE_SIZE:
str = g_format_size_full (variable_data->value.size,
G_FORMAT_SIZE_IEC_UNITS);
static_str = FALSE;
break;
case VARIABLE_TYPE_SIZE_RATIO:
{
if (variable_data->value.size_ratio.consequent)
{
gdouble value;
value = 100.0 * variable_data->value.size_ratio.antecedent /
variable_data->value.size_ratio.consequent;
str = g_strdup_printf ("%d%%", SIGNED_ROUND (value));
static_str = FALSE;
}
}
break;
case VARIABLE_TYPE_INT_RATIO:
{
gdouble min;
gdouble max;
gdouble antecedent;
gdouble consequent;
antecedent = variable_data->value.int_ratio.antecedent;
consequent = variable_data->value.int_ratio.consequent;
min = MIN (ABS (antecedent), ABS (consequent));
max = MAX (ABS (antecedent), ABS (consequent));
if (min)
{
antecedent /= min;
consequent /= min;
}
else if (max)
{
antecedent /= max;
consequent /= max;
}
if (max)
{
str = g_strdup_printf ("%g:%g",
RINT (100.0 * antecedent) / 100.0,
RINT (100.0 * consequent) / 100.0);
static_str = FALSE;
}
}
break;
case VARIABLE_TYPE_PERCENTAGE:
str = g_strdup_printf ("%d%%",
SIGNED_ROUND (100.0 * variable_data->value.percentage));
static_str = FALSE;
show_limit = FALSE;
break;
case VARIABLE_TYPE_DURATION:
str = g_strdup_printf ("%02d:%02d:%04.1f",
(gint) floor (variable_data->value.duration / 3600.0),
(gint) floor (fmod (variable_data->value.duration / 60.0, 60.0)),
floor (fmod (variable_data->value.duration, 60.0) * 10.0) / 10.0);
static_str = FALSE;
show_limit = FALSE;
break;
case VARIABLE_TYPE_RATE_OF_CHANGE:
/* Translators: This string reports the rate of change of a measured
* value. The "%g" is replaced by a certain quantity, and the "/s"
* is an abbreviation for "per second".
*/
str = g_strdup_printf (_("%g/s"),
variable_data->value.rate_of_change);
static_str = FALSE;
break;
}
if (show_limit &&
variable_data->available &&
field_info->meter_value &&
! field_info->meter_variable &&
group_data->limit)
{
gdouble value;
gchar *tmp;
value = gimp_dashboard_variable_to_double (dashboard,
field_info->variable);
if (full)
{
tmp = g_strdup_printf ("%s (%d%%)",
str,
SIGNED_ROUND (100.0 * value /
group_data->limit));
}
else
{
tmp = g_strdup_printf ("%d%%",
SIGNED_ROUND (100.0 * value /
group_data->limit));
}
if (! static_str)
g_free ((gpointer) str);
str = tmp;
static_str = FALSE;
}
else if (full &&
field_info->meter_variable &&
variables[field_info->meter_variable].type ==
VARIABLE_TYPE_RATE_OF_CHANGE &&
priv->variables[field_info->meter_variable].available)
{
gdouble value;
gchar *value_str;
gchar *rate_of_change_str;
gchar *tmp;
value = gimp_dashboard_variable_to_double (dashboard,
field_info->meter_variable);
value_str = gimp_dashboard_format_value (variable_info->type, value);
rate_of_change_str = gimp_dashboard_format_rate_of_change (value_str);
g_free (value_str);
tmp = g_strdup_printf ("%s (%s)", str, rate_of_change_str);
g_free (rate_of_change_str);
if (! static_str)
g_free ((gpointer) str);
str = tmp;
static_str = FALSE;
}
}
if (static_str)
return g_strdup (str);
else
return (gpointer) str;
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
static gboolean
gimp_dashboard_log_printf (GimpDashboard *dashboard,
const gchar *format,
...)
{
GimpDashboardPrivate *priv = dashboard->priv;
va_list args;
gboolean result;
if (priv->log_error)
return FALSE;
va_start (args, format);
result = g_output_stream_vprintf (priv->log_output,
NULL, NULL,
&priv->log_error,
format, args);
va_end (args);
return result;
}
static gboolean
gimp_dashboard_log_print_escaped (GimpDashboard *dashboard,
const gchar *string)
{
GimpDashboardPrivate *priv = dashboard->priv;
gchar buffer[1024];
const gchar *s;
gint i;
if (priv->log_error)
return FALSE;
i = 0;
#define FLUSH() \
G_STMT_START \
{ \
if (! g_output_stream_write_all (priv->log_output, \
buffer, i, NULL, \
NULL, &priv->log_error)) \
{ \
return FALSE; \
} \
\
i = 0; \
} \
G_STMT_END
#define RESERVE(n) \
G_STMT_START \
{ \
if (i + (n) > sizeof (buffer)) \
FLUSH (); \
} \
G_STMT_END
for (s = string; *s; s++)
{
#define ESCAPE(from, to) \
case from: \
RESERVE (sizeof (to) - 1); \
memcpy (&buffer[i], to, sizeof (to) - 1); \
i += sizeof (to) - 1; \
break;
switch (*s)
{
ESCAPE ('"', "&quot;")
ESCAPE ('\'', "&apos;")
ESCAPE ('<', "&lt;")
ESCAPE ('>', "&gt;")
ESCAPE ('&', "&amp;")
default:
RESERVE (1);
buffer[i++] = *s;
break;
}
#undef ESCAPE
}
FLUSH ();
#undef FLUSH
#undef RESERVE
return TRUE;
}
static gint64
gimp_dashboard_log_time (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv = dashboard->priv;
return g_get_monotonic_time () - priv->log_start_time;
}
static void
gimp_dashboard_log_sample (GimpDashboard *dashboard,
gboolean variables_changed)
{
GimpDashboardPrivate *priv = dashboard->priv;
GimpBacktrace *backtrace = NULL;
gboolean empty = TRUE;
Variable variable;
#define NONEMPTY() \
G_STMT_START \
{ \
if (empty) \
{ \
gimp_dashboard_log_printf (dashboard, \
">\n"); \
\
empty = FALSE; \
} \
} \
G_STMT_END
gimp_dashboard_log_printf (dashboard,
"\n"
"<sample id=\"%d\" t=\"%lld\"",
priv->log_n_samples,
(long long) gimp_dashboard_log_time (dashboard));
if (priv->log_n_samples == 0 || variables_changed)
{
NONEMPTY ();
gimp_dashboard_log_printf (dashboard,
"<vars>\n");
for (variable = FIRST_VARIABLE; variable < N_VARIABLES; variable++)
{
const VariableInfo *variable_info = &variables[variable];
const VariableData *variable_data = &priv->variables[variable];
VariableData *log_variable_data = &priv->log_variables[variable];
if (variable_info->exclude_from_log)
continue;
if (priv->log_n_samples > 0 &&
! memcmp (variable_data, log_variable_data,
sizeof (VariableData)))
{
continue;
}
*log_variable_data = *variable_data;
if (variable_data->available)
{
#define LOG_VAR(format, ...) \
gimp_dashboard_log_printf (dashboard, \
"<%s>" format "</%s>\n", \
variable_info->name, \
__VA_ARGS__, \
variable_info->name)
switch (variable_info->type)
{
case VARIABLE_TYPE_BOOLEAN:
LOG_VAR (
"%d",
variable_data->value.boolean);
break;
case VARIABLE_TYPE_INTEGER:
LOG_VAR (
"%d",
variable_data->value.integer);
break;
case VARIABLE_TYPE_SIZE:
LOG_VAR (
"%llu",
(unsigned long long) variable_data->value.size);
break;
case VARIABLE_TYPE_SIZE_RATIO:
LOG_VAR (
"%llu/%llu",
(unsigned long long) variable_data->value.size_ratio.antecedent,
(unsigned long long) variable_data->value.size_ratio.consequent);
break;
case VARIABLE_TYPE_INT_RATIO:
LOG_VAR (
"%d:%d",
variable_data->value.int_ratio.antecedent,
variable_data->value.int_ratio.consequent);
break;
case VARIABLE_TYPE_PERCENTAGE:
LOG_VAR (
"%.16g",
variable_data->value.percentage);
break;
case VARIABLE_TYPE_DURATION:
LOG_VAR (
"%.16g",
variable_data->value.duration);
break;
case VARIABLE_TYPE_RATE_OF_CHANGE:
LOG_VAR (
"%.16g",
variable_data->value.rate_of_change);
break;
}
#undef LOG_VAR
}
else
{
gimp_dashboard_log_printf (dashboard,
"<%s />\n",
variable_info->name);
}
}
gimp_dashboard_log_printf (dashboard,
"</vars>\n");
}
if (priv->log_include_backtrace)
backtrace = gimp_backtrace_new (FALSE);
if (backtrace)
{
gboolean backtrace_empty = TRUE;
gint n_threads;
gint thread;
#define BACKTRACE_NONEMPTY() \
G_STMT_START \
{ \
if (backtrace_empty) \
{ \
NONEMPTY (); \
\
gimp_dashboard_log_printf (dashboard, \
"<backtrace>\n"); \
\
backtrace_empty = FALSE; \
} \
} \
G_STMT_END
if (priv->log_backtrace)
{
n_threads = gimp_backtrace_get_n_threads (priv->log_backtrace);
for (thread = 0; thread < n_threads; thread++)
{
guintptr thread_id;
thread_id = gimp_backtrace_get_thread_id (priv->log_backtrace,
thread);
if (gimp_backtrace_find_thread_by_id (backtrace,
thread_id, thread) < 0)
{
const gchar *thread_name;
BACKTRACE_NONEMPTY ();
thread_name =
gimp_backtrace_get_thread_name (priv->log_backtrace,
thread);
gimp_dashboard_log_printf (dashboard,
"<thread id=\"%llu\"",
(unsigned long long) thread_id);
if (thread_name)
{
gimp_dashboard_log_printf (dashboard,
" name=\"");
gimp_dashboard_log_print_escaped (dashboard, thread_name);
gimp_dashboard_log_printf (dashboard,
"\"");
}
gimp_dashboard_log_printf (dashboard,
" />\n");
}
}
}
n_threads = gimp_backtrace_get_n_threads (backtrace);
for (thread = 0; thread < n_threads; thread++)
{
guintptr thread_id;
const gchar *thread_name;
gint last_running = -1;
gint running;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gint n_frames;
gint n_head = 0;
gint n_tail = 0;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gint frame;
thread_id = gimp_backtrace_get_thread_id (backtrace, thread);
thread_name = gimp_backtrace_get_thread_name (backtrace, thread);
n_frames = gimp_backtrace_get_n_frames (backtrace, thread);
if (priv->log_backtrace)
{
gint other_thread = gimp_backtrace_find_thread_by_id (
priv->log_backtrace, thread_id, thread);
if (other_thread >= 0)
{
gint n;
gint i;
last_running = gimp_backtrace_is_thread_running (
priv->log_backtrace, other_thread);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
n = gimp_backtrace_get_n_frames (priv->log_backtrace,
other_thread);
n = MIN (n, n_frames);
for (i = 0; i < n; i++)
{
if (gimp_backtrace_get_frame_address (backtrace,
thread, i) !=
gimp_backtrace_get_frame_address (priv->log_backtrace,
other_thread, i))
{
break;
}
}
n_head = i;
n -= i;
for (i = 0; i < n; i++)
{
if (gimp_backtrace_get_frame_address (backtrace,
thread, -i - 1) !=
gimp_backtrace_get_frame_address (priv->log_backtrace,
other_thread, -i - 1))
{
break;
}
}
n_tail = i;
}
}
running = gimp_backtrace_is_thread_running (backtrace, thread);
if (running == last_running && n_head + n_tail == n_frames)
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
continue;
BACKTRACE_NONEMPTY ();
gimp_dashboard_log_printf (dashboard,
"<thread id=\"%llu\"",
(unsigned long long) thread_id);
if (thread_name)
{
gimp_dashboard_log_printf (dashboard,
" name=\"");
gimp_dashboard_log_print_escaped (dashboard, thread_name);
gimp_dashboard_log_printf (dashboard,
"\"");
}
gimp_dashboard_log_printf (dashboard,
" running=\"%d\"",
running);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (n_head > 0)
{
gimp_dashboard_log_printf (dashboard,
" head=\"%d\"",
n_head);
}
if (n_tail > 0)
{
gimp_dashboard_log_printf (dashboard,
" tail=\"%d\"",
n_tail);
}
if (n_head + n_tail < n_frames)
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
{
gimp_dashboard_log_printf (dashboard,
">\n");
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
for (frame = n_head; frame < n_frames - n_tail; frame++)
{
unsigned long long address;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
address = gimp_backtrace_get_frame_address (backtrace,
thread, frame);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gimp_dashboard_log_printf (dashboard,
"<frame address=\"0x%llx\" />\n",
address);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
g_hash_table_add (priv->log_addresses, (gpointer) address);
}
gimp_dashboard_log_printf (dashboard,
"</thread>\n");
}
else
{
gimp_dashboard_log_printf (dashboard,
" />\n");
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
}
if (! backtrace_empty)
{
gimp_dashboard_log_printf (dashboard,
"</backtrace>\n");
}
#undef BACKTRACE_NONEMPTY
}
else if (priv->log_backtrace)
{
NONEMPTY ();
gimp_dashboard_log_printf (dashboard,
"<backtrace />\n");
}
gimp_backtrace_free (priv->log_backtrace);
priv->log_backtrace = backtrace;
if (empty)
{
gimp_dashboard_log_printf (dashboard,
" />\n");
}
else
{
gimp_dashboard_log_printf (dashboard,
"</sample>\n");
}
#undef NONEMPTY
priv->log_n_samples++;
}
static void
gimp_dashboard_log_update_highlight (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv = dashboard->priv;
GtkReliefStyle default_relief;
gtk_widget_style_get (GTK_WIDGET (dashboard),
"button-relief", &default_relief,
NULL);
gimp_button_set_suggested (priv->log_record_button,
gimp_dashboard_log_is_recording (dashboard),
default_relief);
}
static void
gimp_dashboard_log_update_n_markers (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv = dashboard->priv;
gchar buffer[32];
g_snprintf (buffer, sizeof (buffer), "%d", priv->log_n_markers + 1);
gtk_label_set_text (priv->log_add_marker_label, buffer);
}
static gint
gimp_dashboard_log_compare_addresses (gconstpointer a1,
gconstpointer a2)
{
guintptr address1 = *(const guintptr *) a1;
guintptr address2 = *(const guintptr *) a2;
if (address1 < address2)
return -1;
else if (address1 > address2)
return +1;
else
return 0;
}
static void
gimp_dashboard_log_write_address_map (GimpAsync *async,
GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv = dashboard->priv;
GimpBacktraceAddressInfo infos[2];
guintptr *addresses;
gint n_addresses;
GList *iter;
gint i;
gint n;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
n_addresses = g_hash_table_size (priv->log_addresses);
if (n_addresses == 0)
{
gimp_async_finish (async, NULL);
return;
}
addresses = g_new (guintptr, n_addresses);
for (iter = g_hash_table_get_keys (priv->log_addresses), i = 0;
iter;
iter = g_list_next (iter), i++)
{
addresses[i] = (guintptr) iter->data;
}
qsort (addresses, n_addresses, sizeof (guintptr),
gimp_dashboard_log_compare_addresses);
gimp_dashboard_log_printf (dashboard,
"\n"
"<address-map>\n");
n = 0;
for (i = 0; i < n_addresses; i++)
{
GimpBacktraceAddressInfo *info = &infos[n % 2];
const GimpBacktraceAddressInfo *prev_info = &infos[(n + 1) % 2];
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (gimp_async_is_canceled (async))
break;
if (gimp_backtrace_get_address_info (addresses[i], info))
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
{
gboolean empty = TRUE;
#define NONEMPTY() \
G_STMT_START \
{ \
if (empty) \
{ \
gimp_dashboard_log_printf (dashboard, \
">\n"); \
\
empty = FALSE; \
} \
} \
G_STMT_END
gimp_dashboard_log_printf (dashboard,
"\n"
"<address value=\"0x%llx\"",
(unsigned long long) addresses[i]);
if (n == 0 || strcmp (info->object_name, prev_info->object_name))
{
NONEMPTY ();
if (info->object_name[0])
{
gimp_dashboard_log_printf (dashboard,
"<object>");
gimp_dashboard_log_print_escaped (dashboard,
info->object_name);
gimp_dashboard_log_printf (dashboard,
"</object>\n");
}
else
{
gimp_dashboard_log_printf (dashboard,
"<object />\n");
}
}
if (n == 0 || strcmp (info->symbol_name, prev_info->symbol_name))
{
NONEMPTY ();
if (info->symbol_name[0])
{
gimp_dashboard_log_printf (dashboard,
"<symbol>");
gimp_dashboard_log_print_escaped (dashboard,
info->symbol_name);
gimp_dashboard_log_printf (dashboard,
"</symbol>\n");
}
else
{
gimp_dashboard_log_printf (dashboard,
"<symbol />\n");
}
}
if (n == 0 || info->symbol_address != prev_info->symbol_address)
{
NONEMPTY ();
if (info->symbol_address)
{
gimp_dashboard_log_printf (dashboard,
"<base>0x%llx</base>\n",
(unsigned long long)
info->symbol_address);
}
else
{
gimp_dashboard_log_printf (dashboard,
"<base />\n");
}
}
if (n == 0 || strcmp (info->source_file, prev_info->source_file))
{
NONEMPTY ();
if (info->source_file[0])
{
gimp_dashboard_log_printf (dashboard,
"<source>");
gimp_dashboard_log_print_escaped (dashboard,
info->source_file);
gimp_dashboard_log_printf (dashboard,
"</source>\n");
}
else
{
gimp_dashboard_log_printf (dashboard,
"<source />\n");
}
}
if (n == 0 || info->source_line != prev_info->source_line)
{
NONEMPTY ();
if (info->source_line)
{
gimp_dashboard_log_printf (dashboard,
"<line>%d</line>\n",
info->source_line);
}
else
{
gimp_dashboard_log_printf (dashboard,
"<line />\n");
}
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (empty)
{
gimp_dashboard_log_printf (dashboard,
" />\n");
}
else
{
gimp_dashboard_log_printf (dashboard,
"</address>\n");
}
#undef NONEMPTY
n++;
}
}
g_free (addresses);
gimp_dashboard_log_printf (dashboard,
"\n"
"</address-map>\n");
gimp_async_finish (async, NULL);
}
static gboolean
gimp_dashboard_field_use_meter_underlay (Group group,
gint field)
{
const GroupInfo *group_info = &groups[group];
Variable variable = group_info->fields[field].variable;
const VariableInfo *variable_info;
if (group_info->fields[field].meter_variable)
variable = group_info->fields[field].meter_variable;
variable_info = &variables [variable];
return variable_info->type == VARIABLE_TYPE_BOOLEAN ||
(group_info->fields[field].meter_variable &&
variable_info->type == VARIABLE_TYPE_RATE_OF_CHANGE);
}
static gchar *
gimp_dashboard_format_rate_of_change (const gchar *value)
{
/* Translators: This string reports the rate of change of a measured value.
* The first "%s" is replaced by a certain quantity, usually followed by a
* unit of measurement (e.g., "10 bytes"). and the final "/s" is an
* abbreviation for "per second" (so the full string would read
* "10 bytes/s", that is, "10 bytes per second".
*/
return g_strdup_printf (_("%s/s"), value);
}
static gchar *
gimp_dashboard_format_value (VariableType type,
gdouble value)
{
switch (type)
{
case VARIABLE_TYPE_BOOLEAN:
return g_strdup (value ? C_("dashboard-value", "Yes") :
C_("dashboard-value", "No"));
case VARIABLE_TYPE_INTEGER:
return g_strdup_printf ("%g", value);
case VARIABLE_TYPE_SIZE:
return g_format_size_full (value, G_FORMAT_SIZE_IEC_UNITS);
case VARIABLE_TYPE_SIZE_RATIO:
if (isfinite (value))
return g_strdup_printf ("%d%%", SIGNED_ROUND (100.0 * value));
break;
case VARIABLE_TYPE_INT_RATIO:
if (isfinite (value))
{
gdouble min;
gdouble max;
gdouble antecedent;
gdouble consequent;
antecedent = value;
consequent = 1.0;
min = MIN (ABS (antecedent), ABS (consequent));
max = MAX (ABS (antecedent), ABS (consequent));
if (min)
{
antecedent /= min;
consequent /= min;
}
else
{
antecedent /= max;
consequent /= max;
}
return g_strdup_printf ("%g:%g",
RINT (100.0 * antecedent) / 100.0,
RINT (100.0 * consequent) / 100.0);
}
else if (isinf (value))
{
return g_strdup ("1:0");
}
break;
case VARIABLE_TYPE_PERCENTAGE:
return g_strdup_printf ("%d%%", SIGNED_ROUND (100.0 * value));
case VARIABLE_TYPE_DURATION:
return g_strdup_printf ("%02d:%02d:%04.1f",
(gint) floor (value / 3600.0),
(gint) floor (fmod (value / 60.0, 60.0)),
floor (fmod (value, 60.0) * 10.0) / 10.0);
case VARIABLE_TYPE_RATE_OF_CHANGE:
{
gchar buf[64];
g_snprintf (buf, sizeof (buf), "%g", value);
return gimp_dashboard_format_rate_of_change (buf);
}
}
return g_strdup (_("N/A"));
}
static void
gimp_dashboard_label_set_text (GtkLabel *label,
const gchar *text)
{
/* the strcmp() reduces the overhead of gtk_label_set_text() when the
* text hasn't changed
*/
if (g_strcmp0 (gtk_label_get_text (label), text))
gtk_label_set_text (label, text);
}
/* public functions */
GtkWidget *
gimp_dashboard_new (Gimp *gimp,
GimpMenuFactory *menu_factory)
{
GimpDashboard *dashboard;
dashboard = g_object_new (GIMP_TYPE_DASHBOARD,
"menu-factory", menu_factory,
"menu-identifier", "<Dashboard>",
"ui-path", "/dashboard-popup",
NULL);
dashboard->priv->gimp = gimp;
return GTK_WIDGET (dashboard);
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gboolean
gimp_dashboard_log_start_recording (GimpDashboard *dashboard,
GFile *file,
GError **error)
{
GimpDashboardPrivate *priv;
GimpUIManager *ui_manager;
GimpActionGroup *action_group;
gchar *version;
gchar **envp;
gchar **env;
GParamSpec **pspecs;
guint n_pspecs;
gboolean has_backtrace;
Variable variable;
guint i;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
g_return_val_if_fail (GIMP_IS_DASHBOARD (dashboard), FALSE);
g_return_val_if_fail (G_IS_FILE (file), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
priv = dashboard->priv;
g_return_val_if_fail (! gimp_dashboard_log_is_recording (dashboard), FALSE);
g_mutex_lock (&priv->mutex);
priv->log_output = G_OUTPUT_STREAM (g_file_replace (file,
NULL, FALSE, G_FILE_CREATE_NONE, NULL,
error));
if (! priv->log_output)
{
g_mutex_unlock (&priv->mutex);
return FALSE;
}
priv->log_error = NULL;
priv->log_start_time = g_get_monotonic_time ();
priv->log_sample_frequency = LOG_SAMPLE_FREQUENCY;
priv->log_n_samples = 0;
priv->log_n_markers = 0;
priv->log_include_backtrace = TRUE;
priv->log_backtrace = NULL;
priv->log_addresses = g_hash_table_new (NULL, NULL);
if (g_getenv ("GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY"))
{
priv->log_sample_frequency =
atoi (g_getenv ("GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY"));
priv->log_sample_frequency = CLAMP (priv->log_sample_frequency,
1, 1000);
}
if (g_getenv ("GIMP_PERFORMANCE_LOG_NO_BACKTRACE"))
priv->log_include_backtrace = FALSE;
if (priv->log_include_backtrace)
has_backtrace = gimp_backtrace_start ();
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
else
has_backtrace = FALSE;
gimp_dashboard_log_printf (dashboard,
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<gimp-performance-log version=\"%d\">\n",
LOG_VERSION);
gimp_dashboard_log_printf (dashboard,
"\n"
"<params>\n"
"<sample-frequency>%d</sample-frequency>\n"
"<backtrace>%d</backtrace>\n"
"</params>\n",
priv->log_sample_frequency,
has_backtrace);
gimp_dashboard_log_printf (dashboard,
"\n"
"<info>\n");
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
version = gimp_version (TRUE, FALSE);
gimp_dashboard_log_printf (dashboard,
"\n"
"<gimp-version>\n");
gimp_dashboard_log_print_escaped (dashboard, version);
gimp_dashboard_log_printf (dashboard,
"</gimp-version>\n");
g_free (version);
gimp_dashboard_log_printf (dashboard,
"\n"
"<env>\n");
envp = g_get_environ ();
for (env = envp; *env; env++)
{
if (g_str_has_prefix (*env, "BABL_") ||
g_str_has_prefix (*env, "GEGL_") ||
g_str_has_prefix (*env, "GIMP_"))
{
gchar *delim = strchr (*env, '=');
const gchar *s;
if (! delim)
continue;
for (s = *env;
s != delim && (g_ascii_isalnum (*s) || *s == '_' || *s == '-');
s++);
if (s != delim)
continue;
*delim = '\0';
gimp_dashboard_log_printf (dashboard,
"<%s>",
*env);
gimp_dashboard_log_print_escaped (dashboard, delim + 1);
gimp_dashboard_log_printf (dashboard,
"</%s>\n",
*env);
}
}
g_strfreev (envp);
gimp_dashboard_log_printf (dashboard,
"</env>\n");
gimp_dashboard_log_printf (dashboard,
"\n"
"<gegl-config>\n");
pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (gegl_config ()),
&n_pspecs);
for (i = 0; i < n_pspecs; i++)
{
const GParamSpec *pspec = pspecs[i];
GValue value = {};
GValue str_value = {};
g_value_init (&value, pspec->value_type);
g_value_init (&str_value, G_TYPE_STRING);
g_object_get_property (G_OBJECT (gegl_config ()), pspec->name, &value);
if (g_value_transform (&value, &str_value))
{
gimp_dashboard_log_printf (dashboard,
"<%s>",
pspec->name);
gimp_dashboard_log_print_escaped (dashboard,
g_value_get_string (&str_value));
gimp_dashboard_log_printf (dashboard,
"</%s>\n",
pspec->name);
}
g_value_unset (&str_value);
g_value_unset (&value);
}
g_free (pspecs);
gimp_dashboard_log_printf (dashboard,
"</gegl-config>\n");
gimp_dashboard_log_printf (dashboard,
"\n"
"</info>\n");
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gimp_dashboard_log_printf (dashboard,
"\n"
"<var-defs>\n");
for (variable = FIRST_VARIABLE; variable < N_VARIABLES; variable++)
{
const VariableInfo *variable_info = &variables[variable];
const gchar *type = "";
if (variable_info->exclude_from_log)
continue;
switch (variable_info->type)
{
case VARIABLE_TYPE_BOOLEAN: type = "boolean"; break;
case VARIABLE_TYPE_INTEGER: type = "integer"; break;
case VARIABLE_TYPE_SIZE: type = "size"; break;
case VARIABLE_TYPE_SIZE_RATIO: type = "size-ratio"; break;
case VARIABLE_TYPE_INT_RATIO: type = "int-ratio"; break;
case VARIABLE_TYPE_PERCENTAGE: type = "percentage"; break;
case VARIABLE_TYPE_DURATION: type = "duration"; break;
case VARIABLE_TYPE_RATE_OF_CHANGE: type = "rate-of-change"; break;
}
gimp_dashboard_log_printf (dashboard,
"<var name=\"%s\" type=\"%s\" />\n",
variable_info->name,
type);
}
gimp_dashboard_log_printf (dashboard,
"</var-defs>\n");
gimp_dashboard_log_printf (dashboard,
"\n"
"<samples>\n");
if (priv->log_error)
{
gimp_backtrace_stop ();
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
g_clear_object (&priv->log_output);
g_propagate_error (error, priv->log_error);
priv->log_error = NULL;
g_mutex_unlock (&priv->mutex);
return FALSE;
}
gimp_dashboard_reset_unlocked (dashboard);
priv->update_now = TRUE;
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->mutex);
gimp_dashboard_log_update_n_markers (dashboard);
ui_manager = gimp_editor_get_ui_manager (GIMP_EDITOR (dashboard));
action_group = gimp_ui_manager_get_action_group (ui_manager, "dashboard");
gimp_action_group_update (action_group, dashboard);
gimp_dashboard_log_update_highlight (dashboard);
return TRUE;
}
gboolean
gimp_dashboard_log_stop_recording (GimpDashboard *dashboard,
GError **error)
{
GimpDashboardPrivate *priv;
GimpUIManager *ui_manager;
GimpActionGroup *action_group;
gboolean result = TRUE;
g_return_val_if_fail (GIMP_IS_DASHBOARD (dashboard), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
priv = dashboard->priv;
if (! gimp_dashboard_log_is_recording (dashboard))
return TRUE;
g_mutex_lock (&priv->mutex);
gimp_dashboard_log_printf (dashboard,
"\n"
"</samples>\n");
if (g_hash_table_size (priv->log_addresses) > 0)
{
GimpAsync *async;
async = gimp_parallel_run_async_full (
-1,
(GimpParallelRunAsyncFunc) gimp_dashboard_log_write_address_map,
dashboard, NULL);
gimp_wait (priv->gimp, GIMP_WAITABLE (async),
_("Resolving symbol information..."));
g_object_unref (async);
}
gimp_dashboard_log_printf (dashboard,
"\n"
"</gimp-performance-log>\n");
if (priv->log_include_backtrace)
gimp_backtrace_stop ();
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (! priv->log_error)
g_output_stream_close (priv->log_output, NULL, &priv->log_error);
g_clear_object (&priv->log_output);
if (priv->log_error)
{
g_propagate_error (error, priv->log_error);
priv->log_error = NULL;
result = FALSE;
}
g_clear_pointer (&priv->log_backtrace, gimp_backtrace_free);
g_clear_pointer (&priv->log_addresses, g_hash_table_unref);
g_mutex_unlock (&priv->mutex);
ui_manager = gimp_editor_get_ui_manager (GIMP_EDITOR (dashboard));
action_group = gimp_ui_manager_get_action_group (ui_manager, "dashboard");
gimp_action_group_update (action_group, dashboard);
gimp_dashboard_log_update_highlight (dashboard);
return result;
}
gboolean
gimp_dashboard_log_is_recording (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv;
g_return_val_if_fail (GIMP_IS_DASHBOARD (dashboard), FALSE);
priv = dashboard->priv;
return priv->log_output != NULL;
}
void
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gimp_dashboard_log_add_marker (GimpDashboard *dashboard,
const gchar *description)
{
GimpDashboardPrivate *priv;
g_return_if_fail (GIMP_IS_DASHBOARD (dashboard));
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
g_return_if_fail (gimp_dashboard_log_is_recording (dashboard));
priv = dashboard->priv;
g_mutex_lock (&priv->mutex);
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
priv->log_n_markers++;
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gimp_dashboard_log_printf (dashboard,
"\n"
"<marker id=\"%d\" t=\"%lld\"",
priv->log_n_markers,
(long long) gimp_dashboard_log_time (dashboard));
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
if (description && description[0])
{
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
gimp_dashboard_log_printf (dashboard,
">\n");
gimp_dashboard_log_print_escaped (dashboard, description);
gimp_dashboard_log_printf (dashboard,
"\n"
"</marker>\n");
}
else
{
gimp_dashboard_log_printf (dashboard,
" />\n");
}
app, icons, menus: add performance-log recording to the dashboard Add an option to record a performance log through the dashboard. The log contains a series of samples of the dashboard variables, as well as the full program backtrace, when available. As such, it essentially acts as a built-in profiler, which allows us to correlate program execution with the information available through the dashboard. It is meant to be used for creating logs to accompany perofrmance-related bug reports, as well as for profiling GIMP during development. The sample frequency defaults to 10 samples per second, but can be overridden using the GIMP_PERFORMANCE_LOG_SAMPLE_FREQUENCY environment variable. Backtraces are included by default when available, but can be suppressed using the GIMP_PERFORMANCE_LOG_NO_BACKTRACE environment variable. Logs are created through the new "record" button at the bottom of the dashboard dialog. When pressed, a file dialog is opened to select the log file, and, once confirmed, data is being recorded to the selected file. Recording is stopped by pressing the "record" button again (we use a highlight to indicate that recording is active.) While recording, the "reset" button is replaced with an "add marker" button, which can be used to add event markers to the log. These can be used to mark events of interest, such as "started painting" and "stopped painting", which then appear in the log as part of the sample stream. Markers are numbered sequentually, and the number of the next (to-be-added) marker appears on the button. Shift- clicking the button adds an empty (description-less) marker, which is only identified by its number; this can be used when markers need to be added quickly. The log is an XML file, containing some extra information (such as the output of "$ gimp -v", and symbol information) in addition to the samples. The data in the file is delta-encoded to reduce the file size, meaning that samples (as well as some other elements) only specify the changes since the previous sample. This adds a necessary decoding step before data can be processed; the next commit adds a tool that does that. There are currently no tools to actually analyze the data -- that's still TBD -- but at least we can start gathering it.
2018-09-02 01:46:27 -04:00
g_mutex_unlock (&priv->mutex);
gimp_dashboard_log_update_n_markers (dashboard);
}
void
gimp_dashboard_reset (GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv;
g_return_if_fail (GIMP_IS_DASHBOARD (dashboard));
priv = dashboard->priv;
g_mutex_lock (&priv->mutex);
gimp_dashboard_reset_unlocked (dashboard);
priv->update_now = TRUE;
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->mutex);
}
void
gimp_dashboard_set_update_interval (GimpDashboard *dashboard,
GimpDashboardUpdateInteval update_interval)
{
GimpDashboardPrivate *priv;
g_return_if_fail (GIMP_IS_DASHBOARD (dashboard));
priv = dashboard->priv;
if (update_interval != priv->update_interval)
{
Group group;
g_mutex_lock (&priv->mutex);
priv->update_interval = update_interval;
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
GroupData *group_data = &priv->groups[group];
if (group_data->meter)
{
gimp_meter_set_history_resolution (group_data->meter,
update_interval / 1000.0);
}
}
priv->update_now = TRUE;
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->mutex);
}
}
GimpDashboardUpdateInteval
gimp_dashboard_get_update_interval (GimpDashboard *dashboard)
{
g_return_val_if_fail (GIMP_IS_DASHBOARD (dashboard), DEFAULT_UPDATE_INTERVAL);
return dashboard->priv->update_interval;
}
void
gimp_dashboard_set_history_duration (GimpDashboard *dashboard,
GimpDashboardHistoryDuration history_duration)
{
GimpDashboardPrivate *priv;
g_return_if_fail (GIMP_IS_DASHBOARD (dashboard));
priv = dashboard->priv;
if (history_duration != priv->history_duration)
{
Group group;
g_mutex_lock (&priv->mutex);
priv->history_duration = history_duration;
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
GroupData *group_data = &priv->groups[group];
if (group_data->meter)
{
gimp_meter_set_history_duration (group_data->meter,
history_duration / 1000.0);
}
}
priv->update_now = TRUE;
g_cond_signal (&priv->cond);
g_mutex_unlock (&priv->mutex);
}
}
GimpDashboardHistoryDuration
gimp_dashboard_get_history_duration (GimpDashboard *dashboard)
{
g_return_val_if_fail (GIMP_IS_DASHBOARD (dashboard), DEFAULT_HISTORY_DURATION);
return dashboard->priv->history_duration;
}
void
gimp_dashboard_set_low_swap_space_warning (GimpDashboard *dashboard,
gboolean low_swap_space_warning)
{
GimpDashboardPrivate *priv;
g_return_if_fail (GIMP_IS_DASHBOARD (dashboard));
priv = dashboard->priv;
if (low_swap_space_warning != priv->low_swap_space_warning)
{
g_mutex_lock (&priv->mutex);
priv->low_swap_space_warning = low_swap_space_warning;
g_mutex_unlock (&priv->mutex);
}
}
gboolean
gimp_dashboard_get_low_swap_space_warning (GimpDashboard *dashboard)
{
g_return_val_if_fail (GIMP_IS_DASHBOARD (dashboard), DEFAULT_LOW_SWAP_SPACE_WARNING);
return dashboard->priv->low_swap_space_warning;
}
void
gimp_dashboard_menu_setup (GimpUIManager *manager,
const gchar *ui_path)
{
guint merge_id;
Group group;
g_return_if_fail (GIMP_IS_UI_MANAGER (manager));
g_return_if_fail (ui_path != NULL);
merge_id = gtk_ui_manager_new_merge_id (GTK_UI_MANAGER (manager));
for (group = FIRST_GROUP; group < N_GROUPS; group++)
{
const GroupInfo *group_info = &groups[group];
gchar *action_name;
gchar *action_path;
action_name = g_strdup_printf ("dashboard-group-%s", group_info->name);
action_path = g_strdup_printf ("%s/Groups/Groups", ui_path);
gtk_ui_manager_add_ui (GTK_UI_MANAGER (manager), merge_id,
action_path, action_name, action_name,
GTK_UI_MANAGER_MENUITEM,
FALSE);
g_free (action_name);
g_free (action_path);
}
}