You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by bm...@apache.org on 2014/01/22 22:42:00 UTC
[7/8] git commit: Added a Top abstraction to the webui.
Added a Top abstraction to the webui.
This allows the webui to asynchronously update resource consumption
information without every Slave controller having to implement this.
Review: https://reviews.apache.org/r/13606
Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/ed3f0438
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/ed3f0438
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/ed3f0438
Branch: refs/heads/master
Commit: ed3f0438d56b007999769152c820c3585cfa540d
Parents: 8b095fe
Author: Benjamin Mahler <bm...@twitter.com>
Authored: Thu Jul 25 14:50:41 2013 -0700
Committer: Benjamin Mahler <bm...@twitter.com>
Committed: Wed Jan 22 13:03:11 2014 -0800
----------------------------------------------------------------------
src/webui/master/static/js/controllers.js | 279 ++++++++++------------
src/webui/master/static/js/services.js | 186 +++++++++++++++
src/webui/master/static/slave.html | 18 +-
src/webui/master/static/slave_executor.html | 6 +-
src/webui/master/static/slave_framework.html | 8 +-
5 files changed, 332 insertions(+), 165 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/mesos/blob/ed3f0438/src/webui/master/static/js/controllers.js
----------------------------------------------------------------------
diff --git a/src/webui/master/static/js/controllers.js b/src/webui/master/static/js/controllers.js
index 01fe64c..afb24fb 100644
--- a/src/webui/master/static/js/controllers.js
+++ b/src/webui/master/static/js/controllers.js
@@ -381,7 +381,9 @@
mesosApp.controller('SlavesCtrl', function() {});
- mesosApp.controller('SlaveCtrl', function($dialog, $scope, $routeParams, $http, $q) {
+ mesosApp.controller('SlaveCtrl', [
+ '$dialog', '$scope', '$routeParams', '$http', '$q', '$timeout', 'top',
+ function($dialog, $scope, $routeParams, $http, $q, $timeout, $top) {
$scope.slave_id = $routeParams.slave_id;
var update = function() {
@@ -408,56 +410,55 @@
}
};
- var usageRequest = $http.jsonp(
- 'http://' + host + '/monitor/usage.json?jsonp=JSON_CALLBACK');
-
- var stateRequest = $http.jsonp(
- 'http://' + host + '/' + id + '/state.json?jsonp=JSON_CALLBACK');
-
- $q.all([usageRequest, stateRequest]).then(function (responses) {
- $scope.monitor = responses[0].data;
- $scope.state = responses[1].data;
-
- $scope.slave = {};
- $scope.slave.frameworks = {};
- $scope.slave.completed_frameworks = {};
-
- $scope.slave.staging_tasks = 0;
- $scope.slave.starting_tasks = 0;
- $scope.slave.running_tasks = 0;
+ // Set up polling for the monitor if this is the first update.
+ if (!$top.started()) {
+ $top.start(host, $scope);
+ }
- // Computes framework stats by setting new attributes on the 'framework'
- // object.
- function computeFrameworkStats(framework) {
- framework.num_tasks = 0;
- framework.cpus = 0;
- framework.mem = 0;
+ $http.jsonp('http://' + host + '/' + id + '/state.json?jsonp=JSON_CALLBACK')
+ .success(function (response) {
+ $scope.state = response;
+
+ $scope.slave = {};
+ $scope.slave.frameworks = {};
+ $scope.slave.completed_frameworks = {};
+
+ $scope.slave.staging_tasks = 0;
+ $scope.slave.starting_tasks = 0;
+ $scope.slave.running_tasks = 0;
+
+ // Computes framework stats by setting new attributes on the 'framework'
+ // object.
+ function computeFrameworkStats(framework) {
+ framework.num_tasks = 0;
+ framework.cpus = 0;
+ framework.mem = 0;
+
+ _.each(framework.executors, function(executor) {
+ framework.num_tasks += _.size(executor.tasks);
+ framework.cpus += executor.resources.cpus;
+ framework.mem += executor.resources.mem;
+ });
+ }
- _.each(framework.executors, function(executor) {
- framework.num_tasks += _.size(executor.tasks);
- framework.cpus += executor.resources.cpus;
- framework.mem += executor.resources.mem;
+ // Compute framework stats and update slave's mappings of those
+ // frameworks.
+ _.each($scope.state.frameworks, function(framework) {
+ $scope.slave.frameworks[framework.id] = framework;
+ computeFrameworkStats(framework);
});
- }
- // Compute framework stats and update slave's mappings of those
- // frameworks.
- _.each($scope.state.frameworks, function(framework) {
- $scope.slave.frameworks[framework.id] = framework;
- computeFrameworkStats(framework);
- });
+ _.each($scope.state.completed_frameworks, function(framework) {
+ $scope.slave.completed_frameworks[framework.id] = framework;
+ computeFrameworkStats(framework);
+ });
- _.each($scope.state.completed_frameworks, function(framework) {
- $scope.slave.completed_frameworks[framework.id] = framework;
- computeFrameworkStats(framework);
+ $('#slave').show();
+ })
+ .error(function(reason) {
+ $scope.alert_message = 'Failed to get slave usage / state: ' + reason;
+ $('#alert').show();
});
-
- $('#slave').show();
- },
- function (reason) {
- $scope.alert_message = 'Failed to get slave usage / state: ' + reason;
- $('#alert').show();
- });
};
if ($scope.state) {
@@ -466,10 +467,12 @@
var removeListener = $scope.$on('state_updated', update);
$scope.$on('$routeChangeStart', removeListener);
- });
+ }]);
- mesosApp.controller('SlaveFrameworkCtrl', function($scope, $routeParams, $http, $q) {
+ mesosApp.controller('SlaveFrameworkCtrl', [
+ '$scope', '$routeParams', '$http', '$q', '$timeout', 'top',
+ function($scope, $routeParams, $http, $q, $timeout, $top) {
$scope.slave_id = $routeParams.slave_id;
$scope.framework_id = $routeParams.framework_id;
@@ -485,72 +488,49 @@
var id = pid.substring(0, pid.indexOf('@'));
var host = hostname + ":" + pid.substring(pid.lastIndexOf(':') + 1);
- var usageRequest = $http.jsonp(
- 'http://' + host + '/monitor/usage.json?jsonp=JSON_CALLBACK');
-
- var stateRequest = $http.jsonp(
- 'http://' + host + '/' + id + '/state.json?jsonp=JSON_CALLBACK');
-
- $q.all([usageRequest, stateRequest]).then(function (responses) {
- var monitor = responses[0].data;
- $scope.state = responses[1].data;
+ // Set up polling for the monitor if this is the first update.
+ if (!$top.started()) {
+ $top.start(host, $scope);
+ }
- $scope.slave = {};
+ $http.jsonp('http://' + host + '/' + id + '/state.json?jsonp=JSON_CALLBACK')
+ .success(function (response) {
+ $scope.state = response;
- function matchFramework(framework) {
- return $scope.framework_id === framework.id;
- }
+ $scope.slave = {};
- // Find the framework; it's either active or completed.
- $scope.framework =
- _.find($scope.state.frameworks, matchFramework) ||
- _.find($scope.state.completed_frameworks, matchFramework);
-
- if (!$scope.framework) {
- $scope.alert_message = 'No framework found with ID: ' + $routeParams.framework_id;
- $('#alert').show();
- return;
- }
+ function matchFramework(framework) {
+ return $scope.framework_id === framework.id;
+ }
- // Compute the framework stats.
- $scope.framework.num_tasks = 0;
- $scope.framework.cpus = 0;
- $scope.framework.mem = 0;
+ // Find the framework; it's either active or completed.
+ $scope.framework =
+ _.find($scope.state.frameworks, matchFramework) ||
+ _.find($scope.state.completed_frameworks, matchFramework);
- _.each($scope.framework.executors, function(executor) {
- $scope.framework.num_tasks += _.size(executor.tasks);
- $scope.framework.cpus += executor.resources.cpus;
- $scope.framework.mem += executor.resources.mem;
- });
+ if (!$scope.framework) {
+ $scope.alert_message = 'No framework found with ID: ' + $routeParams.framework_id;
+ $('#alert').show();
+ return;
+ }
- // Index the monitoring data.
- $scope.monitor = {};
+ // Compute the framework stats.
+ $scope.framework.num_tasks = 0;
+ $scope.framework.cpus = 0;
+ $scope.framework.mem = 0;
- $scope.framework.resource_usage = {};
- $scope.framework.resource_usage["cpu_time"] = 0.0;
- $scope.framework.resource_usage["cpu_usage"] = 0.0;
- $scope.framework.resource_usage["memory_rss"] = 0.0;
+ _.each($scope.framework.executors, function(executor) {
+ $scope.framework.num_tasks += _.size(executor.tasks);
+ $scope.framework.cpus += executor.resources.cpus;
+ $scope.framework.mem += executor.resources.mem;
+ });
- _.each(monitor, function(executor) {
- if (!$scope.monitor[executor.framework_id]) {
- $scope.monitor[executor.framework_id] = {};
- }
- $scope.monitor[executor.framework_id][executor.executor_id] = executor;
-
- $scope.framework.resource_usage["cpu_time"] +=
- executor.resource_usage.cpu_time;
- $scope.framework.resource_usage["cpu_usage"] +=
- executor.resource_usage.cpu_usage;
- $scope.framework.resource_usage["memory_rss"] +=
- executor.resource_usage.memory_rss;
+ $('#slave').show();
+ })
+ .error(function (reason) {
+ $scope.alert_message = 'Failed to get slave usage / state: ' + reason;
+ $('#alert').show();
});
-
- $('#slave').show();
- },
- function (reason) {
- $scope.alert_message = 'Failed to get slave usage / state: ' + reason;
- $('#alert').show();
- });
};
if ($scope.state) {
@@ -559,10 +539,12 @@
var removeListener = $scope.$on('state_updated', update);
$scope.$on('$routeChangeStart', removeListener);
- });
+ }]);
- mesosApp.controller('SlaveExecutorCtrl', function($scope, $routeParams, $http, $q) {
+ mesosApp.controller('SlaveExecutorCtrl', [
+ '$scope', '$routeParams', '$http', '$q', '$timeout', 'top',
+ function($scope, $routeParams, $http, $q, $timeout, $top) {
$scope.slave_id = $routeParams.slave_id;
$scope.framework_id = $routeParams.framework_id;
$scope.executor_id = $routeParams.executor_id;
@@ -579,64 +561,53 @@
var id = pid.substring(0, pid.indexOf('@'));
var host = hostname + ":" + pid.substring(pid.lastIndexOf(':') + 1);
- var usageRequest = $http.jsonp(
- 'http://' + host + '/monitor/usage.json?jsonp=JSON_CALLBACK');
+ // Set up polling for the monitor if this is the first update.
+ if (!$top.started()) {
+ $top.start(host, $scope);
+ }
- var stateRequest = $http.jsonp(
- 'http://' + host + '/' + id + '/state.json?jsonp=JSON_CALLBACK');
+ $http.jsonp('http://' + host + '/' + id + '/state.json?jsonp=JSON_CALLBACK')
+ .success(function (response) {
+ $scope.state = response;
- $q.all([usageRequest, stateRequest]).then(function (responses) {
- var monitor = responses[0].data;
- $scope.state = responses[1].data;
+ $scope.slave = {};
- $scope.slave = {};
+ function matchFramework(framework) {
+ return $scope.framework_id === framework.id;
+ }
- function matchFramework(framework) {
- return $scope.framework_id === framework.id;
- }
+ // Find the framework; it's either active or completed.
+ $scope.framework =
+ _.find($scope.state.frameworks, matchFramework) ||
+ _.find($scope.state.completed_frameworks, matchFramework);
- // Find the framework; it's either active or completed.
- $scope.framework =
- _.find($scope.state.frameworks, matchFramework) ||
- _.find($scope.state.completed_frameworks, matchFramework);
+ if (!$scope.framework) {
+ $scope.alert_message = 'No framework found with ID: ' + $routeParams.framework_id;
+ $('#alert').show();
+ return;
+ }
- if (!$scope.framework) {
- $scope.alert_message = 'No framework found with ID: ' + $routeParams.framework_id;
- $('#alert').show();
- return;
- }
+ function matchExecutor(executor) {
+ return $scope.executor_id === executor.id;
+ }
- function matchExecutor(executor) {
- return $scope.executor_id === executor.id;
- }
+ // Look for the executor; it's either active or completed.
+ $scope.executor =
+ _.find($scope.framework.executors, matchExecutor) ||
+ _.find($scope.framework.completed_executors, matchExecutor);
- // Look for the executor; it's either active or completed.
- $scope.executor =
- _.find($scope.framework.executors, matchExecutor) ||
- _.find($scope.framework.completed_executors, matchExecutor);
+ if (!$scope.executor) {
+ $scope.alert_message = 'No executor found with ID: ' + $routeParams.executor_id;
+ $('#alert').show();
+ return;
+ }
- if (!$scope.executor) {
- $scope.alert_message = 'No executor found with ID: ' + $routeParams.executor_id;
+ $('#slave').show();
+ })
+ .error(function (reason) {
+ $scope.alert_message = 'Failed to get slave usage / state: ' + reason;
$('#alert').show();
- return;
- }
-
- // Index the monitoring data.
- $scope.monitor = {};
-
- _.each(monitor, function(executor) {
- if (!$scope.monitor[executor.framework_id]) {
- $scope.monitor[executor.framework_id] = {};
- }
- $scope.monitor[executor.framework_id][executor.executor_id] = executor;
});
-
- $('#slave').show();
- },
- function (reason) {
- $scope.alert_message = 'Failed to get slave usage / state: ' + reason;
- $('#alert').show();
- });
};
if ($scope.state) {
@@ -645,7 +616,7 @@
var removeListener = $scope.$on('state_updated', update);
$scope.$on('$routeChangeStart', removeListener);
- });
+ }]);
// Reroutes a request like
http://git-wip-us.apache.org/repos/asf/mesos/blob/ed3f0438/src/webui/master/static/js/services.js
----------------------------------------------------------------------
diff --git a/src/webui/master/static/js/services.js b/src/webui/master/static/js/services.js
index 122519a..8403aad 100644
--- a/src/webui/master/static/js/services.js
+++ b/src/webui/master/static/js/services.js
@@ -105,4 +105,190 @@
}
};
}]);
+
+ function Statistics() {
+ this.cpus_user_time_secs = 0.0;
+ this.cpus_user_usage = 0.0;
+ this.cpus_system_time_secs = 0.0;
+ this.cpus_system_usage = 0.0;
+ this.cpus_limit = 0.0;
+ this.cpus_total_usage = 0.0;
+ this.mem_rss_bytes = 0.0;
+ this.mem_limit_bytes = 0.0;
+ }
+
+ Statistics.prototype.add = function(statistics) {
+ this.cpus_user_time_secs += statistics.cpus_user_time_secs;
+ this.cpus_system_time_secs += statistics.cpus_system_time_secs;
+ this.cpus_total_usage += statistics.cpus_total_usage;
+ this.cpus_limit += statistics.cpus_limit;
+ this.mem_rss_bytes += statistics.mem_rss_bytes;
+ this.mem_limit_bytes += statistics.mem_limit_bytes;
+
+ // Set instead of add the timestamp since this is an instantaneous view of
+ // CPU usage since the last poll.
+ this.timestamp = statistics.timestamp;
+ };
+
+ Statistics.prototype.diffUsage = function(statistics) {
+ this.cpus_user_usage =
+ (this.cpus_user_time_secs - statistics.cpus_user_time_secs) /
+ (this.timestamp - statistics.timestamp);
+ this.cpus_system_usage =
+ (this.cpus_system_time_secs - statistics.cpus_system_time_secs) /
+ (this.timestamp - statistics.timestamp);
+ this.cpus_total_usage = this.cpus_user_usage + this.cpus_system_usage;
+ };
+
+ Statistics.parseJSON = function(json) {
+ var statistics = new Statistics();
+ statistics.add(json);
+ return statistics;
+ };
+
+ // Top is an abstraction for polling a slave's monitoring endpoint to
+ // periodically update the monitoring data. It also computes CPU usage.
+ // This places the following data in scope.monitor:
+ //
+ // $scope.monitor = {
+ // "statistics": <stats>,
+ // "frameworks": {
+ // <framework_id>: {
+ // "statistics": <stats>,
+ // "executors": {
+ // <executor_id>: {
+ // "executor_id": <executor_id>,
+ // "framework_id": <framework_id>,
+ // "executor_name: <executor_name>,
+ // "source": <source>,
+ // "statistics": <stats>,
+ // }
+ // }
+ // }
+ // }
+ // }
+ //
+ // To obtain slave statistics:
+ // $scope.monitor.statistics
+ //
+ // To obtain a framework's statistics:
+ // $scope.monitor.frameworks[<framework_id>].statistics
+ //
+ // To obtain an executor's statistics:
+ // $scope.monitor.frameworks[<framework_id>].executors[<executor_id>].statistics
+ //
+ // In the above, <stats> is the following object:
+ //
+ // {
+ // cpus_user_time_secs: value,
+ // cpus_user_usage: value, // Once computed.
+ // cpus_system_time_secs: value,
+ // cpus_system_usage: value, // Once computed.
+ // mem_limit_bytes: value,
+ // mem_rss_bytes: value,
+ // }
+ //
+ // TODO(bmahler): The complexity of the monitor object is mostly in place
+ // until we have path-params on the monitoring endpoint to request
+ // statistics for the slave, or for a specific framework / executor.
+ //
+ // Arguments:
+ // http: $http service from Angular.
+ // timeout: $timeout service from Angular.
+ function Top($http, $timeout) {
+ this.http = $http;
+ this.timeout = $timeout;
+ }
+
+ Top.prototype.poll = function() {
+ this.http.jsonp(this.endpoint)
+
+ // Success! Parse the response.
+ .success(angular.bind(this, this.parseResponse))
+
+ // Do not continue polling on error.
+ .error(angular.noop);
+ };
+
+ Top.prototype.parseResponse = function(response) {
+ var that = this;
+ var monitor = {
+ frameworks: {},
+ statistics: new Statistics()
+ };
+
+ response.forEach(function(executor) {
+ var executor_id = executor.executor_id;
+ var framework_id = executor.framework_id;
+ var current = executor.statistics =
+ Statistics.parseJSON(executor.statistics);
+
+ current.cpus_user_usage = 0.0;
+ current.cpus_system_usage = 0.0;
+
+ // Compute CPU usage if possible.
+ if (that.scope.monitor &&
+ that.scope.monitor.frameworks[framework_id] &&
+ that.scope.monitor.frameworks[framework_id].executors[executor_id]) {
+ var previous = that.scope.monitor.frameworks[framework_id].executors[executor_id].statistics;
+ current.diffUsage(previous);
+ }
+
+ // Index the data.
+ if (!monitor.frameworks[executor.framework_id]) {
+ monitor.frameworks[executor.framework_id] = {
+ executors: {},
+ statistics: new Statistics()
+ };
+ }
+
+ // Aggregate these statistics into the slave and framework statistics.
+ monitor.statistics.add(current);
+ monitor.frameworks[executor.framework_id].statistics.add(current);
+ monitor.frameworks[executor.framework_id].executors[executor.executor_id] = {
+ statistics: current
+ };
+ });
+
+ if (this.scope.monitor) {
+ // Continue polling.
+ this.polling = this.timeout(angular.bind(this, this.poll), 3000);
+ } else {
+ // Try to compute initial CPU usage more quickly than 3 seconds.
+ this.polling = this.timeout(angular.bind(this, this.poll), 500);
+ }
+
+ // Update the monitoring data.
+ this.scope.monitor = monitor;
+ };
+
+ // Arguments:
+ // host: host of slave.
+ // scope: $scope service from Angular.
+ Top.prototype.start = function(host, scope) {
+ if (this.started()) {
+ // TODO(bmahler): Consider logging a warning here.
+ return;
+ }
+
+ this.endpoint = 'http://' + host + '/monitor/statistics.json?jsonp=JSON_CALLBACK';
+ this.scope = scope;
+
+ // Initial poll is immediate.
+ this.polling = this.timeout(angular.bind(this, this.poll), 0);
+
+ // Stop when we leave the page.
+ scope.$on('$routeChangeStart', angular.bind(this, this.stop));
+ };
+
+ Top.prototype.started = function() {
+ return this.polling != null;
+ };
+
+ Top.prototype.stop = function() {
+ this.timeout.cancel(this.polling);
+ this.polling = null;
+ };
+
+ mesosServices.service('top', ['$http', '$timeout', Top]);
})();
http://git-wip-us.apache.org/repos/asf/mesos/blob/ed3f0438/src/webui/master/static/slave.html
----------------------------------------------------------------------
diff --git a/src/webui/master/static/slave.html b/src/webui/master/static/slave.html
index cf927dc..09bfcf2 100644
--- a/src/webui/master/static/slave.html
+++ b/src/webui/master/static/slave.html
@@ -76,19 +76,29 @@
<h4>Resources</h4>
<table class="table table-condensed">
+ <thead>
+ <tr>
+ <td></td>
+ <td class="text-right">Used</td>
+ <td class="text-right">Allocated</td>
+ </tr>
+ </thead>
<tbody>
<tr>
<td>CPUs</td>
+ <td class="text-right">{{monitor.statistics.cpus_total_usage | number}}</td>
<td class="text-right">{{state.resources.cpus | number}}</td>
</tr>
<tr>
<td>Memory</td>
+ <td class="text-right">{{monitor.statistics.mem_rss_bytes | dataSize}}</td>
<td class="text-right">
{{state.resources.mem * (1024 * 1024) | dataSize}}
</td>
</tr>
<tr>
<td>Disk</td>
+ <td class="text-right">{{0 | dataSize}}</td>
<td class="text-right">
{{state.resources.disk * (1024 * 1024) | dataSize}}
</td>
@@ -107,8 +117,8 @@
<th data-key="user">User</th>
<th data-key="name">Name</th>
<th data-key="num_tasks">Active Tasks</th>
- <th data-key="cpus">CPUs</th>
- <th data-key="Mem">Mem</th>
+ <th data-key="cpus">CPUs (Used / Allocated)</th>
+ <th data-key="Mem">Mem (Used / Allocated)</th>
</tr>
</thead>
<tbody>
@@ -127,8 +137,8 @@
<td>{{framework.user}}</td>
<td>{{framework.name}}</td>
<td>{{framework.num_tasks | number}}</td>
- <td>{{framework.cpus | number}}</td>
- <td>{{framework.mem * (1024 * 1024) | dataSize}}</td>
+ <td>{{monitor.frameworks[framework.id].statistics.cpus_user_usage + monitor.frameworks[framework.id].statistics.cpus_system_usage | number}} / {{framework.cpus | number}}</td>
+ <td>{{monitor.frameworks[framework.id].statistics.mem_rss_bytes | dataSize}} / {{framework.mem * (1024 * 1024) | dataSize}}</td>
</tr>
</tbody>
</table>
http://git-wip-us.apache.org/repos/asf/mesos/blob/ed3f0438/src/webui/master/static/slave_executor.html
----------------------------------------------------------------------
diff --git a/src/webui/master/static/slave_executor.html b/src/webui/master/static/slave_executor.html
index 5c349c1..7c66405 100644
--- a/src/webui/master/static/slave_executor.html
+++ b/src/webui/master/static/slave_executor.html
@@ -64,14 +64,14 @@
<tr>
<td>CPUs</td>
<td class="text-right">
- {{monitor[framework.id][executor.id].resource_usage.cpu_usage | number}}
+ {{monitor.frameworks[framework.id].executors[executor.id].statistics.cpus_total_usage | number}}
</td>
<td class="text-right">{{executor.resources.cpus | number}}</td>
</tr>
<tr>
<td>Mem</td>
<td class="text-right">
- {{monitor[framework.id][executor.id].resource_usage.memory_rss | dataSize}}
+ {{monitor.frameworks[framework.id].executors[executor.id].statistics.mem_rss_bytes | dataSize}}
</td>
<td class="text-right">
{{executor.resources.mem * (1024 * 1024) | dataSize}}
@@ -79,7 +79,7 @@
</tr>
<tr>
<td>Disk</td>
- <td class="text-right">-</td>
+ <td class="text-right">{{0 | dataSize}}</td>
<td class="text-right">
{{(executor.resources.disk || 0) * (1024 * 1024) | dataSize}}
</td>
http://git-wip-us.apache.org/repos/asf/mesos/blob/ed3f0438/src/webui/master/static/slave_framework.html
----------------------------------------------------------------------
diff --git a/src/webui/master/static/slave_framework.html b/src/webui/master/static/slave_framework.html
index af52cf9..90eff2f 100644
--- a/src/webui/master/static/slave_framework.html
+++ b/src/webui/master/static/slave_framework.html
@@ -43,14 +43,14 @@
<tr>
<td>CPUs</td>
<td class="text-right">
- {{framework.resource_usage.cpu_usage | number}}
+ {{monitor.frameworks[framework.id].statistics.cpus_total_usage | number}}
</td>
<td class="text-right">{{framework.cpus | number}}</td>
</tr>
<tr>
<td>Memory</td>
<td class="text-right">
- {{framework.resource_usage.memory_rss | dataSize}}
+ {{monitor.frameworks[framework.id].statistics.mem_rss_bytes | dataSize}}
</td>
<td class="text-right">
{{framework.mem * (1024 * 1024) | dataSize}}
@@ -94,9 +94,9 @@
<td>{{executor.source}}</td>
<td>{{executor.tasks.length | number}}</td>
<td>{{executor.queued_tasks.length | number}}</td>
- <td>{{monitor[framework_id][executor.id].resource_usage.cpu_usage | number}} /
+ <td>{{monitor.frameworks[framework.id].executors[executor.id].statistics.cpus_user_usage + monitor.frameworks[framework.id].executors[executor.id].statistics.cpus_system_usage | number}} /
{{executor.resources.cpus | number}}</td>
- <td>{{monitor[framework_id][executor.id].resource_usage.memory_rss | dataSize}} /
+ <td>{{monitor.frameworks[framework.id].executors[executor.id].statistics.mem_rss_bytes | dataSize}} /
{{executor.resources.mem * (1024 * 1024) | dataSize}}</td>
<td>
<a href="{{'#/slaves/' + slave_id + '/browse?path=' +