2017-12-18 18:54:17 -05:00
|
|
|
/* 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
|
2018-07-11 23:27:07 +02:00
|
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
2017-12-18 18:54:17 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2018-06-21 03:54:00 -04:00
|
|
|
#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>
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
#include <gegl.h>
|
|
|
|
#include <gio/gio.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
2018-06-19 12:34:42 -04:00
|
|
|
#ifdef G_OS_WIN32
|
|
|
|
#include <windows.h>
|
2018-06-28 10:17:36 -04:00
|
|
|
#include <psapi.h>
|
2018-06-19 12:34:42 -04:00
|
|
|
#define HAVE_CPU_GROUP
|
|
|
|
#define HAVE_MEMORY_GROUP
|
|
|
|
#else /* ! G_OS_WIN32 */
|
2018-01-19 09:03:44 -05:00
|
|
|
#ifdef HAVE_SYS_TIMES_H
|
|
|
|
#include <sys/times.h>
|
|
|
|
#define HAVE_CPU_GROUP
|
2018-06-19 12:34:42 -04:00
|
|
|
#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 */
|
2018-01-19 09:03:44 -05:00
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
#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"
|
2018-06-19 12:34:42 -04:00
|
|
|
#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"
|
2018-07-01 13:22:51 -04:00
|
|
|
#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"
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
#include "gimpactiongroup.h"
|
2017-12-18 18:54:17 -05:00
|
|
|
#include "gimpdocked.h"
|
|
|
|
#include "gimpdashboard.h"
|
|
|
|
#include "gimpdialogfactory.h"
|
2017-12-30 13:43:09 -05:00
|
|
|
#include "gimphelp-ids.h"
|
2017-12-18 18:54:17 -05:00
|
|
|
#include "gimpmeter.h"
|
|
|
|
#include "gimpsessioninfo-aux.h"
|
2018-04-02 16:24:09 -04:00
|
|
|
#include "gimpuimanager.h"
|
2018-08-30 23:40:15 -04:00
|
|
|
#include "gimpwidgets-utils.h"
|
2017-12-18 18:54:17 -05:00
|
|
|
#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"
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
2017-12-19 02:40:39 -05:00
|
|
|
#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 */
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
#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 */
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
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,
|
|
|
|
|
2018-08-17 20:54:42 -04:00
|
|
|
VARIABLE_SWAP_QUEUED,
|
|
|
|
VARIABLE_SWAP_QUEUE_STALLS,
|
|
|
|
VARIABLE_SWAP_QUEUE_FULL,
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
VARIABLE_SWAP_READ,
|
2018-08-17 22:32:13 -04:00
|
|
|
VARIABLE_SWAP_READ_THROUGHPUT,
|
2018-06-21 03:54:00 -04:00
|
|
|
VARIABLE_SWAP_WRITTEN,
|
2018-08-17 22:32:13 -04:00
|
|
|
VARIABLE_SWAP_WRITE_THROUGHPUT,
|
2018-06-21 03:54:00 -04:00
|
|
|
|
2018-08-16 07:11:31 -04:00
|
|
|
VARIABLE_SWAP_COMPRESSION,
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
#ifdef HAVE_CPU_GROUP
|
|
|
|
/* cpu */
|
|
|
|
VARIABLE_CPU_USAGE,
|
|
|
|
VARIABLE_CPU_ACTIVE,
|
|
|
|
VARIABLE_CPU_ACTIVE_TIME,
|
|
|
|
#endif
|
|
|
|
|
2018-06-19 12:34:42 -04:00
|
|
|
#ifdef HAVE_MEMORY_GROUP
|
|
|
|
/* memory */
|
|
|
|
VARIABLE_MEMORY_USED,
|
|
|
|
VARIABLE_MEMORY_AVAILABLE,
|
|
|
|
VARIABLE_MEMORY_SIZE,
|
|
|
|
#endif
|
|
|
|
|
2018-03-31 11:43:15 -04:00
|
|
|
/* misc */
|
|
|
|
VARIABLE_MIPMAPED,
|
2018-07-01 13:22:51 -04:00
|
|
|
VARIABLE_ASYNC_RUNNING,
|
2018-03-31 11:43:15 -04:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
N_VARIABLES,
|
|
|
|
|
|
|
|
VARIABLE_SEPARATOR
|
|
|
|
} Variable;
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
VARIABLE_TYPE_BOOLEAN,
|
2018-07-01 13:22:51 -04:00
|
|
|
VARIABLE_TYPE_INTEGER,
|
2017-12-30 13:43:09 -05:00
|
|
|
VARIABLE_TYPE_SIZE,
|
|
|
|
VARIABLE_TYPE_SIZE_RATIO,
|
2018-01-19 09:03:44 -05:00
|
|
|
VARIABLE_TYPE_INT_RATIO,
|
|
|
|
VARIABLE_TYPE_PERCENTAGE,
|
2018-08-17 22:32:13 -04:00
|
|
|
VARIABLE_TYPE_DURATION,
|
|
|
|
VARIABLE_TYPE_RATE_OF_CHANGE
|
2017-12-30 13:43:09 -05:00
|
|
|
} VariableType;
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
FIRST_GROUP,
|
|
|
|
|
|
|
|
GROUP_CACHE = FIRST_GROUP,
|
|
|
|
GROUP_SWAP,
|
2018-01-19 09:03:44 -05:00
|
|
|
#ifdef HAVE_CPU_GROUP
|
|
|
|
GROUP_CPU,
|
2018-06-19 12:34:42 -04:00
|
|
|
#endif
|
|
|
|
#ifdef HAVE_MEMORY_GROUP
|
|
|
|
GROUP_MEMORY,
|
2018-01-19 09:03:44 -05:00
|
|
|
#endif
|
2018-03-31 11:43:15 -04:00
|
|
|
GROUP_MISC,
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
typedef void (* VariableFunc) (GimpDashboard *dashboard,
|
|
|
|
Variable variable);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
|
|
|
|
struct _VariableInfo
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
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;
|
2018-06-21 03:54:00 -04:00
|
|
|
GimpRGB color;
|
|
|
|
VariableFunc sample_func;
|
|
|
|
VariableFunc reset_func;
|
|
|
|
gconstpointer data;
|
2017-12-30 13:43:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _FieldInfo
|
|
|
|
{
|
2018-06-19 12:34:42 -04:00
|
|
|
Variable variable;
|
|
|
|
const gchar *title;
|
|
|
|
gboolean default_active;
|
|
|
|
gboolean show_in_header;
|
|
|
|
Variable meter_variable;
|
|
|
|
gint meter_value;
|
|
|
|
gboolean meter_cumulative;
|
2017-12-30 13:43:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _GroupInfo
|
|
|
|
{
|
|
|
|
const gchar *name;
|
|
|
|
const gchar *title;
|
|
|
|
const gchar *description;
|
2018-04-02 16:24:09 -04:00
|
|
|
gboolean default_active;
|
2017-12-30 13:43:09 -05:00
|
|
|
gboolean default_expanded;
|
|
|
|
gboolean has_meter;
|
|
|
|
Variable meter_limit;
|
2018-06-28 11:20:26 -04:00
|
|
|
const Variable *meter_led;
|
2017-12-30 13:43:09 -05:00
|
|
|
const FieldInfo *fields;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _VariableData
|
|
|
|
{
|
|
|
|
gboolean available;
|
|
|
|
|
|
|
|
union
|
|
|
|
{
|
|
|
|
gboolean boolean;
|
2018-07-01 13:22:51 -04:00
|
|
|
gint integer;
|
2018-08-17 22:32:13 -04:00
|
|
|
guint64 size; /* in bytes */
|
2017-12-30 13:43:09 -05:00
|
|
|
struct
|
|
|
|
{
|
|
|
|
guint64 antecedent;
|
|
|
|
guint64 consequent;
|
|
|
|
} size_ratio;
|
|
|
|
struct
|
|
|
|
{
|
|
|
|
gint antecedent;
|
|
|
|
gint consequent;
|
|
|
|
} int_ratio;
|
2018-08-17 22:32:13 -04:00
|
|
|
gdouble percentage; /* from 0 to 1 */
|
|
|
|
gdouble duration; /* in seconds */
|
|
|
|
gdouble rate_of_change; /* in source units per second */
|
2017-12-30 13:43:09 -05:00
|
|
|
} value;
|
2018-06-21 03:54:00 -04:00
|
|
|
|
|
|
|
gpointer data;
|
|
|
|
gsize data_size;
|
2017-12-30 13:43:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _FieldData
|
|
|
|
{
|
2017-12-31 10:43:47 -05:00
|
|
|
gboolean active;
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
GtkCheckMenuItem *menu_item;
|
|
|
|
GtkLabel *value_label;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _GroupData
|
|
|
|
{
|
2018-04-02 16:24:09 -04:00
|
|
|
gint n_fields;
|
|
|
|
gint n_meter_values;
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
gboolean active;
|
|
|
|
gdouble limit;
|
2018-01-04 11:08:24 -05:00
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
GtkToggleAction *action;
|
|
|
|
GtkExpander *expander;
|
|
|
|
GtkLabel *header_values_label;
|
|
|
|
GtkButton *menu_button;
|
|
|
|
GtkMenu *menu;
|
|
|
|
GimpMeter *meter;
|
2018-05-04 00:49:57 +02:00
|
|
|
GtkGrid *grid;
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
FieldData *fields;
|
2017-12-30 13:43:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
2017-12-30 13:43:09 -05:00
|
|
|
};
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
/* local function prototypes */
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
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);
|
2018-01-19 09:03:44 -05:00
|
|
|
#ifdef HAVE_CPU_GROUP
|
2018-08-17 22:32:13 -04:00
|
|
|
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);
|
2018-01-19 09:03:44 -05:00
|
|
|
#endif /* HAVE_CPU_GROUP */
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-06-19 12:34:42 -04:00
|
|
|
#ifdef HAVE_MEMORY_GROUP
|
2018-08-17 22:32:13 -04:00
|
|
|
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);
|
2018-06-19 12:34:42 -04:00
|
|
|
#endif /* HAVE_MEMORY_GROUP */
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
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);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
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);
|
2017-12-30 13:43:09 -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
|
|
|
static void gimp_dashboard_reset_unlocked (GimpDashboard *dashboard);
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
static void gimp_dashboard_reset_variables (GimpDashboard *dashboard);
|
2018-06-21 04:03:19 -04:00
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
static gpointer gimp_dashboard_variable_get_data (GimpDashboard *dashboard,
|
|
|
|
Variable variable,
|
|
|
|
gsize size);
|
2018-06-21 03:54:00 -04:00
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
static gboolean gimp_dashboard_variable_to_boolean (GimpDashboard *dashboard,
|
|
|
|
Variable variable);
|
|
|
|
static gdouble gimp_dashboard_variable_to_double (GimpDashboard *dashboard,
|
|
|
|
Variable variable);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
static gchar * gimp_dashboard_field_to_string (GimpDashboard *dashboard,
|
|
|
|
Group group,
|
|
|
|
gint field,
|
|
|
|
gboolean full);
|
2018-01-04 11:08:24 -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
|
|
|
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);
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
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);
|
2018-01-04 11:08:24 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
/* 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"),
|
2017-12-30 14:08:52 -05:00
|
|
|
.description = N_("Maximal tile cache occupied size"),
|
2017-12-30 13:43:09 -05:00
|
|
|
.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,
|
|
|
|
},
|
|
|
|
|
2018-08-17 20:54:42 -04:00
|
|
|
[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)
|
|
|
|
},
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
[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"
|
|
|
|
},
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
[VARIABLE_SWAP_READ_THROUGHPUT] =
|
|
|
|
{ .name = "swap-read-throughput",
|
|
|
|
.title = NC_("dashboard-variable", "Read throughput"),
|
2018-08-26 15:11:04 -04:00
|
|
|
.description = N_("The rate at which data is read from the swap"),
|
2018-08-17 22:32:13 -04:00
|
|
|
.type = VARIABLE_TYPE_RATE_OF_CHANGE,
|
2018-06-28 11:20:26 -04:00
|
|
|
.color = {0.2, 0.4, 1.0, 1.0},
|
2018-08-17 22:32:13 -04:00
|
|
|
.sample_func = gimp_dashboard_sample_variable_rate_of_change,
|
2018-06-21 03:54:00 -04:00
|
|
|
.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"
|
|
|
|
},
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
[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,
|
2018-06-28 11:20:26 -04:00
|
|
|
.color = {0.8, 0.3, 0.2, 1.0},
|
2018-08-17 22:32:13 -04:00
|
|
|
.sample_func = gimp_dashboard_sample_variable_rate_of_change,
|
2018-06-21 03:54:00 -04:00
|
|
|
.data = GINT_TO_POINTER (VARIABLE_SWAP_WRITTEN)
|
|
|
|
},
|
|
|
|
|
2018-08-16 07:11:31 -04:00
|
|
|
[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"
|
|
|
|
},
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
|
|
|
|
#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},
|
2018-06-21 03:54:00 -04:00
|
|
|
.sample_func = gimp_dashboard_sample_cpu_active
|
2018-01-19 09:03:44 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
[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},
|
2018-06-21 03:54:00 -04:00
|
|
|
.sample_func = gimp_dashboard_sample_cpu_active_time
|
2018-03-31 11:43:15 -04:00
|
|
|
},
|
2018-01-19 09:03:44 -05:00
|
|
|
#endif /* HAVE_CPU_GROUP */
|
2018-03-31 11:43:15 -04:00
|
|
|
|
|
|
|
|
2018-06-19 12:34:42 -04:00
|
|
|
#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 */
|
|
|
|
|
|
|
|
|
2018-03-31 11:43:15 -04:00
|
|
|
/* 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"
|
|
|
|
},
|
2018-07-01 13:22:51 -04:00
|
|
|
|
|
|
|
[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
|
|
|
|
}
|
2017-12-30 13:43:09 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
static const GroupInfo groups[] =
|
|
|
|
{
|
|
|
|
/* cache group */
|
|
|
|
[GROUP_CACHE] =
|
|
|
|
{ .name = "cache",
|
|
|
|
.title = NC_("dashboard-group", "Cache"),
|
|
|
|
.description = N_("In-memory tile cache"),
|
2018-04-02 16:24:09 -04:00
|
|
|
.default_active = TRUE,
|
2017-12-30 13:43:09 -05:00
|
|
|
.default_expanded = TRUE,
|
|
|
|
.has_meter = TRUE,
|
|
|
|
.meter_limit = VARIABLE_CACHE_LIMIT,
|
|
|
|
.fields = (const FieldInfo[])
|
|
|
|
{
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_CACHE_OCCUPIED,
|
|
|
|
.default_active = TRUE,
|
|
|
|
.show_in_header = TRUE,
|
|
|
|
.meter_value = 2
|
2017-12-30 13:43:09 -05:00
|
|
|
},
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_CACHE_MAXIMUM,
|
|
|
|
.default_active = FALSE,
|
|
|
|
.meter_value = 1
|
2017-12-30 13:43:09 -05:00
|
|
|
},
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_CACHE_LIMIT,
|
|
|
|
.default_active = TRUE
|
2017-12-30 13:43:09 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
{ VARIABLE_SEPARATOR },
|
|
|
|
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_CACHE_COMPRESSION,
|
|
|
|
.default_active = FALSE
|
2017-12-30 13:43:09 -05:00
|
|
|
},
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_CACHE_HIT_MISS,
|
|
|
|
.default_active = FALSE
|
2017-12-30 13:43:09 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
{}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
/* swap group */
|
|
|
|
[GROUP_SWAP] =
|
|
|
|
{ .name = "swap",
|
|
|
|
.title = NC_("dashboard-group", "Swap"),
|
|
|
|
.description = N_("On-disk tile swap"),
|
2018-04-02 16:24:09 -04:00
|
|
|
.default_active = TRUE,
|
2017-12-30 13:43:09 -05:00
|
|
|
.default_expanded = TRUE,
|
|
|
|
.has_meter = TRUE,
|
|
|
|
.meter_limit = VARIABLE_SWAP_LIMIT,
|
2018-06-28 11:20:26 -04:00
|
|
|
.meter_led = (const Variable[])
|
|
|
|
{
|
2018-08-17 20:54:42 -04:00
|
|
|
VARIABLE_SWAP_QUEUE_FULL,
|
2018-08-17 22:32:13 -04:00
|
|
|
VARIABLE_SWAP_READ_THROUGHPUT,
|
|
|
|
VARIABLE_SWAP_WRITE_THROUGHPUT,
|
2018-06-28 11:20:26 -04:00
|
|
|
|
|
|
|
VARIABLE_NONE
|
|
|
|
},
|
2017-12-30 13:43:09 -05:00
|
|
|
.fields = (const FieldInfo[])
|
|
|
|
{
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_SWAP_OCCUPIED,
|
|
|
|
.default_active = TRUE,
|
|
|
|
.show_in_header = TRUE,
|
2018-08-17 20:54:42 -04:00
|
|
|
.meter_value = 5
|
2017-12-30 13:43:09 -05:00
|
|
|
},
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_SWAP_SIZE,
|
|
|
|
.default_active = TRUE,
|
2018-08-17 20:54:42 -04:00
|
|
|
.meter_value = 4
|
2017-12-30 13:43:09 -05:00
|
|
|
},
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_SWAP_LIMIT,
|
|
|
|
.default_active = TRUE
|
2017-12-30 13:43:09 -05:00
|
|
|
},
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
{ VARIABLE_SEPARATOR },
|
|
|
|
|
2018-08-17 20:54:42 -04:00
|
|
|
{ .variable = VARIABLE_SWAP_QUEUED,
|
|
|
|
.default_active = FALSE,
|
|
|
|
.meter_variable = VARIABLE_SWAP_QUEUE_FULL,
|
|
|
|
.meter_value = 3
|
|
|
|
},
|
|
|
|
|
|
|
|
{ VARIABLE_SEPARATOR },
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
{ .variable = VARIABLE_SWAP_READ,
|
|
|
|
.default_active = FALSE,
|
2018-08-17 22:32:13 -04:00
|
|
|
.meter_variable = VARIABLE_SWAP_READ_THROUGHPUT,
|
2018-06-21 07:36:52 -04:00
|
|
|
.meter_value = 2
|
2018-06-21 03:54:00 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
{ .variable = VARIABLE_SWAP_WRITTEN,
|
|
|
|
.default_active = FALSE,
|
2018-08-17 22:32:13 -04:00
|
|
|
.meter_variable = VARIABLE_SWAP_WRITE_THROUGHPUT,
|
2018-06-21 07:36:52 -04:00
|
|
|
.meter_value = 1
|
2018-06-21 03:54:00 -04:00
|
|
|
},
|
|
|
|
|
2018-08-16 07:11:31 -04:00
|
|
|
{ VARIABLE_SEPARATOR },
|
|
|
|
|
|
|
|
{ .variable = VARIABLE_SWAP_COMPRESSION,
|
|
|
|
.default_active = FALSE
|
|
|
|
},
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
{}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
#ifdef HAVE_CPU_GROUP
|
|
|
|
/* cpu group */
|
|
|
|
[GROUP_CPU] =
|
|
|
|
{ .name = "cpu",
|
|
|
|
.title = NC_("dashboard-group", "CPU"),
|
|
|
|
.description = N_("CPU usage"),
|
2018-04-02 16:24:09 -04:00
|
|
|
.default_active = TRUE,
|
2018-01-19 09:03:44 -05:00
|
|
|
.default_expanded = FALSE,
|
|
|
|
.has_meter = TRUE,
|
2018-06-28 11:20:26 -04:00
|
|
|
.meter_led = (const Variable[])
|
|
|
|
{
|
|
|
|
VARIABLE_CPU_ACTIVE,
|
|
|
|
|
|
|
|
VARIABLE_NONE
|
|
|
|
},
|
2018-01-19 09:03:44 -05:00
|
|
|
.fields = (const FieldInfo[])
|
|
|
|
{
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_CPU_USAGE,
|
|
|
|
.default_active = TRUE,
|
|
|
|
.show_in_header = TRUE,
|
|
|
|
.meter_value = 2
|
2018-01-19 09:03:44 -05:00
|
|
|
},
|
|
|
|
|
|
|
|
{ VARIABLE_SEPARATOR },
|
|
|
|
|
2018-06-19 12:34:42 -04:00
|
|
|
{ .variable = VARIABLE_CPU_ACTIVE_TIME,
|
|
|
|
.default_active = FALSE,
|
|
|
|
.meter_variable = VARIABLE_CPU_ACTIVE,
|
|
|
|
.meter_value = 1
|
2018-01-19 09:03:44 -05:00
|
|
|
},
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
{}
|
|
|
|
}
|
2018-03-31 11:43:15 -04:00
|
|
|
},
|
2018-01-19 09:03:44 -05:00
|
|
|
#endif /* HAVE_CPU_GROUP */
|
2018-03-31 11:43:15 -04:00
|
|
|
|
2018-06-19 12:34:42 -04:00
|
|
|
#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 */
|
|
|
|
|
2018-03-31 11:43:15 -04:00
|
|
|
/* 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
|
|
|
|
},
|
2018-07-01 13:22:51 -04:00
|
|
|
{ .variable = VARIABLE_ASYNC_RUNNING,
|
|
|
|
.default_active = TRUE
|
|
|
|
},
|
2018-03-31 11:43:15 -04:00
|
|
|
|
|
|
|
{}
|
|
|
|
}
|
|
|
|
},
|
2017-12-30 13:43:09 -05:00
|
|
|
};
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (GimpDashboard, gimp_dashboard, GIMP_TYPE_EDITOR,
|
|
|
|
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);
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
object_class->constructed = gimp_dashboard_constructed;
|
|
|
|
object_class->dispose = gimp_dashboard_dispose;
|
|
|
|
object_class->finalize = gimp_dashboard_finalize;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
widget_class->map = gimp_dashboard_map;
|
|
|
|
widget_class->unmap = gimp_dashboard_unmap;
|
|
|
|
|
|
|
|
g_type_class_add_private (klass, sizeof (GimpDashboardPrivate));
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dashboard_init (GimpDashboard *dashboard)
|
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboardPrivate *priv;
|
|
|
|
GtkWidget *box;
|
2018-06-19 12:46:07 -04:00
|
|
|
GtkWidget *scrolled_window;
|
|
|
|
GtkWidget *viewport;
|
2017-12-30 13:43:09 -05:00
|
|
|
GtkWidget *vbox;
|
|
|
|
GtkWidget *expander;
|
|
|
|
GtkWidget *hbox;
|
|
|
|
GtkWidget *button;
|
|
|
|
GtkWidget *image;
|
|
|
|
GtkWidget *menu;
|
|
|
|
GtkWidget *item;
|
|
|
|
GtkWidget *frame;
|
|
|
|
GtkWidget *vbox2;
|
|
|
|
GtkWidget *meter;
|
2018-05-04 00:49:57 +02:00
|
|
|
GtkWidget *grid;
|
2017-12-30 13:43:09 -05:00
|
|
|
GtkWidget *label;
|
|
|
|
gint content_spacing;
|
|
|
|
Group group;
|
|
|
|
gint field;
|
|
|
|
|
|
|
|
priv = dashboard->priv = G_TYPE_INSTANCE_GET_PRIVATE (dashboard,
|
|
|
|
GIMP_TYPE_DASHBOARD,
|
|
|
|
GimpDashboardPrivate);
|
|
|
|
|
|
|
|
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;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2017-12-19 02:52:21 -05:00
|
|
|
box = gtk_event_box_new ();
|
2017-12-18 18:54:17 -05:00
|
|
|
gtk_box_pack_start (GTK_BOX (dashboard), box, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_show (box);
|
|
|
|
|
2018-06-19 12:46:07 -04:00
|
|
|
/* scrolled window */
|
|
|
|
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
|
|
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
|
2018-08-17 22:53:15 -04:00
|
|
|
GTK_POLICY_AUTOMATIC,
|
2018-06-19 12:46:07 -04:00
|
|
|
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);
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
/* main vbox */
|
|
|
|
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2 * content_spacing);
|
2018-06-19 12:46:07 -04:00
|
|
|
gtk_container_add (GTK_CONTAINER (viewport), vbox);
|
2017-12-18 18:54:17 -05:00
|
|
|
gtk_widget_show (vbox);
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
/* construct the groups */
|
|
|
|
for (group = FIRST_GROUP; group < N_GROUPS; group++)
|
|
|
|
{
|
|
|
|
const GroupInfo *group_info = &groups[group];
|
|
|
|
GroupData *group_data = &priv->groups[group];
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
group_data->n_fields = 0;
|
|
|
|
group_data->n_meter_values = 0;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
for (field = 0; group_info->fields[field].variable; field++)
|
|
|
|
{
|
|
|
|
const FieldInfo *field_info = &group_info->fields[field];
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
2018-01-04 11:08:24 -05:00
|
|
|
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
|
2017-12-30 13:43:09 -05:00
|
|
|
gtk_widget_show (label);
|
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
/* 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);
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
/* 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 (
|
2018-06-19 12:34:42 -04:00
|
|
|
g_dpgettext2 (NULL, "dashboard-variable",
|
|
|
|
field_info->title ? field_info->title :
|
|
|
|
variable_info->title));
|
2017-12-30 13:43:09 -05:00
|
|
|
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",
|
2018-04-02 16:24:09 -04:00
|
|
|
G_CALLBACK (gimp_dashboard_field_menu_item_toggled),
|
2017-12-30 13:43:09 -05:00
|
|
|
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)
|
|
|
|
{
|
2018-08-17 22:32:13 -04:00
|
|
|
const VariableInfo *variable_info = &variables[field_info->variable];
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
gimp_meter_set_value_color (GIMP_METER (meter),
|
|
|
|
field_info->meter_value - 1,
|
|
|
|
&variable_info->color);
|
2018-01-19 09:03:44 -05:00
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
if (gimp_dashboard_field_use_meter_underlay (group, field))
|
2018-01-19 09:03:44 -05:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
2017-12-30 13:43:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2018-05-04 00:49:57 +02:00
|
|
|
/* 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);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
gimp_dashboard_group_set_active (dashboard, group,
|
|
|
|
group_info->default_active);
|
2017-12-30 13:43:09 -05:00
|
|
|
gimp_dashboard_update_group (dashboard, group);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* sampler thread
|
|
|
|
*
|
|
|
|
* we use a separate thread for sampling, so that data is sampled even when
|
2017-12-18 18:54:17 -05:00
|
|
|
* the main thread is busy
|
|
|
|
*/
|
2017-12-30 13:43:09 -05:00
|
|
|
priv->thread = g_thread_new ("dashboard",
|
|
|
|
(GThreadFunc) gimp_dashboard_sample,
|
|
|
|
dashboard);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2017-12-30 13:43:09 -05:00
|
|
|
gimp_dashboard_constructed (GObject *object)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2018-04-02 16:24:09 -04:00
|
|
|
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;
|
2018-04-02 16:24:09 -04:00
|
|
|
Group group;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
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);
|
2017-12-30 13:43:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dashboard_dispose (GObject *object)
|
|
|
|
{
|
|
|
|
GimpDashboard *dashboard = GIMP_DASHBOARD (object);
|
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
|
|
|
|
if (priv->thread)
|
2017-12-25 13:10:47 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_lock (&priv->mutex);
|
2017-12-25 13:10:47 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
priv->quit = TRUE;
|
|
|
|
g_cond_signal (&priv->cond);
|
2017-12-25 13:10:47 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_unlock (&priv->mutex);
|
2017-12-25 13:10:47 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_clear_pointer (&priv->thread, g_thread_join);
|
2017-12-25 13:10:47 -05:00
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
if (priv->update_idle_id)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
g_source_remove (priv->update_idle_id);
|
|
|
|
priv->update_idle_id = 0;
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
if (priv->low_swap_space_idle_id)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
g_source_remove (priv->low_swap_space_idle_id);
|
|
|
|
priv->low_swap_space_idle_id = 0;
|
2017-12-18 18:54:17 -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
|
|
|
gimp_dashboard_log_stop_recording (dashboard, NULL);
|
|
|
|
|
2018-06-21 04:03:19 -04:00
|
|
|
gimp_dashboard_reset_variables (dashboard);
|
2018-06-21 03:54:00 -04:00
|
|
|
|
2017-12-25 13:10:47 -05:00
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-25 13:10:47 -05:00
|
|
|
static void
|
|
|
|
gimp_dashboard_finalize (GObject *object)
|
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboard *dashboard = GIMP_DASHBOARD (object);
|
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
gint i;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
for (i = FIRST_GROUP; i < N_GROUPS; i++)
|
|
|
|
g_free (priv->groups[i].fields);
|
|
|
|
|
|
|
|
g_mutex_clear (&priv->mutex);
|
|
|
|
g_cond_clear (&priv->cond);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
gimp_dashboard_update (dashboard);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dashboard_unmap (GtkWidget *widget)
|
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboard *dashboard = GIMP_DASHBOARD (widget);
|
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
|
|
|
|
g_mutex_lock (&priv->mutex);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
if (priv->update_idle_id)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
g_source_remove (priv->update_idle_id);
|
|
|
|
priv->update_idle_id = 0;
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_unlock (&priv->mutex);
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
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)
|
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboard *dashboard = GIMP_DASHBOARD (docked);
|
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
gchar *name;
|
|
|
|
GList *list;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
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"));
|
|
|
|
}
|
2017-12-30 13:43:09 -05:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Group group;
|
|
|
|
gint field;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
for (group = FIRST_GROUP; group < N_GROUPS; group++)
|
|
|
|
{
|
|
|
|
const GroupInfo *group_info = &groups[group];
|
|
|
|
GroupData *group_data = &priv->groups[group];
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
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);
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
name = g_strdup_printf ("%s-expanded", group_info->name);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
if (! strcmp (aux->name, name))
|
|
|
|
{
|
|
|
|
gboolean expanded = ! strcmp (aux->value, "yes");
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
gtk_expander_set_expanded (group_data->expander, expanded);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_free (name);
|
|
|
|
goto next_aux_info;
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
static GList *
|
|
|
|
gimp_dashboard_get_aux_info (GimpDocked *docked)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboard *dashboard = GIMP_DASHBOARD (docked);
|
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
GList *aux_info;
|
|
|
|
GimpSessionInfoAux *aux;
|
|
|
|
gchar *name;
|
|
|
|
gchar *value;
|
|
|
|
Group group;
|
|
|
|
gint field;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
aux_info = parent_docked_iface->get_aux_info (docked);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
for (group = FIRST_GROUP; group < N_GROUPS; group++)
|
|
|
|
{
|
|
|
|
const GroupInfo *group_info = &groups[group];
|
|
|
|
GroupData *group_data = &priv->groups[group];
|
2018-04-02 16:24:09 -04:00
|
|
|
gboolean active = group_data->active;
|
2017-12-30 13:43:09 -05:00
|
|
|
gboolean expanded = gtk_expander_get_expanded (group_data->expander);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2017-12-30 13:43:09 -05:00
|
|
|
gimp_dashboard_group_expander_button_press (GimpDashboard *dashboard,
|
|
|
|
GdkEventButton *bevent,
|
|
|
|
GtkWidget *widget)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
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)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2018-05-01 23:21:04 +02:00
|
|
|
gtk_menu_popup_at_widget (group_data->menu,
|
|
|
|
GTK_WIDGET (group_data->menu_button),
|
|
|
|
GDK_GRAVITY_WEST,
|
|
|
|
GDK_GRAVITY_NORTH_EAST,
|
|
|
|
(GdkEvent *) bevent);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
return TRUE;
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
return FALSE;
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
static void
|
2018-04-02 16:24:09 -04:00
|
|
|
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,
|
2017-12-30 13:43:09 -05:00
|
|
|
GtkCheckMenuItem *item)
|
|
|
|
{
|
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
Group group;
|
|
|
|
GroupData *group_data;
|
|
|
|
gint field;
|
|
|
|
FieldData *field_data;
|
2017-12-19 02:40:39 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
group = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item),
|
|
|
|
"gimp-dashboard-group"));
|
|
|
|
group_data = &priv->groups[group];
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
field = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (item),
|
|
|
|
"gimp-dashboard-field"));
|
|
|
|
field_data = &group_data->fields[field];
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
field_data->active = gtk_check_menu_item_get_active (item);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
gimp_dashboard_update_group (dashboard, group);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_lock (&priv->mutex);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
while (! priv->quit)
|
2017-12-18 18:54:17 -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
|
|
|
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;
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
if (! g_cond_wait_until (&priv->cond, &priv->mutex, end_time) ||
|
|
|
|
priv->update_now)
|
2017-12-18 18:54:17 -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
|
|
|
gint64 time;
|
2018-01-19 09:03:44 -05:00
|
|
|
gboolean variables_changed = FALSE;
|
2017-12-30 13:43:09 -05:00
|
|
|
Variable variable;
|
|
|
|
Group group;
|
|
|
|
gint field;
|
2017-12-18 18:54:17 -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
|
|
|
time = g_get_monotonic_time ();
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
/* sample all variables */
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
variable_info->sample_func (dashboard, variable);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
variables_changed = variables_changed ||
|
2017-12-30 13:43:09 -05:00
|
|
|
memcmp (variable_data, &prev_variable_data,
|
|
|
|
sizeof (VariableData));
|
|
|
|
}
|
2017-12-18 18:54:17 -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
|
|
|
/* log sample */
|
|
|
|
if (priv->log_output)
|
|
|
|
gimp_dashboard_log_sample (dashboard, variables_changed);
|
2017-12-18 18:54:17 -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
|
|
|
/* 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++)
|
2017-12-30 13:43:09 -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
|
|
|
const GroupInfo *group_info = &groups[group];
|
|
|
|
GroupData *group_data = &priv->groups[group];
|
|
|
|
gdouble *sample;
|
|
|
|
gdouble total = 0.0;
|
2018-06-19 12:34:42 -04: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 (! group_info->has_meter)
|
|
|
|
continue;
|
2018-01-19 09:03:44 -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
|
|
|
sample = g_new (gdouble, group_data->n_meter_values);
|
2018-06-19 12:34:42 -04: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
|
|
|
for (field = 0; field < group_data->n_fields; field++)
|
|
|
|
{
|
|
|
|
const FieldInfo *field_info = &group_info->fields[field];
|
2018-06-21 03:54:00 -04: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 (field_info->meter_value)
|
2018-06-19 12:34:42 -04: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
|
|
|
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;
|
2018-06-19 12:34:42 -04:00
|
|
|
}
|
2017-12-30 13:43:09 -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
|
|
|
gimp_meter_add_sample (group_data->meter, sample);
|
2017-12-30 13:43:09 -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
|
|
|
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)
|
2017-12-30 13:43:09 -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
|
|
|
/* 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);
|
|
|
|
}
|
2017-12-30 13:43:09 -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
|
|
|
/* check for low swap space */
|
|
|
|
if (priv->low_swap_space_warning &&
|
|
|
|
priv->variables[VARIABLE_SWAP_OCCUPIED].available &&
|
|
|
|
priv->variables[VARIABLE_SWAP_LIMIT].available)
|
2017-12-30 13:43:09 -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
|
|
|
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)
|
2017-12-30 13:43:09 -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 (! 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;
|
2017-12-30 13:43:09 -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
|
|
|
else if (seen_low_swap_space &&
|
|
|
|
swap_occupied <= LOW_SWAP_SPACE_WARNING_OFF * swap_limit)
|
2017-12-30 13:43:09 -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 (priv->low_swap_space_idle_id)
|
|
|
|
{
|
|
|
|
g_source_remove (priv->low_swap_space_idle_id);
|
2017-12-30 13:43:09 -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
|
|
|
priv->low_swap_space_idle_id = 0;
|
|
|
|
}
|
2017-12-30 13:43:09 -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
|
|
|
seen_low_swap_space = FALSE;
|
|
|
|
}
|
2017-12-30 13:43:09 -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
|
|
|
priv->update_now = FALSE;
|
2017-12-18 18:54:17 -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
|
|
|
last_update_time = time;
|
|
|
|
}
|
2017-12-19 02:40:39 -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
|
|
|
last_sample_time = time;
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_unlock (&priv->mutex);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
static gboolean
|
|
|
|
gimp_dashboard_update (GimpDashboard *dashboard)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
Group group;
|
|
|
|
|
|
|
|
g_mutex_lock (&priv->mutex);
|
|
|
|
|
|
|
|
for (group = FIRST_GROUP; group < N_GROUPS; group++)
|
2018-06-28 11:20:26 -04:00
|
|
|
gimp_dashboard_update_group_values (dashboard, group);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
priv->update_idle_id = 0;
|
|
|
|
|
|
|
|
g_mutex_unlock (&priv->mutex);
|
|
|
|
|
|
|
|
return G_SOURCE_REMOVE;
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
static gboolean
|
|
|
|
gimp_dashboard_low_swap_space (GimpDashboard *dashboard)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
if (priv->gimp)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2018-04-29 17:27:47 +02:00
|
|
|
GdkMonitor *monitor;
|
|
|
|
gint field;
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
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];
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
if (field_info->variable == VARIABLE_SWAP_OCCUPIED ||
|
|
|
|
field_info->variable == VARIABLE_SWAP_LIMIT)
|
|
|
|
{
|
|
|
|
gimp_dashboard_field_set_active (dashboard,
|
|
|
|
GROUP_SWAP, field, TRUE);
|
|
|
|
}
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
gimp_dashboard_update_groups (dashboard);
|
|
|
|
|
2018-04-29 17:27:47 +02:00
|
|
|
monitor = gimp_get_monitor_at_pointer ();
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
gimp_window_strategy_show_dockable_dialog (
|
|
|
|
GIMP_WINDOW_STRATEGY (gimp_get_window_strategy (priv->gimp)),
|
|
|
|
priv->gimp,
|
|
|
|
gimp_dialog_factory_get_singleton (),
|
2018-04-29 17:27:47 +02:00
|
|
|
monitor,
|
2017-12-30 13:43:09 -05:00
|
|
|
"gimp-dashboard");
|
|
|
|
|
|
|
|
g_mutex_lock (&priv->mutex);
|
|
|
|
|
|
|
|
priv->low_swap_space_idle_id = 0;
|
|
|
|
|
|
|
|
g_mutex_unlock (&priv->mutex);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
2018-07-01 13:22:51 -04:00
|
|
|
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;
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
case VARIABLE_TYPE_RATE_OF_CHANGE:
|
|
|
|
variable_data->value.rate_of_change = CALL_FUNC (gdouble);
|
|
|
|
break;
|
|
|
|
|
2018-07-01 13:22:51 -04:00
|
|
|
case VARIABLE_TYPE_SIZE_RATIO:
|
|
|
|
case VARIABLE_TYPE_INT_RATIO:
|
|
|
|
g_return_if_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef CALL_FUNC
|
|
|
|
|
|
|
|
variable_data->available = TRUE;
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
static void
|
|
|
|
gimp_dashboard_sample_gegl_config (GimpDashboard *dashboard,
|
|
|
|
Variable variable)
|
|
|
|
{
|
|
|
|
gimp_dashboard_sample_object (dashboard, G_OBJECT (gegl_config ()), variable);
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
static void
|
|
|
|
gimp_dashboard_sample_gegl_stats (GimpDashboard *dashboard,
|
|
|
|
Variable variable)
|
|
|
|
{
|
|
|
|
gimp_dashboard_sample_object (dashboard, G_OBJECT (gegl_stats ()), variable);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
static void
|
|
|
|
gimp_dashboard_sample_swap_limit (GimpDashboard *dashboard,
|
|
|
|
Variable variable)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
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));
|
2017-12-30 13:43:09 -05:00
|
|
|
gint64 time;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
/* 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 ();
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
if (time - data->last_check_time >= G_TIME_SPAN_SECOND)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
|
|
|
gchar *swap_dir;
|
|
|
|
|
|
|
|
g_object_get (gegl_config (),
|
|
|
|
"swap", &swap_dir,
|
|
|
|
NULL);
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
data->free_space = 0;
|
|
|
|
data->has_free_space = FALSE;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
data->free_space =
|
2017-12-18 18:54:17 -05:00
|
|
|
g_file_info_get_attribute_uint64 (info,
|
|
|
|
G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
|
2018-06-21 03:54:00 -04:00
|
|
|
data->has_free_space = TRUE;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
g_object_unref (info);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (file);
|
|
|
|
|
|
|
|
g_free (swap_dir);
|
|
|
|
}
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
data->last_check_time = time;
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
variable_data->available = data->has_free_space;
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
if (data->has_free_space)
|
2017-12-30 13:43:09 -05:00
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
variable_data->value.size = data->free_space;
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
#ifdef HAVE_CPU_GROUP
|
|
|
|
|
|
|
|
#ifdef HAVE_SYS_TIMES_H
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dashboard_sample_cpu_usage (GimpDashboard *dashboard,
|
|
|
|
Variable variable)
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
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));
|
2018-01-19 09:03:44 -05:00
|
|
|
clock_t curr_clock;
|
|
|
|
clock_t curr_usage;
|
|
|
|
struct tms tms;
|
|
|
|
|
|
|
|
curr_clock = times (&tms);
|
|
|
|
|
|
|
|
if (curr_clock == (clock_t) -1)
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
data->prev_clock = 0;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
|
|
|
variable_data->available = FALSE;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
curr_usage = tms.tms_utime + tms.tms_stime;
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
if (data->prev_clock && curr_clock != data->prev_clock)
|
2018-01-19 09:03:44 -05:00
|
|
|
{
|
|
|
|
variable_data->available = TRUE;
|
2018-06-21 03:54:00 -04:00
|
|
|
variable_data->value.percentage = (gdouble) (curr_usage - data->prev_usage) /
|
|
|
|
(curr_clock - data->prev_clock);
|
2018-01-19 09:03:44 -05:00
|
|
|
variable_data->value.percentage /= g_get_num_processors ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
variable_data->available = FALSE;
|
|
|
|
}
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
data->prev_clock = curr_clock;
|
|
|
|
data->prev_usage = curr_usage;
|
2018-01-19 09:03:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined (G_OS_WIN32)
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dashboard_sample_cpu_usage (GimpDashboard *dashboard,
|
|
|
|
Variable variable)
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
typedef struct
|
|
|
|
{
|
2018-06-28 10:17:36 -04:00
|
|
|
guint64 prev_time;
|
|
|
|
guint64 prev_usage;
|
2018-06-21 03:54:00 -04:00
|
|
|
} Data;
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
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 (
|
2018-06-21 03:54:00 -04:00
|
|
|
dashboard, variable, sizeof (Data));
|
2018-01-19 09:03:44 -05:00
|
|
|
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,
|
2018-01-20 18:05:51 -05:00
|
|
|
&process_kernel_time,
|
2018-01-19 09:03:44 -05:00
|
|
|
&process_user_time))
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
data->prev_time = 0;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
|
|
|
variable_data->available = FALSE;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GetSystemTimeAsFileTime (&system_time);
|
|
|
|
|
2018-01-25 07:41:34 -05:00
|
|
|
curr_time = ((guint64) system_time.dwHighDateTime << 32) |
|
|
|
|
(guint64) system_time.dwLowDateTime;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
2018-01-25 07:41:34 -05:00
|
|
|
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;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
if (data->prev_time && curr_time != data->prev_time)
|
2018-01-19 09:03:44 -05:00
|
|
|
{
|
|
|
|
variable_data->available = TRUE;
|
2018-06-21 03:54:00 -04:00
|
|
|
variable_data->value.percentage = (gdouble) (curr_usage - data->prev_usage) /
|
|
|
|
(curr_time - data->prev_time);
|
2018-01-19 09:03:44 -05:00
|
|
|
variable_data->value.percentage /= g_get_num_processors ();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
variable_data->available = FALSE;
|
|
|
|
}
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
data->prev_time = curr_time;
|
|
|
|
data->prev_usage = curr_usage;
|
2018-01-19 09:03:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* G_OS_WIN32 */
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dashboard_sample_cpu_active (GimpDashboard *dashboard,
|
|
|
|
Variable variable)
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gboolean active;
|
|
|
|
} Data;
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
VariableData *variable_data = &priv->variables[variable];
|
2018-06-21 03:54:00 -04:00
|
|
|
Data *data = gimp_dashboard_variable_get_data (
|
|
|
|
dashboard, variable, sizeof (Data));
|
2018-01-19 09:03:44 -05:00
|
|
|
gboolean active = FALSE;
|
|
|
|
|
|
|
|
if (priv->variables[VARIABLE_CPU_USAGE].available)
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
if (! data->active)
|
2018-01-19 09:03:44 -05:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
data->active = active;
|
2018-01-19 09:03:44 -05:00
|
|
|
variable_data->value.boolean = active;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_dashboard_sample_cpu_active_time (GimpDashboard *dashboard,
|
|
|
|
Variable variable)
|
|
|
|
{
|
2018-06-21 03:54:00 -04:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gint64 prev_time;
|
|
|
|
gint64 active_time;
|
|
|
|
} Data;
|
|
|
|
|
2018-01-19 09:03:44 -05:00
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
VariableData *variable_data = &priv->variables[variable];
|
2018-06-21 03:54:00 -04:00
|
|
|
Data *data = gimp_dashboard_variable_get_data (
|
|
|
|
dashboard, variable, sizeof (Data));
|
2018-01-19 09:03:44 -05:00
|
|
|
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;
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
if (active && data->prev_time)
|
|
|
|
data->active_time += curr_time - data->prev_time;
|
2018-01-19 09:03:44 -05:00
|
|
|
}
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
data->prev_time = curr_time;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
|
|
|
variable_data->available = TRUE;
|
2018-06-21 03:54:00 -04:00
|
|
|
variable_data->value.duration = data->active_time / 1000000.0;
|
2018-01-19 09:03:44 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* HAVE_CPU_GROUP */
|
|
|
|
|
2018-06-19 12:34:42 -04:00
|
|
|
#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;
|
2018-06-19 13:39:52 -04:00
|
|
|
static gint fd = -1;
|
2018-06-19 12:34:42 -04:00
|
|
|
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)
|
|
|
|
{
|
2018-06-28 10:48:11 -04:00
|
|
|
GimpDashboardPrivate *priv = dashboard->priv;
|
|
|
|
VariableData *variable_data = &priv->variables[variable];
|
|
|
|
PROCESS_MEMORY_COUNTERS_EX pmc = {};
|
2018-06-19 12:34:42 -04:00
|
|
|
|
|
|
|
variable_data->available = FALSE;
|
|
|
|
|
2018-06-28 10:48:11 -04:00
|
|
|
if (! GetProcessMemoryInfo (GetCurrentProcess (),
|
|
|
|
(PPROCESS_MEMORY_COUNTERS) &pmc,
|
|
|
|
sizeof (pmc)) ||
|
|
|
|
pmc.cb != sizeof (pmc))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2018-06-19 12:34:42 -04:00
|
|
|
|
|
|
|
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 */
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
|
|
|
|
2018-07-01 13:22:51 -04:00
|
|
|
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;
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
|
|
|
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;
|
2018-08-17 22:32:13 -04:00
|
|
|
|
|
|
|
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;
|
2017-12-30 13:43:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
gtk_widget_set_visible (GTK_WIDGET (group_data->expander),
|
|
|
|
group_data->active);
|
|
|
|
|
|
|
|
if (! group_data->active)
|
|
|
|
return;
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-30 23:40:15 -04:00
|
|
|
gimp_gtk_container_clear (GTK_CONTAINER (group_data->grid));
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
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);
|
2018-05-04 00:49:57 +02:00
|
|
|
gtk_widget_set_hexpand (separator, TRUE);
|
|
|
|
gtk_grid_attach (group_data->grid, separator,
|
|
|
|
0, n_rows, 3, 1);
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
2018-05-04 00:49:57 +02:00
|
|
|
gtk_widget_set_valign (color_area, GTK_ALIGN_CENTER);
|
|
|
|
gtk_grid_attach (group_data->grid, color_area,
|
|
|
|
0, n_rows, 1, 1);
|
2017-12-30 13:43:09 -05:00
|
|
|
gtk_widget_show (color_area);
|
|
|
|
}
|
|
|
|
|
|
|
|
str = g_strdup_printf ("%s:",
|
|
|
|
g_dpgettext2 (NULL, "dashboard-variable",
|
2018-06-19 12:34:42 -04:00
|
|
|
field_info->title ?
|
|
|
|
field_info->title :
|
|
|
|
variable_info->title));
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
label = gtk_label_new (str);
|
|
|
|
gimp_help_set_help_data (label, description,
|
|
|
|
NULL);
|
|
|
|
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
|
2018-05-04 00:49:57 +02:00
|
|
|
gtk_grid_attach (group_data->grid, label,
|
|
|
|
1, n_rows, 1, 1);
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
2018-05-04 00:49:57 +02:00
|
|
|
gtk_widget_set_hexpand (label, TRUE);
|
|
|
|
gtk_grid_attach (group_data->grid, label,
|
|
|
|
2, n_rows, 1, 1);
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
2018-01-04 11:08:24 -05:00
|
|
|
GString *header_values;
|
2017-12-30 13:43:09 -05:00
|
|
|
gint field;
|
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
if (! group_data->active)
|
|
|
|
return;
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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)
|
|
|
|
{
|
2018-06-28 11:20:26 -04:00
|
|
|
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);
|
2017-12-30 13:43:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
group_data->limit = limit;
|
|
|
|
|
|
|
|
header_values = g_string_new (NULL);
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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)
|
|
|
|
{
|
2018-01-04 11:08:24 -05:00
|
|
|
gchar *text;
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
text = gimp_dashboard_field_to_string (dashboard,
|
|
|
|
group, field, TRUE);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
gimp_dashboard_label_set_text (field_data->value_label, text);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
g_free (text);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
if (field_info->show_in_header)
|
|
|
|
{
|
|
|
|
text = gimp_dashboard_field_to_string (dashboard,
|
|
|
|
group, field, FALSE);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
if (header_values->len > 0)
|
|
|
|
g_string_append (header_values, ", ");
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
g_string_append (header_values, text);
|
2017-12-30 13:43:09 -05:00
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
g_free (text);
|
|
|
|
}
|
2017-12-30 13:43:09 -05:00
|
|
|
}
|
|
|
|
}
|
2018-01-04 11:08:24 -05:00
|
|
|
|
|
|
|
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);
|
2017-12-30 13:43:09 -05:00
|
|
|
}
|
|
|
|
|
2018-04-02 16:24:09 -04:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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,
|
2018-04-02 16:24:09 -04:00
|
|
|
gimp_dashboard_field_menu_item_toggled,
|
2017-12-30 13:43:09 -05:00
|
|
|
dashboard);
|
|
|
|
|
|
|
|
gtk_check_menu_item_set_active (field_data->menu_item, active);
|
|
|
|
|
|
|
|
g_signal_handlers_unblock_by_func (field_data->menu_item,
|
2018-04-02 16:24:09 -04:00
|
|
|
gimp_dashboard_field_menu_item_toggled,
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-21 03:54:00 -04:00
|
|
|
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);
|
|
|
|
}
|
2018-06-21 03:54:00 -04:00
|
|
|
|
|
|
|
variable_data->data_size = size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return variable_data->data;
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
|
|
|
|
2018-07-01 13:22:51 -04:00
|
|
|
case VARIABLE_TYPE_INTEGER:
|
|
|
|
return variable_data->value.integer != 0;
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
|
|
|
case VARIABLE_TYPE_PERCENTAGE:
|
|
|
|
return variable_data->value.percentage != 0.0;
|
|
|
|
|
|
|
|
case VARIABLE_TYPE_DURATION:
|
|
|
|
return variable_data->value.duration != 0.0;
|
2018-08-17 22:32:13 -04:00
|
|
|
|
|
|
|
case VARIABLE_TYPE_RATE_OF_CHANGE:
|
|
|
|
return variable_data->value.rate_of_change != 0.0;
|
2017-12-30 13:43:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-07-01 13:22:51 -04:00
|
|
|
case VARIABLE_TYPE_INTEGER:
|
|
|
|
return variable_data->value.integer;
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
|
|
|
case VARIABLE_TYPE_PERCENTAGE:
|
|
|
|
return variable_data->value.percentage;
|
|
|
|
|
|
|
|
case VARIABLE_TYPE_DURATION:
|
|
|
|
return variable_data->value.duration;
|
2018-08-17 22:32:13 -04:00
|
|
|
|
|
|
|
case VARIABLE_TYPE_RATE_OF_CHANGE:
|
|
|
|
return variable_data->value.rate_of_change;
|
2017-12-30 13:43:09 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0.0;
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
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;
|
2018-01-19 09:03:44 -05:00
|
|
|
gboolean show_limit = TRUE;
|
2018-01-04 11:08:24 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2018-07-01 13:22:51 -04:00
|
|
|
case VARIABLE_TYPE_INTEGER:
|
|
|
|
str = g_strdup_printf ("%d", variable_data->value.integer);
|
|
|
|
static_str = FALSE;
|
|
|
|
break;
|
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
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;
|
2018-01-19 09:03:44 -05:00
|
|
|
|
|
|
|
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;
|
2018-08-17 22:32:13 -04:00
|
|
|
|
|
|
|
case VARIABLE_TYPE_RATE_OF_CHANGE:
|
2018-08-26 15:11:04 -04:00
|
|
|
/* 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".
|
|
|
|
*/
|
2018-08-17 22:32:13 -04:00
|
|
|
str = g_strdup_printf (_("%g/s"),
|
|
|
|
variable_data->value.rate_of_change);
|
|
|
|
static_str = FALSE;
|
|
|
|
break;
|
2018-01-04 11:08:24 -05:00
|
|
|
}
|
|
|
|
|
2018-06-21 07:36:52 -04:00
|
|
|
if (show_limit &&
|
|
|
|
variable_data->available &&
|
|
|
|
field_info->meter_value &&
|
|
|
|
! field_info->meter_variable &&
|
2018-01-19 09:03:44 -05:00
|
|
|
group_data->limit)
|
2018-01-04 11:08:24 -05:00
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
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);
|
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
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 ('"', """)
|
|
|
|
ESCAPE ('\'', "'")
|
|
|
|
ESCAPE ('<', "<")
|
|
|
|
ESCAPE ('>', ">")
|
|
|
|
ESCAPE ('&', "&")
|
|
|
|
|
|
|
|
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 n_frames;
|
|
|
|
gint n_head = 0;
|
|
|
|
gint n_tail = 0;
|
|
|
|
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;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (n_head + n_tail == n_frames)
|
|
|
|
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,
|
|
|
|
"\"");
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_dashboard_log_printf (dashboard,
|
|
|
|
">\n");
|
|
|
|
|
|
|
|
for (frame = n_head; frame < n_frames - n_tail; frame++)
|
|
|
|
{
|
|
|
|
unsigned long long address;
|
|
|
|
|
|
|
|
address = gimp_backtrace_get_frame_address (backtrace,
|
|
|
|
thread, frame);
|
|
|
|
|
|
|
|
gimp_dashboard_log_printf (dashboard,
|
|
|
|
"<frame address=\"0x%llx\" />\n",
|
|
|
|
address);
|
|
|
|
|
|
|
|
g_hash_table_add (priv->log_addresses, (gpointer) address);
|
|
|
|
}
|
|
|
|
|
|
|
|
gimp_dashboard_log_printf (dashboard,
|
|
|
|
"</thread>\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2018-09-02 13:22:27 -04:00
|
|
|
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++)
|
|
|
|
{
|
2018-09-02 13:22:27 -04:00
|
|
|
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;
|
|
|
|
|
2018-09-02 13:22:27 -04:00
|
|
|
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 (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);
|
|
|
|
}
|
|
|
|
|
2018-08-17 22:32:13 -04:00
|
|
|
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"));
|
|
|
|
}
|
|
|
|
|
2018-01-04 11:08:24 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
dashboard->priv->gimp = gimp;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
gboolean has_backtrace;
|
|
|
|
Variable variable;
|
|
|
|
|
|
|
|
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_init ();
|
|
|
|
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);
|
|
|
|
|
|
|
|
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"
|
|
|
|
"<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"
|
|
|
|
"<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_shutdown ();
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
if (priv->log_include_backtrace)
|
|
|
|
gimp_backtrace_shutdown ();
|
|
|
|
|
|
|
|
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_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;
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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)
|
2017-12-30 13:43:09 -05:00
|
|
|
{
|
|
|
|
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));
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
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++;
|
2017-12-30 13:43:09 -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
|
|
|
gimp_dashboard_log_printf (dashboard,
|
|
|
|
"\n"
|
|
|
|
"<marker id=\"%d\" t=\"%lld\"",
|
|
|
|
priv->log_n_markers,
|
|
|
|
(long long) gimp_dashboard_log_time (dashboard));
|
2018-01-19 09:03:44 -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 (description && description[0])
|
2017-12-30 13:43:09 -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
|
|
|
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");
|
2017-12-30 13:43:09 -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
|
|
|
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);
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
priv->update_now = TRUE;
|
|
|
|
g_cond_signal (&priv->cond);
|
|
|
|
|
|
|
|
g_mutex_unlock (&priv->mutex);
|
|
|
|
}
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
void
|
|
|
|
gimp_dashboard_set_update_interval (GimpDashboard *dashboard,
|
|
|
|
GimpDashboardUpdateInteval update_interval)
|
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboardPrivate *priv;
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
g_return_if_fail (GIMP_IS_DASHBOARD (dashboard));
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
priv = dashboard->priv;
|
|
|
|
|
|
|
|
if (update_interval != priv->update_interval)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
Group group;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_lock (&priv->mutex);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
priv->update_interval = update_interval;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
for (group = FIRST_GROUP; group < N_GROUPS; group++)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GroupData *group_data = &priv->groups[group];
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
if (group_data->meter)
|
|
|
|
{
|
|
|
|
gimp_meter_set_history_resolution (group_data->meter,
|
|
|
|
update_interval / 1000.0);
|
|
|
|
}
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
priv->update_now = TRUE;
|
|
|
|
g_cond_signal (&priv->cond);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_unlock (&priv->mutex);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
void
|
|
|
|
gimp_dashboard_set_history_duration (GimpDashboard *dashboard,
|
|
|
|
GimpDashboardHistoryDuration history_duration)
|
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboardPrivate *priv;
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
g_return_if_fail (GIMP_IS_DASHBOARD (dashboard));
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
priv = dashboard->priv;
|
|
|
|
|
|
|
|
if (history_duration != priv->history_duration)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
Group group;
|
|
|
|
|
|
|
|
g_mutex_lock (&priv->mutex);
|
|
|
|
|
|
|
|
priv->history_duration = history_duration;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
void
|
|
|
|
gimp_dashboard_set_low_swap_space_warning (GimpDashboard *dashboard,
|
|
|
|
gboolean low_swap_space_warning)
|
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
GimpDashboardPrivate *priv;
|
|
|
|
|
2017-12-18 18:54:17 -05:00
|
|
|
g_return_if_fail (GIMP_IS_DASHBOARD (dashboard));
|
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
priv = dashboard->priv;
|
|
|
|
|
|
|
|
if (low_swap_space_warning != priv->low_swap_space_warning)
|
2017-12-18 18:54:17 -05:00
|
|
|
{
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_lock (&priv->mutex);
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
priv->low_swap_space_warning = low_swap_space_warning;
|
2017-12-18 18:54:17 -05:00
|
|
|
|
2017-12-30 13:43:09 -05:00
|
|
|
g_mutex_unlock (&priv->mutex);
|
2017-12-18 18:54:17 -05:00
|
|
|
}
|
|
|
|
}
|
2017-12-30 13:43:09 -05:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-04-02 16:24:09 -04:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|