Skip to content

Commit

Permalink
Add mmap table and resident page UI to memory_inspector.
Browse files Browse the repository at this point in the history
This wires-up the raw mmap dump (through memdump), introducing:
 - A new /ajax/dump/mmap endpoint to the server.
 - The HTML/JS ui to show the mmap table and the resident page list.


BUG=340294
NOTRY=true

Review URL: https://codereview.chromium.org/196973008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@256836 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
primiano@chromium.org committed Mar 13, 2014
1 parent c2d2ef9 commit 438c69e
Show file tree
Hide file tree
Showing 7 changed files with 301 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<title>Memory Inspector</title>
<link href='//fonts.googleapis.com/css?family=Coda' rel='stylesheet' type='text/css'>
<link href="//ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/themes/flick/jquery-ui.css" rel="stylesheet">
<link href="/mmap.css" rel="stylesheet" type="text/css">
<link href="/rootUi.css" rel="stylesheet" type="text/css">
<link href="/settings.css" rel="stylesheet" type="text/css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
Expand All @@ -20,6 +21,7 @@
{ packages: ['corechart', 'table', 'orgchart', 'treemap'] });
</script>
<script src="/js/devices.js"></script>
<script src="/js/mmap.js"></script>
<script src="/js/rootUi.js"></script>
<script src="/js/processes.js"></script>
<script src="/js/settings.js"></script>
Expand Down Expand Up @@ -92,19 +94,33 @@ <h2>Hierarchical view of selected snapshot</h2>
<header>
<b>Filters: </b>
<span>
Prot. flags: <input type="text" id="mm-filter-prot" />
File name: <input type="text" id="mm-filter-file" />
<input type="button" id="mm-filter-clear" value="Reset">
Prot. flags: <input type="text" id="mm-filter-prot">
File name: <input type="text" id="mm-filter-file">
<i>(Just press enter to apply filters)</i>
</span>
</header>
<header>
<b>Totals: </b>
<b>Priv dirty (Kb): </b><span id="memmaps-totals-priv-dirty">0</span>
<b>Priv clean (Kb): </b><span id="memmaps-totals-priv-clean">0</span>
<b>Shared dirty (Kb): </b><span id="memmaps-totals-shared-dirty">0</span>
<b>Shared clean (Kb): </b><span id="memmaps-totals-shared-clean">0</span>
<b>Lookup addr: </b>
<input type="text" id="mm-lookup-addr">
<span><b>Offset in mapping:</b></span>
<span id="mm-lookup-offset">0</span>
</span>
</header>
<hr>
<header>
<b>Totals [Kb]: </b>
<b>Priv dirty: </b><span id="mm-totals-priv-dirty">0</span>
<b>Priv clean: </b><span id="mm-totals-priv-clean">0</span>
<b>Shared dirty: </b><span id="mm-totals-shared-dirty">0</span>
<b>Shared clean: </b><span id="mm-totals-shared-clean">0</span>
</header>
<header>
Note: totals from this filtered table might not match the totals in the treemap, as table filtering is not hierarchical.
<b>Selected [Kb]: </b>
<b>Priv dirty: </b><span id="mm-selected-priv-dirty">0</span>
<b>Priv clean: </b><span id="mm-selected-priv-clean">0</span>
<b>Shared dirty: </b><span id="mm-selected-shared-dirty">0</span>
<b>Shared clean: </b><span id="mm-selected-shared-clean">0</span>
</header>
<div id="mm-table"></div>
</div>
Expand All @@ -130,17 +146,17 @@ <h2>Hierarchical view of selected snapshot</h2>
</div>

<div id="tabs-archive">
<input type="button" value="Refresh" id="archive-refresh" />
<input type="button" value="Analyze Memory maps" id="archive-classify_mmaps" />
<input type="button" value="Analyze Native Heap" id="archive-classify_native" />
<input type="button" value="Refresh" id="archive-refresh">
<input type="button" value="Analyze Memory maps" id="archive-classify_mmaps">
<input type="button" value="Analyze Native Heap" id="archive-classify_native">
<div id="archive">
</div>
</div>

<div id="tabs-settings">
<header>
<input type="button" value="Reload" id="settings-load" />
<input type="button" value="Store" id="settings-store" />
<input type="button" value="Reload" id="settings-load">
<input type="button" value="Store" id="settings-store">
</header>
<div id="settings-container">
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

