[Libreoffice-commits] online.git: common/Util.cpp common/Util.hpp loleaflet/admin.strings.js loleaflet/dist loleaflet/src wsd/Admin.cpp wsd/Admin.hpp wsd/AdminModel.cpp wsd/AdminModel.hpp

Aditya Dewan iit2015097 at iiita.ac.in
Thu Jun 8 10:58:30 UTC 2017


 common/Util.cpp                              |   40 +++--
 common/Util.hpp                              |    4 
 loleaflet/admin.strings.js                   |    2 
 loleaflet/dist/admin/adminAnalytics.html     |   36 +++-
 loleaflet/dist/admin/bootstrap/dashboard.css |   11 +
 loleaflet/src/admin/AdminSocketAnalytics.js  |  215 ++++++++++++++++++---------
 wsd/Admin.cpp                                |   28 +++
 wsd/Admin.hpp                                |    2 
 wsd/AdminModel.cpp                           |   25 +++
 wsd/AdminModel.hpp                           |    7 
 10 files changed, 282 insertions(+), 88 deletions(-)

New commits:
commit 9502741590d293155e7b3546654aa696b045362b
Author: Aditya Dewan <iit2015097 at iiita.ac.in>
Date:   Tue Jun 6 06:47:42 2017 +0530

    tdf#107278 admin console: adding graph to track CPU load
    
    Change-Id: Idb07fe4139dd639a49ce1545cc15895f74876b06
    Reviewed-on: https://gerrit.libreoffice.org/38425
    Reviewed-by: pranavk <pranavk at collabora.co.uk>
    Tested-by: pranavk <pranavk at collabora.co.uk>

diff --git a/common/Util.cpp b/common/Util.cpp
index a94457e8..a61fe6d0 100644
--- a/common/Util.cpp
+++ b/common/Util.cpp
@@ -228,14 +228,38 @@ namespace Util
     size_t getMemoryUsageRSS(const Poco::Process::PID pid)
     {
         static const auto pageSizeBytes = getpagesize();
+        size_t rss = 0;
 
         if (pid > 0)
         {
+            rss = getStatFromPid(pid, 23);
+            rss *= pageSizeBytes;
+            rss /= 1024;
+            return rss;
+        }
+        return 0;
+    }
+
+    size_t getCpuUsage(const Poco::Process::PID pid)
+    {
+        if (pid > 0)
+        {
+            size_t totalJiffies = 0;
+            totalJiffies += getStatFromPid(pid, 13);
+            totalJiffies += getStatFromPid(pid, 14);
+            return totalJiffies;
+        }
+        return 0;
+    }
+
+    size_t getStatFromPid(const Poco::Process::PID pid, int ind)
+    {
+        if (pid > 0)
+        {
             const auto cmd = "/proc/" + std::to_string(pid) + "/stat";
             FILE* fp = fopen(cmd.c_str(), "r");
             if (fp != nullptr)
             {
-                size_t rss = 0;
                 char line[4096] = { 0 };
                 if (fgets(line, sizeof (line), fp))
                 {
@@ -244,25 +268,17 @@ namespace Util
                     auto pos = s.find(' ');
                     while (pos != std::string::npos)
                     {
-                        if (index == 23)
+                        if (index == ind)
                         {
-                            // Convert from memory pages to KB.
-                            rss = strtol(&s[pos], nullptr, 10);
-                            rss *= pageSizeBytes;
-                            rss /= 1024;
-                            break;
+                            fclose(fp);
+                            return strtol(&s[pos], nullptr, 10);
                         }
-
                         ++index;
                         pos = s.find(' ', pos + 1);
                     }
                 }
-
-                fclose(fp);
-                return rss;
             }
         }
-
         return 0;
     }
 
diff --git a/common/Util.hpp b/common/Util.hpp
index 0fbf794d..4f9906e9 100644
--- a/common/Util.hpp
+++ b/common/Util.hpp
@@ -105,6 +105,10 @@ namespace Util
     /// Example: "procmemstats: pid=123 rss=12400 pss=566"
     std::string getMemoryStats(FILE* file);
 
+    size_t getCpuUsage(const Poco::Process::PID pid);
+
+    size_t getStatFromPid(const Poco::Process::PID pid, int ind);
+
     std::string replace(std::string s, const std::string& a, const std::string& b);
 
     std::string formatLinesForLog(const std::string& s);
