From 08b8b39a5dc5d60db81ea8b1e1d6f6c2f6ff4c13 Mon Sep 17 00:00:00 2001 From: "Owen W. Taylor" Date: Tue, 11 May 2010 15:53:55 -0400 Subject: [PATCH] Add simple malloc statistics and metrics Add some basic statistics for allocated memory based on mallinfo(), and use that to define two metrics: usedAfterOverview: bytes used after the overview is shown once leakedAfterOverview: additional bytes used when the overview is shown a second time. https://bugzilla.gnome.org/show_bug.cgi?id=618189 --- js/perf/core.js | 30 +++++++++++++++++++++++-- js/ui/scripting.js | 9 ++++++++ src/gnome-shell-plugin.c | 48 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 2 deletions(-) diff --git a/js/perf/core.js b/js/perf/core.js index f69809664..7fa74bcbf 100644 --- a/js/perf/core.js +++ b/js/perf/core.js @@ -12,7 +12,9 @@ let METRIC_DESCRIPTIONS = { overviewLatencyFirst: "Time to first frame after triggering overview, first time", overviewFramesFirst: "Frames displayed when going to overview, first time", overviewLatencySubsequent: "Time to first frame after triggering overview, second time", - overviewFramesSubsequent: "Frames displayed when going to overview, second time" + overviewFramesSubsequent: "Frames displayed when going to overview, second time", + usedAfterOverview: "Malloc'ed bytes after the overview is shown once", + leakedAfterOverview: "Additional malloc'ed bytes the second time the overview is shown" }; let METRICS = { @@ -21,6 +23,7 @@ let METRICS = { function run() { Scripting.defineScriptEvent("overviewShowStart", "Starting to show the overview"); Scripting.defineScriptEvent("overviewShowDone", "Overview finished showing"); + Scripting.defineScriptEvent("afterShowHide", "After a show/hide cycle for the overview"); yield Scripting.sleep(1000); yield Scripting.waitLeisure(); @@ -29,8 +32,14 @@ function run() { Main.overview.show(); yield Scripting.waitLeisure(); Scripting.scriptEvent('overviewShowDone'); + Main.overview.hide(); yield Scripting.waitLeisure(); + + global.gc(); + yield Scripting.sleep(1000); + Scripting.collectStatistics(); + Scripting.scriptEvent('afterShowHide'); } } @@ -38,6 +47,9 @@ let showingOverview = false; let overviewShowStart; let overviewFrames; let overviewLatency; +let mallocUsedSize = 0; +let overviewShowCount = 0; +let firstOverviewUsedSize; function script_overviewShowStart(time) { showingOverview = true; @@ -48,7 +60,9 @@ function script_overviewShowStart(time) { function script_overviewShowDone(time) { showingOverview = false; - if (!('overviewLatencyFirst' in METRICS)) { + overviewShowCount++; + + if (overviewShowCount == 1) { METRICS.overviewLatencyFirst = overviewLatency; METRICS.overviewFramesFirst = overviewFrames; } else { @@ -57,6 +71,18 @@ function script_overviewShowDone(time) { } } +function script_afterShowHide(time) { + if (overviewShowCount == 1) { + METRICS.usedAfterOverview = mallocUsedSize; + } else { + METRICS.leakedAfterOverview = mallocUsedSize - METRICS.usedAfterOverview; + } +} + +function malloc_usedSize(time, bytes) { + mallocUsedSize = bytes; +} + function clutter_stagePaintDone(time) { if (showingOverview) { if (overviewFrames == 0) diff --git a/js/ui/scripting.js b/js/ui/scripting.js index 7e34175a3..2e3520e02 100644 --- a/js/ui/scripting.js +++ b/js/ui/scripting.js @@ -94,6 +94,15 @@ function scriptEvent(name) { Shell.PerfLog.get_default().event("script." + name); } +/** + * collectStatistics + * + * Convenience function to trigger statistics collection + */ +function collectStatistics() { + Shell.PerfLog.get_default().collect_statistics(); +} + function _step(g, finish, onError) { try { let waitFunction = g.next(); diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c index 83942beb7..36e2bdf72 100644 --- a/src/gnome-shell-plugin.c +++ b/src/gnome-shell-plugin.c @@ -38,12 +38,14 @@ #include #include #include +#include #include #include #include "display.h" #include "shell-global-private.h" +#include "shell-perf-log.h" #include "shell-wm.h" #include "st.h" @@ -232,6 +234,50 @@ settings_notify_cb (GtkSettings *settings, update_font_options (settings); } +static void +malloc_statistics_callback (ShellPerfLog *perf_log, + gpointer data) +{ + struct mallinfo info = mallinfo (); + + shell_perf_log_update_statistic_i (perf_log, + "malloc.arenaSize", + info.arena); + shell_perf_log_update_statistic_i (perf_log, + "malloc.mmapSize", + info.hblkhd); + shell_perf_log_update_statistic_i (perf_log, + "malloc.usedSize", + info.uordblks); +} + +static void +add_statistics (GnomeShellPlugin *shell_plugin) +{ + ShellPerfLog *perf_log = shell_perf_log_get_default (); + + /* For probably historical reasons, mallinfo() defines the returned values, + * even those in bytes as int, not size_t. We're determined not to use + * more than 2G of malloc'ed memory, so are OK with that. + */ + shell_perf_log_define_statistic (perf_log, + "malloc.arenaSize", + "Amount of memory allocated by malloc() with brk(), in bytes", + "i"); + shell_perf_log_define_statistic (perf_log, + "malloc.mmapSize", + "Amount of memory allocated by malloc() with mmap(), in bytes", + "i"); + shell_perf_log_define_statistic (perf_log, + "malloc.usedSize", + "Amount of malloc'ed memory currently in use", + "i"); + + shell_perf_log_add_statistics_callback (perf_log, + malloc_statistics_callback, + NULL, NULL); +} + static void gnome_shell_plugin_start (MutterPlugin *plugin) { @@ -280,6 +326,8 @@ gnome_shell_plugin_start (MutterPlugin *plugin) _shell_global_set_plugin (global, MUTTER_PLUGIN(shell_plugin)); _shell_global_set_gjs_context (global, shell_plugin->gjs_context); + add_statistics (shell_plugin); + if (!gjs_context_eval (shell_plugin->gjs_context, "const Main = imports.ui.main; Main.start();", -1,