diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2007-12-20 12:50:14 +0000 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2007-12-20 12:50:14 +0000 |
commit | 650d06b4d317fa47ae0882c9908de95d9501ff49 (patch) | |
tree | dc69de858a020cf06ed835239b4fda14b977ec88 | |
parent | e64a19fe9511e8f9a76d11d1c933e4796a430014 (diff) |
Delay updating the widgets to reduce overhead whilst monitoring clients.
-rw-r--r-- | src/app.c | 274 | ||||
-rw-r--r-- | src/client.h | 3 | ||||
-rw-r--r-- | src/spacetime.c | 2 |
3 files changed, 228 insertions, 51 deletions
@@ -609,6 +609,13 @@ _client_update_alloc_fn (Client *client) if (A->alloc_fn_serial == serial) break; + if (A->alloc_fn_serial == 0) { + for (n = 0; n < A->n_frames; n++) { + A->frames[n] = frames_get (&client->frames, + ((gulong *)A->frames)[n]); + } + } + for (n = 0; n < A->n_frames - 1; n++) { if (! frames_is_alloc_fn (&client->frames, A->frames[n])) break; @@ -620,7 +627,7 @@ _client_update_alloc_fn (Client *client) } static void -_client_update_max_bytes (Client *client, guint time) +_client_update_max_bytes (Client *client) { Allocator *A; @@ -635,31 +642,17 @@ _client_update_max_bytes (Client *client, guint time) static void app_update_allocators (App *app, Client *client, guint time) { - _client_update_alloc_fn (&app->client); - _client_update_max_bytes (&app->client, time); - - - call_graph_store_update (app->client.call_graph, - app, - app->client.allocators, - app->client.last); - timeline_add_datum ((Timeline *) app->timeline, &app->client, time, app->client.allocators); spacetime_add_datum ((Spacetime *) app->spacetime, &app->client, time, app->client.allocators); - - summary_update ((Summary *) app->summary, client); - - app->client.last = time; } static void app_update_client (App *app, Client *client, guint time) { app_update_allocators (app, client, time); - app_set_blocks (app, client->blocks); } @@ -1541,6 +1534,7 @@ lwp_read (gzFile *file, App *app) app->client.pid = pid; app->client.type = LWP; + app->client.time = time; /* new objects */ if (! readn (file, &count, sizeof (count))) @@ -1594,7 +1588,6 @@ lwp_read (gzFile *file, App *app) NULL, NULL, NULL, NULL, 0); } } - shared_objects_lookup_symbols (&app->client.objects); /* new allocators */ if (! readn (file, &count, sizeof (count))) @@ -1603,7 +1596,6 @@ lwp_read (gzFile *file, App *app) while (count--) { guint key; Allocator *A; - guint n; if (! readn (file, &key, sizeof (key))) return FALSE; @@ -1625,12 +1617,6 @@ lwp_read (gzFile *file, App *app) if (! readn (file, A->frames, A->n_frames * sizeof (gulong))) return FALSE; - - for (n = 0; n < A->n_frames; n++) { - A->frames[n] = frames_get (&app->client.frames, - ((gulong *)A->frames)[n]); - g_return_val_if_fail (A->frames[n] != NULL, FALSE); - } A->alloc_fn_serial = 0; _client_add_allocator (&app->client, A); @@ -1721,15 +1707,205 @@ lwp_read (gzFile *file, App *app) } } - if (app->client.pid) { - if (! _get_pid_cmd (app->client.pid, client, G_N_ELEMENTS (client))) + return TRUE; +} + +typedef struct _timeout_source { + GSource source; + GTimeVal expiration; + guint interval; +} TimeoutSource; + +static void +_timeout_set_expiration (TimeoutSource *timeout_source, + GTimeVal *current_time) +{ + guint seconds = timeout_source->interval / 1000; + guint msecs = timeout_source->interval - seconds * 1000; + + timeout_source->expiration.tv_sec = current_time->tv_sec + seconds; + timeout_source->expiration.tv_usec = current_time->tv_usec + msecs * 1000; + if (timeout_source->expiration.tv_usec >= 1000000) + { + timeout_source->expiration.tv_usec -= 1000000; + timeout_source->expiration.tv_sec++; + } +} + +static gboolean +_timeout_prepare (GSource *source, + gint *timeout) +{ + TimeoutSource *timeout_source = (TimeoutSource *)source; + GTimeVal current_time; + glong sec; + glong msec; + + g_source_get_current_time (source, ¤t_time); + + sec = timeout_source->expiration.tv_sec - current_time.tv_sec; + msec = (timeout_source->expiration.tv_usec - current_time.tv_usec) / 1000; + + /* We do the following in a rather convoluted fashion to deal with + * the fact that we don't have an integral type big enough to hold + * the difference of two timevals in millseconds. + */ + if (sec < 0 || (sec == 0 && msec < 0)) + msec = 0; + else + { + glong interval_sec = timeout_source->interval / 1000; + glong interval_msec = timeout_source->interval % 1000; + + if (msec < 0) + { + msec += 1000; + sec -= 1; + } + + if (sec > interval_sec || + (sec == interval_sec && msec > interval_msec)) + { + /* The system time has been set backwards, so we + * reset the expiration time to now + timeout_source->interval; + * this at least avoids hanging for long periods of time. + */ + _timeout_set_expiration (timeout_source, ¤t_time); + msec = MIN (G_MAXINT, timeout_source->interval); + } + else + { + msec = MIN (G_MAXINT, (guint)msec + 1000 * (guint)sec); + } + } + + *timeout = (gint)msec; + + return msec == 0; +} + +static gboolean +_timeout_check (GSource *source) +{ + TimeoutSource *timeout_source = (TimeoutSource *)source; + GTimeVal current_time; + + g_source_get_current_time (source, ¤t_time); + return ((timeout_source->expiration.tv_sec < current_time.tv_sec) || + ((timeout_source->expiration.tv_sec == current_time.tv_sec) && + (timeout_source->expiration.tv_usec <= current_time.tv_usec))); +} + +static gboolean +_timeout_dispatch (GSource *source, + GSourceFunc callback, + gpointer user_data) +{ + TimeoutSource *timeout_source = (TimeoutSource *)source; + + g_assert (callback != NULL); + if (callback (user_data)) + { + GTimeVal current_time; + + g_source_get_current_time (source, ¤t_time); + _timeout_set_expiration (timeout_source, ¤t_time); + + return TRUE; + } + else + return FALSE; +} + +static GSourceFuncs _timeout_funcs = { + _timeout_prepare, + _timeout_check, + _timeout_dispatch, + NULL +}; + +static GSource * +_new_timeout (guint interval, GSourceFunc function, gpointer data) +{ + GSource *source = g_source_new (&_timeout_funcs, sizeof (TimeoutSource)); + TimeoutSource *timeout_source = (TimeoutSource *)source; + GTimeVal current_time; + + timeout_source->interval = interval; + + g_get_current_time (¤t_time); + _timeout_set_expiration (timeout_source, ¤t_time); + + g_source_set_priority (source, G_PRIORITY_DEFAULT_IDLE); + + g_source_set_callback (source, function, data, NULL); + g_source_attach (source, NULL); + + return source; +} + +static void +_reset_timeout (GSource *source, guint interval) +{ + TimeoutSource *timeout_source = (TimeoutSource *)source; + GTimeVal current_time; + + timeout_source->interval = interval; + + g_get_current_time (¤t_time); + _timeout_set_expiration (timeout_source, ¤t_time); +} + +static gboolean +_update_client (App *app) +{ + app_set_busy (app, TRUE); + + shared_objects_lookup_symbols (&app->client.objects); + + app_set_blocks (app, app->client.blocks); + + _client_update_alloc_fn (&app->client); + _client_update_max_bytes (&app->client); + + call_graph_store_update (app->client.call_graph, + app, + app->client.allocators, + app->client.last); + + summary_update ((Summary *) app->summary, &app->client); + + timeline_add_datum ((Timeline *) app->timeline, &app->client, + app->client.time, app->client.allocators); + + spacetime_add_datum ((Spacetime *) app->spacetime, &app->client, + app->client.time, app->client.allocators); + app->client.last = app->client.time; + + if (app->client.pid && ! app->client.terminated) { + GtkTreeModel *model; + char client[1024]; + + if (! _get_pid_cmd (app->client.pid, + client, G_N_ELEMENTS (client))) strcpy (client, "«unknown»"); _app_set_client_name (app, client); + + model = procmap_store_new (app->client.pid); + gtk_tree_view_set_model (ensure_procmap (app), model); + g_object_unref (model); + } else { + call_graph_store_update_tree_model (app->client.call_graph); } - app_update_client (app, &app->client, time); + app_update_status (app); - return TRUE; + g_source_destroy (app->client.timeout); + app->client.timeout = NULL; + + app_set_busy (app, FALSE); + + return FALSE; } static gboolean @@ -1740,35 +1916,29 @@ lwp_events_server_cb (GIOChannel *source, App *app = data; if (condition & G_IO_IN) { - GUnixSocket *client = gnet_unix_socket_server_accept (app->lwp_events); - GIOChannel *io; - int fd; - gzFile *file; - gboolean update; + GUnixSocket *client; + gboolean update = FALSE; - gdk_window_set_cursor (app->window->window, app->busy_cursor); - gdk_flush (); + client = gnet_unix_socket_server_accept (app->lwp_events); + do { + GIOChannel *io = gnet_unix_socket_get_io_channel (client); + int fd = g_io_channel_unix_get_fd (io); + gzFile *file = gzdopen (dup (fd), "r"); - io = gnet_unix_socket_get_io_channel (client); - fd = g_io_channel_unix_get_fd (io); - file = gzdopen (dup (fd), "r"); + update |= lwp_read (file, app); + gzclose (file); - update = lwp_read (file, app); - gzclose (file); + gnet_unix_socket_delete (client); + + client = gnet_unix_socket_server_accept_nonblock (app->lwp_events); + } while (client != NULL); if (update) { - if (! app->client.terminated) { - GtkTreeModel *model = procmap_store_new (app->client.pid); - gtk_tree_view_set_model (ensure_procmap (app), model); - g_object_unref (model); - } else { - call_graph_store_update_tree_model (app->client.call_graph); - } + if (app->client.timeout) + _reset_timeout (app->client.timeout, 2000); + else + app->client.timeout = _new_timeout (2000, (GSourceFunc) _update_client, app); } - - gdk_window_set_cursor (app->window->window, NULL); - - gnet_unix_socket_delete (client); } if (condition & G_IO_HUP) @@ -2286,14 +2456,18 @@ int main file = gzdopen (dup (g_io_channel_unix_get_fd (io)), "r"); + app_set_busy (&app, TRUE); have_allocators = lwp_read (file, &app); if (have_allocators) do { + _update_client (&app); while (gtk_events_pending ()) gtk_main_iteration (); } while (lwp_read (file, &app)); + _update_client (&app); gzclose (file); g_io_channel_unref (io); + app_set_busy (&app, FALSE); } } if (have_allocators == FALSE){ diff --git a/src/client.h b/src/client.h index e3a03de..f603d9f 100644 --- a/src/client.h +++ b/src/client.h @@ -47,6 +47,7 @@ struct _client { GPid pid; gboolean terminated; + guint time; guint last; Allocator *allocators; @@ -79,6 +80,8 @@ struct _client { Chunk *perm_chunks; Chunk *block_chunks; Block *block_free_list; + + GSource *timeout; }; gpointer diff --git a/src/spacetime.c b/src/spacetime.c index a623b02..322022c 100644 --- a/src/spacetime.c +++ b/src/spacetime.c @@ -537,7 +537,7 @@ spacetime_query_tooltip (GtkWidget *widget, pretty_print_number (blocks + 40, len, blocks); text = g_strdup_printf ( - "%s: Allocated %s bytes over %s blocks.", + "%s: currently allocated %s bytes over %s blocks.", self->sorted[n].alloc_fn, bytes, blocks); gtk_tooltip_set_text (tooltip, text); g_free (text); |