diff --git a/loleaflet/admin.strings.js b/loleaflet/admin.strings.js
index a38f9a0e..9bc38b29 100644
--- a/loleaflet/admin.strings.js
+++ b/loleaflet/admin.strings.js
@@ -25,6 +25,8 @@ l10nstrings.strIdleTime = _('Idle time');
 l10nstrings.strModified = _('Modified');
 l10nstrings.strKill = _('Kill');
 l10nstrings.strGraphs = _('Graphs');
+l10nstrings.strMemoryGraph = _('Memory Graph');
+l10nstrings.strCpuGraph = _('CPU Graph');
 l10nstrings.strSave = _('Save');
 l10nstrings.strMemoryStatsCachesize = _('Cache size of memory statistics');
 l10nstrings.strMemoryStatsInterval = _('Time interval of memory statistics (in ms)');
diff --git a/loleaflet/dist/admin/adminAnalytics.html b/loleaflet/dist/admin/adminAnalytics.html
index b905619b..10957f24 100644
--- a/loleaflet/dist/admin/adminAnalytics.html
+++ b/loleaflet/dist/admin/adminAnalytics.html
@@ -62,13 +62,35 @@
           </ul>
         </div>
         <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
-          <h1 class="page-header"><script>document.write(l10nstrings.strGraphs)</script></h1>
-		        <div class="graph-container">
-		          <div class="jumbotron">
-		            <svg id="visualisation" width="1010" height="510"></svg>
-		          </div>
-		        </div>
-	      </div>
+          <ul class="nav nav-tabs">
+            <li class="active">
+              <a href="#memview" data-toggle="tab">
+                <h4><script>document.write(l10nstrings.strMemoryGraph)</script></h3>
+              </a>
+            </li>
+            <li>
+              <a href="#cpuview" data-toggle="tab">
+                <h4><script>document.write(l10nstrings.strCpuGraph)</script></h3>
+              </a>
+            </li>
+          </ul>
+          <div class="tab-content graph-content">
+            <div id="memview" class="active tab-pane">
+              <div class="graph-container">
+                <div>
+                  <svg id="MemVisualisation" width="1010" height="510"></svg>
+                </div>
+              </div>
+            </div>
+            <div id="cpuview" class="tab-pane">
+              <div class="graph-container">
+                <div>
+                  <svg id="CpuVisualisation" width="1010" height="510"></svg>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
       </div>
     </div>
   </body>
diff --git a/loleaflet/dist/admin/bootstrap/dashboard.css b/loleaflet/dist/admin/bootstrap/dashboard.css
index cdf37a82..95d62235 100644
--- a/loleaflet/dist/admin/bootstrap/dashboard.css
+++ b/loleaflet/dist/admin/bootstrap/dashboard.css
@@ -138,4 +138,15 @@ tr:hover .dropdown-menu{
 }
 .doc_list_label{
   cursor: pointer;
+}
+
+/*
+ * Graph view buttons
+ */
+
+.nav-tabs > li.active > a{
+  background-color: #f5f5f5;
+}
+.graph-content {
+  background-color: #f5f5f5;
 }
\ No newline at end of file
diff --git a/loleaflet/src/admin/AdminSocketAnalytics.js b/loleaflet/src/admin/AdminSocketAnalytics.js
index 898063c0..b09348c2 100644
--- a/loleaflet/src/admin/AdminSocketAnalytics.js
+++ b/loleaflet/src/admin/AdminSocketAnalytics.js
@@ -19,22 +19,23 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 	_cpuStatsSize: 0,
 	_cpuStatsInterval: 0,
 
-	_initMemStatsData: function(memStatsSize, memStatsInterval, reset) {
+	_initStatsData: function(option, size, interval, reset) {
+		var actualData;
+
 		if (reset) {
-			this._memStatsData = [];
+			actualData = [];
 		}
 
-		var offset = this._memStatsData.length * memStatsInterval;
-		for (var i = 0; i < memStatsSize; i++) {
-			this._memStatsData.unshift({time: -(offset), value: 0});
-			offset += memStatsInterval;
+		var offset = actualData.length * interval;
+		for (var i = 0; i < size; i++) {
+			actualData.unshift({time: -(offset), value: 0});
+			offset += interval;
 		}
-	},
 
-	_initCpuStatsData: function() {
-		for (var i = 0; i < this._cpuStatsSize; i++) {
-			this._cpuStatsData.push({time: -((this._cpuStatsSize - i - 1) * this._cpuStatsInterval), value: 0});
-		}
+		if (option === 'mem')
+			this._memStatsData = actualData;
+		else if (option === 'cpu')
+			this._cpuStatsData = actualData;
 	},
 
 	onSocketOpen: function() {
@@ -44,19 +45,20 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 		this.socket.send('subscribe mem_stats cpu_stats settings');
 		this.socket.send('settings');
 		this.socket.send('mem_stats');
+		this.socket.send('cpu_stats');
 	},
 
-	_createMemData: function() {
-		for (var i = this._memStatsRawData.length - 1, j = this._memStatsData.length - 1; i >= 0 && j >= 0; i--, j--) {
-			this._memStatsData[j].value = parseInt(this._memStatsRawData[i]);
-		}
-	},
+	_d3MemXAxis: null,
+	_d3MemYAxis: null,
+	_d3MemLine: null,
+	_xMemScale: null,
+	_yMemScale: null,
 
-	_d3xAxis: null,
-	_d3yAxis: null,
-	_d3line: null,
-	_xScale: null,
-	_yScale: null,
+	_d3CpuXAxis: null,
+	_d3CpuYAxis: null,
+	_d3CpuLine: null,
+	_xCpuScale: null,
+	_yCpuScale: null,
 
 	_graphWidth: 1000,
 	_graphHeight: 500,
@@ -67,22 +69,28 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 		left: 100
 	},
 
-	_setUpAxis: function() {
-		this._xScale = d3.scale.linear().range([this._graphMargins.left, this._graphWidth - this._graphMargins.right]).domain([d3.min(this._memStatsData, function(d) {
+	_setUpAxis: function(option) {
+
+		if (option === 'mem')
+			data = this._memStatsData;
+		else if (option === 'cpu')
+			data = this._cpuStatsData;
+
+		xScale = d3.scale.linear().range([this._graphMargins.left, this._graphWidth - this._graphMargins.right]).domain([d3.min(data, function(d) {
 			return d.time;
-		}), d3.max(this._memStatsData, function(d) {
+		}), d3.max(data, function(d) {
 			return d.time;
 		})]);
 
 
-		this._yScale = d3.scale.linear().range([this._graphHeight - this._graphMargins.bottom, this._graphMargins.top]).domain([d3.min(this._memStatsData, function(d) {
+		yScale = d3.scale.linear().range([this._graphHeight - this._graphMargins.bottom, this._graphMargins.top]).domain([d3.min(data, function(d) {
 			return d.value;
-		}), d3.max(this._memStatsData, function(d) {
+		}), d3.max(data, function(d) {
 			return d.value;
 		})]);
 
-		this._d3xAxis = d3.svg.axis()
-			.scale(this._xScale)
+		d3XAxis = d3.svg.axis()
+			.scale(xScale)
 			.tickFormat(function(d) {
 				d = Math.abs(d / 1000);
 				var units = ['s', 'min', 'hr'];
@@ -92,76 +100,120 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 				return parseInt(d) + units[i] + ' ago';
 			});
 
-		this._d3yAxis = d3.svg.axis()
-			.scale(this._yScale)
-			.tickFormat(function (d) {
-				return Util.humanizeMem(d);
-			})
-			.orient('left');
-
-		var xScale = this._xScale;
-		var yScale = this._yScale;
-
-		this._d3line = d3.svg.line()
+		d3Line = d3.svg.line()
 			.x(function(d) {
 				return xScale(d.time);
 			})
 			.y(function(d) {
 				return yScale(d.value);
-			});
+			})
+			.interpolate('basis');
+
+		if (option === 'mem') {
+			this._xMemScale = xScale;
+			this._yMemScale = yScale;
+			this._d3MemXAxis = d3XAxis;
+			this._d3MemYAxis = d3.svg.axis()
+				.scale(this._yMemScale)
+				.tickFormat(function (d) {
+					return Util.humanizeMem(d);
+				})
+				.orient('left');
+			this._d3MemLine = d3Line;
+		}
+		else if (option === 'cpu') {
+			this._xCpuScale = xScale;
+			this._yCpuScale = yScale;
+			this._d3CpuXAxis = d3XAxis;
+			this._d3CpuYAxis = d3.svg.axis()
+				.scale(this._yCpuScale)
+				.tickFormat(function (d) {
+					return d + '%';
+				})
+				.orient('left');
+			this._d3CpuLine = d3Line;
+		}
 	},
 
-	_createMemGraph: function() {
-		var vis = d3.select('#visualisation');
-
-		this._setUpAxis();
+	_createGraph: function(option) {
+		if (option === 'mem') {
+			var vis = d3.select('#MemVisualisation');
+			this._setUpAxis('mem');
+			xAxis = this._d3MemXAxis;
+			yAxis = this._d3MemYAxis;
+			line = this._d3MemLine;
+			data = this._memStatsData;
+		}
+		else if (option === 'cpu') {
+			var vis = d3.select('#CpuVisualisation');
+			this._setUpAxis('cpu');
+			xAxis = this._d3CpuXAxis;
+			yAxis = this._d3CpuYAxis;
+			line = this._d3CpuLine;
+			data = this._cpuStatsData;
+		}
 
 		vis.append('svg:g')
 		.attr('class', 'x-axis')
 		.attr('transform', 'translate(0,' + (this._graphHeight - this._graphMargins.bottom) + ')')
-		.call(this._d3xAxis);
+		.call(xAxis);
 
 		vis.append('svg:g')
 		.attr('class', 'y-axis')
 		.attr('transform', 'translate(' + this._graphMargins.left + ',0)')
-		.call(this._d3yAxis);
+		.call(yAxis);
 
 		vis.append('svg:path')
-			.attr('d', this._d3line(this._memStatsData))
+			.attr('d', line(data))
 			.attr('class', 'line')
 			.attr('stroke', 'blue')
 			.attr('stroke-width', 2)
 			.attr('fill', 'none');
 	},
 
-	_addNewMemData: function(data) {
+	_addNewData: function(oldData, newData) {
 		// make a space for new data
-		for (var i = this._memStatsData.length - 1; i > 0; i--) {
-			this._memStatsData[i].time = this._memStatsData[i - 1].time;
+		for (var i = oldData.length - 1; i > 0; i--) {
+			oldData[i].time = oldData[i - 1].time;
 		}
 
 		// push new data at time '0'
-		this._memStatsData.push({time: 0, value: parseInt(data)});
+		oldData.push({time: 0, value: parseInt(newData)});
 
 		// remove extra items
-		if (this._memStatsData.length > this._memStatsSize) {
-			this._memStatsData.shift();
+		if (oldData.length > this._memStatsSize) {
+			oldData.shift();
 		}
 	},
 
 	_updateMemGraph: function() {
-		var svg = d3.select('#visualisation');
+		svg = d3.select('#MemVisualisation');
+
+		this._setUpAxis('mem');
+
+		svg.select('.line')
+		.attr('d', this._d3MemLine(this._memStatsData));
+
+		svg.select('.x-axis')
+		.call(this._d3MemXAxis);
+
+		svg.select('.y-axis')
+		.call(this._d3MemYAxis);
+	},
+
+	_updateCpuGraph: function() {
+		svg = d3.select('#CpuVisualisation');
 
-		this._setUpAxis();
+		this._setUpAxis('cpu');
 
 		svg.select('.line')
-		.attr('d', this._d3line(this._memStatsData));
+		.attr('d', this._d3CpuLine(this._cpuStatsData));
 
 		svg.select('.x-axis')
-		.call(this._d3xAxis);
+		.call(this._d3CpuXAxis);
 
 		svg.select('.y-axis')
-		.call(this._d3yAxis);
+		.call(this._d3CpuYAxis);
 	},
 
 	onSocketMessage: function(e) {
@@ -173,12 +225,10 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 			textMsg = '';
 		}
 
-
 		if (textMsg.startsWith('settings')) {
 			textMsg = textMsg.substring('settings '.length);
 			textMsg = textMsg.split(' ');
 
-			//TODO: Add CPU statistics
 			var memStatsSize, memStatsInterval, cpuStatsSize, cpuStatsInterval;
 			var i, j, data;
 			memStatsSize = this._memStatsSize;
@@ -204,10 +254,10 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 			// Fix the axes according to changed data
 			if (memStatsInterval !== this._memStatsInterval) {
 				// We can possibly reuse the data with a bit of work
-				this._initMemStatsData(memStatsSize, memStatsInterval, true);
+				this._initStatsData('mem', memStatsSize, memStatsInterval, true);
 			}
 			else if (memStatsSize > this._memStatsSize) {
-				this._initMemStatsData(memStatsSize - this._memStatsSize, memStatsInterval, false);
+				this._initStatsData('mem', memStatsSize - this._memStatsSize, memStatsInterval, false);
 			}
 			else {
 				// just strip the extra items
@@ -218,11 +268,24 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 
 			this._memStatsSize = memStatsSize;
 			this._memStatsInterval = memStatsInterval;
+
+			// Similar Logic as above for CPU stats
+			if (cpuStatsInterval !== this._cpuStatsInterval) {
+				this._initStatsData('cpu', cpuStatsSize, cpuStatsInterval, true);
+			}
+			else if (cpuStatsSize > this._cpuStatsSize) {
+				this._initStatsData('cpu', cpuStatsSize - this._cpuStatsSize, cpuStatsInterval, false);
+			}
+			else {
+				for (i = 0; i < this._cpuStatsSize - cpuStatsSize; i++) {
+					this._cpuStatsData.shift();
+				}
+			}
+
 			this._cpuStatsSize = cpuStatsSize;
 			this._cpuStatsInterval = cpuStatsInterval;
 		}
-		else if (textMsg.startsWith('mem_stats') ||
-			textMsg.startsWith('cpu_stats')) {
+		else if (textMsg.startsWith('mem_stats')) {
 			textMsg = textMsg.split(' ')[1];
 			if (textMsg.endsWith(',')) {
 				// This is the result of query, not notification
@@ -231,16 +294,34 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 					this._memStatsData[i].value = parseInt(data[j]);
 				}
 
-				//this._createMemData(data);
-				this._createMemGraph();
+				this._createGraph('mem');
 			}
 			else {
 				// this is a notification data; append to _memStatsData
 				data = textMsg.trim();
-				this._addNewMemData(data);
+				this._addNewData(this._memStatsData, data);
 				this._updateMemGraph();
 			}
 		}
+		else if (textMsg.startsWith('cpu_stats')) {
+			textMsg = textMsg.split(' ')[1];
+			if (textMsg.endsWith(',')) {
+				// This is the result of query, not notification
+				data = textMsg.substring(0, textMsg.length - 1).split(',');
+
+				for (i = this._cpuStatsData.length - 1, j = data.length - 1; i >= 0 && j >= 0; i--, j--) {
+					this._cpuStatsData[i].value = parseInt(data[j]);
+				}
+
+				this._createGraph('cpu');
+			}
+			else {
+				// this is a notification data; append to _cpuStatsData
+				data = textMsg.trim();
+				this._addNewData(this._cpuStatsData, data);
+				this._updateCpuGraph();
+			}
+		}
 	},
 
 	onSocketClose: function() {
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index 1c15aa1d..425a352d 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -12,6 +12,7 @@
 #include <cassert>
 #include <mutex>
 #include <sys/poll.h>
+#include <unistd.h>
 
 #include <Poco/Net/HTTPCookie.h>
 #include <Poco/Net/HTTPRequest.h>
@@ -298,8 +299,9 @@ Admin::Admin() :
     _model(AdminModel()),
     _forKitPid(-1),
     _lastTotalMemory(0),
+    _lastJiffies(0),
     _memStatsTaskIntervalMs(5000),
-    _cpuStatsTaskIntervalMs(5000)
+    _cpuStatsTaskIntervalMs(2000)
 {
     LOG_INF("Admin ctor.");
 
@@ -327,9 +329,13 @@ void Admin::pollingThread()
         std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
         int cpuWait = _cpuStatsTaskIntervalMs -
             std::chrono::duration_cast<std::chrono::milliseconds>(now - lastCPU).count();
+
+        size_t currentJiffies = getTotalCpuUsage();
         if (cpuWait <= 0)
         {
-            // TODO: implement me ...
+            auto cpuPercent = 100 * 1000 * currentJiffies / (sysconf (_SC_CLK_TCK) * _cpuStatsTaskIntervalMs);
+            _model.addCpuStats(cpuPercent);
+
             lastCPU = now;
             cpuWait += _cpuStatsTaskIntervalMs;
         }
@@ -408,6 +414,24 @@ size_t Admin::getTotalMemoryUsage()
     return totalMem;
 }
 
+size_t Admin::getTotalCpuUsage()
+{
+    const size_t forkitJ = Util::getCpuUsage(_forKitPid);
+    const size_t wsdJ = Util::getCpuUsage(Poco::Process::id());
+    const size_t kitsJ = _model.getKitsJiffies();
+
+    if(_lastJiffies == 0)
+    {
+        _lastJiffies = forkitJ + wsdJ;
+        return 0;
+    }
+
+    const size_t totalJ = ((forkitJ + wsdJ) - _lastJiffies) + kitsJ;
+    _lastJiffies = forkitJ + wsdJ;
+
+    return totalJ;
+}
+
 unsigned Admin::getMemStatsInterval()
 {
     return _memStatsTaskIntervalMs;
diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp
index 2c77e391..91df8108 100644
--- a/wsd/Admin.hpp
+++ b/wsd/Admin.hpp
@@ -70,6 +70,7 @@ public:
     void pollingThread() override;
 
     size_t getTotalMemoryUsage();
+    size_t getTotalCpuUsage();
 
     void modificationAlert(const std::string& dockey, Poco::Process::PID pid, bool value);
     /// Update the Admin Model.
@@ -109,6 +110,7 @@ private:
     AdminModel _model;
     int _forKitPid;
     size_t _lastTotalMemory;
+    size_t _lastJiffies;
 
     std::atomic<int> _memStatsTaskIntervalMs;
     std::atomic<int> _cpuStatsTaskIntervalMs;
diff --git a/wsd/AdminModel.cpp b/wsd/AdminModel.cpp
index 1ee088eb..bcbdd1d1 100644
--- a/wsd/AdminModel.cpp
+++ b/wsd/AdminModel.cpp
@@ -271,6 +271,31 @@ unsigned AdminModel::getKitsMemoryUsage()
     return totalMem;
 }
 
+size_t AdminModel::getKitsJiffies()
+{
+    assertCorrectThread();
+
+    size_t totalJ = 0;
+    for (auto& it : _documents)
+    {
+        if (!it.second.isExpired())
+        {
+            const auto pid = it.second.getPid();
+            if (pid > 0)
+            {
+                unsigned newJ = Util::getCpuUsage(pid);
+                unsigned prevJ = it.second.getLastJiffies();
+                if(newJ >= prevJ)
+                {
+                    totalJ += (newJ - prevJ);
+                    it.second.setLastJiffies(newJ);
+                }
+            }
+        }
+    }
+    return totalJ;
+}
+
 void AdminModel::subscribe(int sessionId, const std::weak_ptr<WebSocketHandler>& ws)
 {
     assertCorrectThread();
diff --git a/wsd/AdminModel.hpp b/wsd/AdminModel.hpp
index ed83d8cd..90716964 100644
--- a/wsd/AdminModel.hpp
+++ b/wsd/AdminModel.hpp
@@ -54,6 +54,7 @@ public:
           _pid(pid),
           _filename(filename),
           _memoryDirty(0),
+          _lastJiffy(0),
           _start(std::time(nullptr)),
           _lastActivity(_start),
           _sentBytes(0),
@@ -77,6 +78,9 @@ public:
 
     unsigned getActiveViews() const { return _activeViews; }
 
+    unsigned getLastJiffies() const { return _lastJiffy; }
+    void setLastJiffies(size_t newJ) { _lastJiffy = newJ; }
+
     const std::map<std::string, View>& getViews() const { return _views; }
 
     void updateLastActivityTime() { _lastActivity = std::time(nullptr); }
@@ -110,6 +114,8 @@ private:
     std::string _filename;
     /// The dirty (ie. un-shared) memory of the document's Kit process.
     int _memoryDirty;
+    /// Last noted Jiffy count
+    unsigned _lastJiffy;
 
     std::time_t _start;
     std::time_t _lastActivity;
@@ -184,6 +190,7 @@ public:
 
     /// Returns memory consumed by all active loolkit processes
     unsigned getKitsMemoryUsage();
+    size_t getKitsJiffies();
 
     void subscribe(int sessionId, const std::weak_ptr<WebSocketHandler>& ws);
     void subscribe(int sessionId, const std::string& command);


More information about the Libreoffice-commits mailing list