summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2007-12-20 12:50:14 +0000
committerChris Wilson <chris@chris-wilson.co.uk>2007-12-20 12:50:14 +0000
commit650d06b4d317fa47ae0882c9908de95d9501ff49 (patch)
treedc69de858a020cf06ed835239b4fda14b977ec88
parente64a19fe9511e8f9a76d11d1c933e4796a430014 (diff)
Delay updating the widgets to reduce overhead whilst monitoring clients.
-rw-r--r--src/app.c274
-rw-r--r--src/client.h3
-rw-r--r--src/spacetime.c2
3 files changed, 228 insertions, 51 deletions
diff --git a/src/app.c b/src/app.c
index b6b37f4..aae3465 100644
--- a/src/app.c
+++ b/src/app.c
@@ -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, &current_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, &current_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, &current_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, &current_time);
+ _timeout_set_expiration (timeout_source, &current_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 (&current_time);
+ _timeout_set_expiration (timeout_source, &current_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 (&current_time);
+ _timeout_set_expiration (timeout_source, &current_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);