mmap = new (function() {

this.AJAX_BASE_URL_ = '/ajax';
this.COL_START = 0;
this.COL_END = 1;
this.COL_LEN = 2;
this.COL_PROT = 3;
this.COL_PRIV_DIRTY = 4;
this.COL_PRIV_CLEAN = 5;
this.COL_SHARED_DIRTY = 6;
this.COL_SHARED_CLEAN = 7;
this.COL_FILE = 8;
this.COL_RESIDENT = 10;
this.SHOW_COLUMNS = [0, 1, 2, 3, 4, 5, 6, 7, 8];
this.PAGE_SIZE = 4096;

this.mapsData_ = null;
this.mapsTable_ = null;
this.mapsFilter_ = null;

this.onDomReady_ = function() {
$('#mm-lookup-addr').on('change', this.lookupAddress.bind(this));
$('#mm-filter-file').on('change', this.applyMapsTableFilters_.bind(this));
$('#mm-filter-prot').on('change', this.applyMapsTableFilters_.bind(this));
$('#mm-filter-clear').on('click', this.resetMapsTableFilters_.bind(this));
};

this.dumpMmaps = function(targetProcUri) {
if (!targetProcUri)
return;
webservice.ajaxRequest('/dump/mmap/' + targetProcUri,
this.onDumpAjaxResponse_.bind(this));
rootUi.showDialog('Dumping memory maps for ' + targetProcUri + '...');
};

this.onDumpAjaxResponse_ = function(data) {
$('#mm-filter-file').val('');
$('#mm-filter-prot').val('');
this.mapsData_ = new google.visualization.DataTable(data);
this.mapsFilter_ = new google.visualization.DataView(this.mapsData_);
this.mapsFilter_.setColumns(this.SHOW_COLUMNS);
this.mapsTable_ = new google.visualization.Table($('#mm-table')[0]);
google.visualization.events.addListener(
this.mapsTable_, 'select', this.onMmapTableRowSelect_.bind(this));
$('#mm-table').on('dblclick', this.onMmapTableDblClick_.bind(this));
rootUi.showTab('mm-table');
this.applyMapsTableFilters_();
rootUi.hideDialog();
};

this.applyMapsTableFilters_ = function() {
// Filters the rows according to the user-provided file and prot regexps.
if (!this.mapsFilter_)
return;

var fileRx = $('#mm-filter-file').val();
var protRx = $('#mm-filter-prot').val();
var rows = [];
var totPrivDirty = 0;
var totPrivClean = 0;
var totSharedDirty = 0;
var totSharedClean = 0;

for (var row = 0; row < this.mapsData_.getNumberOfRows(); ++row) {
mappedFile = this.mapsData_.getValue(row, this.COL_FILE);
protFlags = this.mapsData_.getValue(row, this.COL_PROT);
if (!mappedFile.match(fileRx) || !protFlags.match(protRx))
continue;
rows.push(row);
totPrivDirty += this.mapsData_.getValue(row, this.COL_PRIV_DIRTY);
totPrivClean += this.mapsData_.getValue(row, this.COL_PRIV_CLEAN);
totSharedDirty += this.mapsData_.getValue(row,this.COL_SHARED_DIRTY);
totSharedClean += this.mapsData_.getValue(row, this.COL_SHARED_CLEAN);
}
this.mapsFilter_.setRows(rows);
this.mapsTable_.draw(this.mapsFilter_);
$('#mm-totals-priv-dirty').text(totPrivDirty);
$('#mm-totals-priv-clean').text(totPrivClean);
$('#mm-totals-shared-dirty').text(totSharedDirty);
$('#mm-totals-shared-clean').text(totSharedClean);
};

this.resetMapsTableFilters_ = function() {
$('#mm-filter-file').val('');
$('#mm-filter-prot').val('');
this.applyMapsTableFilters_();
};

this.onMmapTableRowSelect_ = function() {
// Update the memory totals for the selected rows.
if (!this.mapsFilter_)
return;

var totPrivDirty = 0;
var totPrivClean = 0;
var totSharedDirty = 0;
var totSharedClean = 0;

this.mapsTable_.getSelection().forEach(function(sel) {
var row = sel.row;
totPrivDirty += this.mapsFilter_.getValue(row, this.COL_PRIV_DIRTY);
totPrivClean += this.mapsFilter_.getValue(row, this.COL_PRIV_CLEAN);
totSharedDirty += this.mapsFilter_.getValue(row,this.COL_SHARED_DIRTY);
totSharedClean += this.mapsFilter_.getValue(row, this.COL_SHARED_CLEAN);
}, this);
$('#mm-selected-priv-dirty').text(totPrivDirty);
$('#mm-selected-priv-clean').text(totPrivClean);
$('#mm-selected-shared-dirty').text(totSharedDirty);
$('#mm-selected-shared-clean').text(totSharedClean);
};

this.onMmapTableDblClick_ = function() {
// Show resident pages for the selected mapping.
var PAGES_PER_ROW = 16;

if (!this.mapsData_)
return;

var sel = this.mapsTable_.getSelection();
if (sel.length == 0)
return;

// |sel| returns the row index in the current view, which might be filtered.
// Need to walk back in the mapsFilter_.getViewRows to get the actual row
// index in the original table.
var row = this.mapsFilter_.getViewRows()[sel[0].row];
var arr = JSON.parse(this.mapsData_.getValue(row, this.COL_RESIDENT));
var table = $('<table class="mm-resident-table"/>');
var curRow = $('<tr/>');
table.append(curRow);

for (var i = 0; i < arr.length; ++i) {
for (var j = 0; j < 8; ++j) {
var pageIdx = i * 8 + j;
var resident = !!(arr[i] & (1 << j));
if (pageIdx % PAGES_PER_ROW == 0) {
curRow = $('<tr/>');
table.append(curRow);
}
var hexAddr = (pageIdx * this.PAGE_SIZE).toString(16);
var cell = $('<td/>').text(hexAddr);
if (resident)
cell.addClass('resident')
curRow.append(cell);
}
}
rootUi.showDialog(table, 'Resident page list');
};

this.lookupAddress = function() {
// Looks up the user-provided address in the mmap table and highlights the
// row containing the map (if found).
if (!this.mapsData_)
return;

addr = parseInt($('#mm-lookup-addr').val(), 16);
$('#mm-lookup-offset').text('');
if (!addr)
return;

this.resetMapsTableFilters_();

var lbound = 0;
var ubound = this.mapsData_.getNumberOfRows() - 1;
while (lbound <= ubound) {
var row = ((lbound + ubound) / 2) >> 0;
var start = parseInt(this.mapsData_.getValue(row, this.COL_START), 16);
var end = parseInt(this.mapsData_.getValue(row, this.COL_END), 16);
if (addr < start){
ubound = row - 1;
}
else if (addr > end) {
lbound = row + 1;
}
else {
$('#mm-lookup-offset').text((addr - start).toString(16));
this.mapsTable_.setSelection([{row: row, column: null}]);
// Scroll to row.
$('#wrapper').scrollTop(
$('#mm-table .google-visualization-table-tr-sel').offset().top);
break;
}
}
};

$(document).ready(this.onDomReady_.bind(this));

})();
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ this.refreshPsTable = function() {
this.psTable_ = new google.visualization.Table($('#ps-table')[0]);
google.visualization.events.addListener(
this.psTable_, 'select', this.onPsTableRowSelect_.bind(this));
$('#ps-table').on('dblclick', this.onPsTableDblClick_.bind(this));
};

var showAllParam = $('#ps-show_all').prop('checked') ? '?all=1' : '';
Expand Down Expand Up @@ -71,6 +72,10 @@ this.onPsTableRowSelect_ = function() {
this.startSelectedProcessStats();
};

this.onPsTableDblClick_ = function() {
mmap.dumpMmaps(this.getSelectedProcessURI());
};

this.onPsAjaxResponse_ = function(data) {
// Redraw table preserving sorting info.
var sort = this.psTable_.getSortInfo() || {column: -1, ascending: false};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,23 @@ this.showTab = function(tabId) {
$('#tabs').tabs('option', 'active', index - 1);
};

this.showDialog = function(message) {
this.showDialog = function(content, title) {
var dialog = $("#message_dialog");
title = title || '';
if (dialog.length == 0) {
dialog = $('<div id="message_dialog"/>');
$('body').append(dialog);
}
$("#message_dialog").text(message).dialog({ modal: true });
if (typeof(content) == 'string')
dialog.empty().text(content);
else
dialog.empty().append(content); // Assume is a jQuery DOM object.

dialog.dialog({modal: true, title: title, height:'auto', width:'auto'});
};

this.hideDialog = function() {
$("#message_dialog").dialog('close');
};

$(document).ready(this.onDomReady_.bind(this));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* Copyright 2014 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */

.mm-resident-table {
border: 1px solid #999;
}

.mm-resident-table td {
padding: 0.2em;
}

.mm-resident-table td.resident {
background: lightgreen;
}

Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,7 @@ input[type="text"] {
display: inline-block;
height: 20em;
}

table {
-webkit-user-select: none;
}
Loading

0 comments on commit 438c69e

Please sign in to comment.