diff --git a/js/ui/lookingGlass.js b/js/ui/lookingGlass.js index db3291f87..d7d50def9 100644 --- a/js/ui/lookingGlass.js +++ b/js/ui/lookingGlass.js @@ -582,6 +582,53 @@ ErrorLog.prototype = { } }; +function Memory() { + this._init(); +} + +Memory.prototype = { + _init: function() { + this.actor = new St.BoxLayout({ vertical: true }); + this._glibc_uordblks = new St.Label(); + this.actor.add(this._glibc_uordblks); + + this._js_bytes = new St.Label(); + this.actor.add(this._js_bytes); + + this._gjs_boxed = new St.Label(); + this.actor.add(this._gjs_boxed); + + this._gjs_gobject = new St.Label(); + this.actor.add(this._gjs_gobject); + + this._gjs_function = new St.Label(); + this.actor.add(this._gjs_function); + + this._gjs_closure = new St.Label(); + this.actor.add(this._gjs_closure); + + this._gcbutton = new St.Button({ label: 'Full GC', + style_class: 'lg-obj-inspector-button' }); + this._gcbutton.connect('clicked', Lang.bind(this, function () { global.gc(); this._renderText(); })); + this.actor.add(this._gcbutton, { x_align: St.Align.START, + x_fill: false }); + + this.actor.connect('notify::mapped', Lang.bind(this, this._renderText)); + }, + + _renderText: function() { + if (!this.actor.mapped) + return; + let memInfo = global.get_memory_info(); + this._glibc_uordblks.text = 'glibc_uordblks: ' + memInfo.glibc_uordblks; + this._js_bytes.text = 'js bytes: ' + memInfo.js_bytes; + this._gjs_boxed.text = 'gjs_boxed: ' + memInfo.gjs_boxed; + this._gjs_gobject.text = 'gjs_gobject: ' + memInfo.gjs_gobject; + this._gjs_function.text = 'gjs_function: ' + memInfo.gjs_function; + this._gjs_closure.text = 'gjs_closure: ' + memInfo.gjs_closure; + } +}; + function Extensions() { this._init(); } @@ -764,6 +811,9 @@ LookingGlass.prototype = { this._errorLog = new ErrorLog(); notebook.appendPage('Errors', this._errorLog.actor); + this._memory = new Memory(); + notebook.appendPage('Memory', this._memory.actor); + this._extensions = new Extensions(); notebook.appendPage('Extensions', this._extensions.actor); diff --git a/src/shell-global.c b/src/shell-global.c index e18dbc998..84b35db75 100644 --- a/src/shell-global.c +++ b/src/shell-global.c @@ -25,6 +25,11 @@ #include #include +/* Memory report bits */ +#ifdef HAVE_MALLINFO +#include +#endif + #include "shell-enum-types.h" #include "shell-global-private.h" #include "shell-jsapi-compat-private.h" @@ -1126,6 +1131,38 @@ shell_global_maybe_gc (ShellGlobal *global) gjs_context_maybe_gc (global->js_context); } +/** + * shell_global_get_memory_info: + * @global: + * @meminfo: (out caller-allocates): Output location for memory information + * + * Load process-global data about memory usage. + */ +void +shell_global_get_memory_info (ShellGlobal *global, + ShellMemoryInfo *meminfo) +{ + JSContext *context; + + memset (meminfo, 0, sizeof (meminfo)); +#ifdef HAVE_MALLINFO + { + struct mallinfo info = mallinfo (); + meminfo->glibc_uordblks = info.uordblks; + } +#endif + + context = gjs_context_get_native_context (global->js_context); + + meminfo->js_bytes = JS_GetGCParameter (JS_GetRuntime (context), JSGC_BYTES); + + meminfo->gjs_boxed = (unsigned int) gjs_counter_boxed.value; + meminfo->gjs_gobject = (unsigned int) gjs_counter_object.value; + meminfo->gjs_function = (unsigned int) gjs_counter_function.value; + meminfo->gjs_closure = (unsigned int) gjs_counter_closure.value; +} + + /** * shell_global_notify_error: * @global: a #ShellGlobal diff --git a/src/shell-global.h b/src/shell-global.h index c9d4f7c6f..d6f4c33a7 100644 --- a/src/shell-global.h +++ b/src/shell-global.h @@ -90,6 +90,21 @@ void shell_global_get_pointer (ShellGlobal *global, void shell_global_gc (ShellGlobal *global); void shell_global_maybe_gc (ShellGlobal *global); +typedef struct { + guint glibc_uordblks; + + guint js_bytes; + + guint gjs_boxed; + guint gjs_gobject; + guint gjs_function; + guint gjs_closure; +} ShellMemoryInfo; + +void shell_global_get_memory_info (ShellGlobal *global, + ShellMemoryInfo *meminfo); + + gboolean shell_global_set_property_mutable (ShellGlobal *global, const char *object, const char *property,