Commit 60ca6110 authored by Ell's avatar Ell

app: add progressive performance logs

Add an option to record progressive performance logs.  Progressive
logs contain complete information after each recorded sample, by
writing partial address maps at each sample, containing all new
addresses introduced by the sample.  Furthermore, when recording a
progressive log, the output stream is flushed after each sample.

This allows recording complete logs even in cases where they can't
be properly terminated, such as when GIMP crashes or freezes in the
middle of the log.

Progressive logs are disabled by default, since they potentially
increase the sampling cost.  They can be enabled through a toggle
in the log file-dialog, or through the
GIMP_PERFORMANCE_LOG_PROGRESSIVE environment varaible.

(cherry picked from commit 146c2343)
parent 7e21f792
...@@ -212,6 +212,20 @@ dashboard_log_record_cmd_callback (GimpAction *action, ...@@ -212,6 +212,20 @@ dashboard_log_record_cmd_callback (GimpAction *action,
G_CALLBACK (gimp_toggle_button_update), G_CALLBACK (gimp_toggle_button_update),
&info->params.backtrace); &info->params.backtrace);
toggle = gtk_check_button_new_with_mnemonic (_("Progressi_ve"));
gimp_help_set_help_data (toggle, _("Produce complete log "
"even if not properly terminated"),
NULL);
gtk_box_pack_start (GTK_BOX (hbox), toggle, FALSE, FALSE, 0);
gtk_widget_show (toggle);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggle),
info->params.progressive);
g_signal_connect (toggle, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&info->params.progressive);
g_signal_connect (dialog, "response", g_signal_connect (dialog, "response",
G_CALLBACK (dashboard_log_record_response), G_CALLBACK (dashboard_log_record_response),
dashboard); dashboard);
......
...@@ -99,6 +99,7 @@ ...@@ -99,6 +99,7 @@
#define LOG_SAMPLE_FREQUENCY_MAX 1000 /* samples per second */ #define LOG_SAMPLE_FREQUENCY_MAX 1000 /* samples per second */
#define LOG_DEFAULT_SAMPLE_FREQUENCY 10 /* samples per second */ #define LOG_DEFAULT_SAMPLE_FREQUENCY 10 /* samples per second */
#define LOG_DEFAULT_BACKTRACE TRUE #define LOG_DEFAULT_BACKTRACE TRUE
#define LOG_DEFAULT_PROGRESSIVE FALSE
typedef enum typedef enum
...@@ -440,7 +441,11 @@ static void gimp_dashboard_log_sample (GimpDashboard ...@@ -440,7 +441,11 @@ static void gimp_dashboard_log_sample (GimpDashboard
static void gimp_dashboard_log_update_highlight (GimpDashboard *dashboard); static void gimp_dashboard_log_update_highlight (GimpDashboard *dashboard);
static void gimp_dashboard_log_update_n_markers (GimpDashboard *dashboard); static void gimp_dashboard_log_update_n_markers (GimpDashboard *dashboard);
static void gimp_dashboard_log_write_address_map (GimpAsync *async, static void gimp_dashboard_log_write_address_map (GimpDashboard *dashboard,
guintptr *addresses,
gint n_addresses,
GimpAsync *async);
static void gimp_dashboard_log_write_global_address_map (GimpAsync *async,
GimpDashboard *dashboard); GimpDashboard *dashboard);
static gboolean gimp_dashboard_field_use_meter_underlay (Group group, static gboolean gimp_dashboard_field_use_meter_underlay (Group group,
...@@ -3556,6 +3561,7 @@ gimp_dashboard_log_sample (GimpDashboard *dashboard, ...@@ -3556,6 +3561,7 @@ gimp_dashboard_log_sample (GimpDashboard *dashboard,
{ {
GimpDashboardPrivate *priv = dashboard->priv; GimpDashboardPrivate *priv = dashboard->priv;
GimpBacktrace *backtrace = NULL; GimpBacktrace *backtrace = NULL;
GArray *addresses = NULL;
gboolean empty = TRUE; gboolean empty = TRUE;
Variable variable; Variable variable;
...@@ -3874,7 +3880,18 @@ gimp_dashboard_log_sample (GimpDashboard *dashboard, ...@@ -3874,7 +3880,18 @@ gimp_dashboard_log_sample (GimpDashboard *dashboard,
"<frame address=\"0x%llx\" />\n", "<frame address=\"0x%llx\" />\n",
(unsigned long long) address); (unsigned long long) address);
g_hash_table_add (priv->log_addresses, (gpointer) address); if (g_hash_table_add (priv->log_addresses,
(gpointer) address) &&
priv->log_params.progressive)
{
if (! addresses)
{
addresses = g_array_new (FALSE, FALSE,
sizeof (guintptr));
}
g_array_append_val (addresses, address);
}
} }
gimp_dashboard_log_printf (dashboard, gimp_dashboard_log_printf (dashboard,
...@@ -3917,6 +3934,19 @@ gimp_dashboard_log_sample (GimpDashboard *dashboard, ...@@ -3917,6 +3934,19 @@ gimp_dashboard_log_sample (GimpDashboard *dashboard,
"</sample>\n"); "</sample>\n");
} }
if (addresses)
{
gimp_dashboard_log_write_address_map (dashboard,
(guintptr *) addresses->data,
addresses->len,
NULL);
g_array_free (addresses, TRUE);
}
if (priv->log_params.progressive)
g_output_stream_flush (priv->log_output, NULL, NULL);
#undef NONEMPTY #undef NONEMPTY
priv->log_n_samples++; priv->log_n_samples++;
...@@ -3959,34 +3989,17 @@ gimp_dashboard_log_compare_addresses (gconstpointer a1, ...@@ -3959,34 +3989,17 @@ gimp_dashboard_log_compare_addresses (gconstpointer a1,
} }
static void static void
gimp_dashboard_log_write_address_map (GimpAsync *async, gimp_dashboard_log_write_address_map (GimpDashboard *dashboard,
GimpDashboard *dashboard) guintptr *addresses,
gint n_addresses,
GimpAsync *async)
{ {
GimpDashboardPrivate *priv = dashboard->priv; GimpBacktraceAddressInfo infos[2];
GimpBacktraceAddressInfo infos[2]; gint i;
guintptr *addresses; gint n;
gint n_addresses;
GList *iter;
gint i;
gint n;
n_addresses = g_hash_table_size (priv->log_addresses);
if (n_addresses == 0) if (n_addresses == 0)
{ return;
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), qsort (addresses, n_addresses, sizeof (guintptr),
gimp_dashboard_log_compare_addresses); gimp_dashboard_log_compare_addresses);
...@@ -4002,7 +4015,7 @@ gimp_dashboard_log_write_address_map (GimpAsync *async, ...@@ -4002,7 +4015,7 @@ gimp_dashboard_log_write_address_map (GimpAsync *async,
GimpBacktraceAddressInfo *info = &infos[n % 2]; GimpBacktraceAddressInfo *info = &infos[n % 2];
const GimpBacktraceAddressInfo *prev_info = &infos[(n + 1) % 2]; const GimpBacktraceAddressInfo *prev_info = &infos[(n + 1) % 2];
if (gimp_async_is_canceled (async)) if (async && gimp_async_is_canceled (async))
break; break;
if (gimp_backtrace_get_address_info (addresses[i], info)) if (gimp_backtrace_get_address_info (addresses[i], info))
...@@ -4139,11 +4152,41 @@ gimp_dashboard_log_write_address_map (GimpAsync *async, ...@@ -4139,11 +4152,41 @@ gimp_dashboard_log_write_address_map (GimpAsync *async,
} }
} }
g_free (addresses);
gimp_dashboard_log_printf (dashboard, gimp_dashboard_log_printf (dashboard,
"\n" "\n"
"</address-map>\n"); "</address-map>\n");
}
static void
gimp_dashboard_log_write_global_address_map (GimpAsync *async,
GimpDashboard *dashboard)
{
GimpDashboardPrivate *priv = dashboard->priv;
gint n_addresses;
n_addresses = g_hash_table_size (priv->log_addresses);
if (n_addresses > 0)
{
guintptr *addresses;
GList *iter;
gint i;
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;
}
gimp_dashboard_log_write_address_map (dashboard,
addresses, n_addresses,
async);
g_free (addresses);
}
gimp_async_finish (async, NULL); gimp_async_finish (async, NULL);
} }
...@@ -4331,12 +4374,27 @@ gimp_dashboard_log_start_recording (GimpDashboard *dashboard, ...@@ -4331,12 +4374,27 @@ gimp_dashboard_log_start_recording (GimpDashboard *dashboard,
atoi (g_getenv ("GIMP_PERFORMANCE_LOG_BACKTRACE")) ? 1 : 0; atoi (g_getenv ("GIMP_PERFORMANCE_LOG_BACKTRACE")) ? 1 : 0;
} }
if (g_getenv ("GIMP_PERFORMANCE_LOG_PROGRESSIVE"))
{
priv->log_params.progressive =
atoi (g_getenv ("GIMP_PERFORMANCE_LOG_BACKTRACE")) ? 1 : 0;
}
priv->log_params.sample_frequency = CLAMP (priv->log_params.sample_frequency, priv->log_params.sample_frequency = CLAMP (priv->log_params.sample_frequency,
LOG_SAMPLE_FREQUENCY_MIN, LOG_SAMPLE_FREQUENCY_MIN,
LOG_SAMPLE_FREQUENCY_MAX); LOG_SAMPLE_FREQUENCY_MAX);
g_mutex_lock (&priv->mutex); g_mutex_lock (&priv->mutex);
if (priv->log_params.progressive &&
g_file_query_exists (file, NULL) &&
! g_file_delete (file, NULL, error))
{
g_mutex_unlock (&priv->mutex);
return FALSE;
}
priv->log_output = G_OUTPUT_STREAM (g_file_replace (file, priv->log_output = G_OUTPUT_STREAM (g_file_replace (file,
NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, FALSE, G_FILE_CREATE_NONE, NULL,
error)); error));
...@@ -4370,9 +4428,11 @@ gimp_dashboard_log_start_recording (GimpDashboard *dashboard, ...@@ -4370,9 +4428,11 @@ gimp_dashboard_log_start_recording (GimpDashboard *dashboard,
"<params>\n" "<params>\n"
"<sample-frequency>%d</sample-frequency>\n" "<sample-frequency>%d</sample-frequency>\n"
"<backtrace>%d</backtrace>\n" "<backtrace>%d</backtrace>\n"
"<progressive>%d</progressive>\n"
"</params>\n", "</params>\n",
priv->log_params.sample_frequency, priv->log_params.sample_frequency,
has_backtrace); has_backtrace,
priv->log_params.progressive);
gimp_dashboard_log_printf (dashboard, gimp_dashboard_log_printf (dashboard,
"\n" "\n"
...@@ -4580,12 +4640,13 @@ gimp_dashboard_log_stop_recording (GimpDashboard *dashboard, ...@@ -4580,12 +4640,13 @@ gimp_dashboard_log_stop_recording (GimpDashboard *dashboard,
"</samples>\n"); "</samples>\n");
if (g_hash_table_size (priv->log_addresses) > 0) if (! priv->log_params.progressive &&
g_hash_table_size (priv->log_addresses) > 0)
{ {
GimpAsync *async; GimpAsync *async;
async = gimp_parallel_run_async_independent ( async = gimp_parallel_run_async_independent (
(GimpRunAsyncFunc) gimp_dashboard_log_write_address_map, (GimpRunAsyncFunc) gimp_dashboard_log_write_global_address_map,
dashboard); dashboard);
gimp_wait (priv->gimp, GIMP_WAITABLE (async), gimp_wait (priv->gimp, GIMP_WAITABLE (async),
...@@ -4659,6 +4720,7 @@ gimp_dashboard_log_get_default_params (GimpDashboard *dashboard) ...@@ -4659,6 +4720,7 @@ gimp_dashboard_log_get_default_params (GimpDashboard *dashboard)
{ {
.sample_frequency = LOG_DEFAULT_SAMPLE_FREQUENCY, .sample_frequency = LOG_DEFAULT_SAMPLE_FREQUENCY,
.backtrace = LOG_DEFAULT_BACKTRACE, .backtrace = LOG_DEFAULT_BACKTRACE,
.progressive = LOG_DEFAULT_PROGRESSIVE
}; };
g_return_val_if_fail (GIMP_IS_DASHBOARD (dashboard), NULL); g_return_val_if_fail (GIMP_IS_DASHBOARD (dashboard), NULL);
......
...@@ -29,6 +29,7 @@ struct _GimpDashboardLogParams ...@@ -29,6 +29,7 @@ struct _GimpDashboardLogParams
{ {
gint sample_frequency; gint sample_frequency;
gboolean backtrace; gboolean backtrace;
gboolean progressive;
}; };
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment