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

Aditya Dewan iit2015097 at iiita.ac.in
Fri Jun 16 07:55:19 UTC 2017


 loleaflet/admin.strings.js                  |    1 
 loleaflet/dist/admin/adminAnalytics.html    |   12 +
 loleaflet/src/admin/AdminSocketAnalytics.js |  245 ++++++++++++++++++++++++++--
 wsd/Admin.cpp                               |   45 ++++-
 wsd/Admin.hpp                               |    6 
 wsd/AdminModel.cpp                          |   60 ++++++
 wsd/AdminModel.hpp                          |   14 +
 wsd/DocumentBroker.cpp                      |    4 
 8 files changed, 361 insertions(+), 26 deletions(-)

New commits:
commit 681138ab54ac03fbb26b1c2aa3ae7bcf9e7dde82
Author: Aditya Dewan <iit2015097 at iiita.ac.in>
Date:   Sat Jun 10 06:58:16 2017 +0530

    tdf#106451 admin: graph to monitor network activity
    
    Change-Id: Id71ef4e2a9d16e72f4df442fbf646a39213b61d5
    Reviewed-on: https://gerrit.libreoffice.org/38621
    Reviewed-by: pranavk <pranavk at collabora.co.uk>
    Tested-by: pranavk <pranavk at collabora.co.uk>

diff --git a/loleaflet/admin.strings.js b/loleaflet/admin.strings.js
index 896dcbc3..26f232ba 100644
--- a/loleaflet/admin.strings.js
+++ b/loleaflet/admin.strings.js
@@ -27,6 +27,7 @@ l10nstrings.strKill = _('Kill');
 l10nstrings.strGraphs = _('Graphs');
 l10nstrings.strMemoryGraph = _('Memory Graph');
 l10nstrings.strCpuGraph = _('CPU Graph');
+l10nstrings.strNetGraph = _('Network 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 10957f24..2dc97203 100644
--- a/loleaflet/dist/admin/adminAnalytics.html
+++ b/loleaflet/dist/admin/adminAnalytics.html
@@ -73,6 +73,11 @@
                 <h4><script>document.write(l10nstrings.strCpuGraph)</script></h3>
               </a>
             </li>
+            <li>
+              <a href="#networkview" data-toggle="tab">
+                <h4><script>document.write(l10nstrings.strNetGraph)</script></h3>
+              </a>
+            </li>
           </ul>
           <div class="tab-content graph-content">
             <div id="memview" class="active tab-pane">
@@ -89,6 +94,13 @@
                 </div>
               </div>
             </div>
+            <div id="networkview" class="tab-pane">
+              <div class="graph-container">
+                <div>
+                  <svg id="NetVisualisation" width="1010" height="510"></svg>
+                </div>
+              </div>
+            </div>
           </div>
         </div>
       </div>
diff --git a/loleaflet/src/admin/AdminSocketAnalytics.js b/loleaflet/src/admin/AdminSocketAnalytics.js
index b09348c2..72d5f275 100644
--- a/loleaflet/src/admin/AdminSocketAnalytics.js
+++ b/loleaflet/src/admin/AdminSocketAnalytics.js
@@ -12,6 +12,10 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 
 	_memStatsData: [],
 	_cpuStatsData: [],
+	_sentStatsData: [],
+	_sentAvgStats: [],
+	_recvStatsData: [],
+	_recvAvgStats: [],
 
 	_memStatsSize: 0,
 	_memStatsInterval: 0,
@@ -19,6 +23,10 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 	_cpuStatsSize: 0,
 	_cpuStatsInterval: 0,
 
+	_netAvgSize: 10,
+	_netStatsSize: 0,
+	_netStatsInterval: 0,
+
 	_initStatsData: function(option, size, interval, reset) {
 		var actualData;
 
@@ -36,14 +44,24 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 			this._memStatsData = actualData;
 		else if (option === 'cpu')
 			this._cpuStatsData = actualData;
+		else if (option === 'sent')
+			this._sentStatsData = actualData;
+		else if (option === 'recv')
+			this._recvStatsData = actualData;
+		else if (option === 'sent_avg')
+			this._sentAvgStats = actualData;
+		else if (option === 'recv_avg')
+			this._recvAvgStats = actualData;
 	},
 
 	onSocketOpen: function() {
 		// Base class' onSocketOpen handles authentication
 		this.base.call(this);
 
-		this.socket.send('subscribe mem_stats cpu_stats settings');
+		this.socket.send('subscribe mem_stats cpu_stats sent_activity recv_activity settings');
 		this.socket.send('settings');
+		this.socket.send('sent_activity');
+		this.socket.send('recv_activity');
 		this.socket.send('mem_stats');
 		this.socket.send('cpu_stats');
 	},
@@ -60,6 +78,13 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 	_xCpuScale: null,
 	_yCpuScale: null,
 
+	_d3NetXAxis: null,
+	_d3NetYAxis: null,
+	_d3NetSentLine: null,
+	_d3NetRecvLine: null,
+	_xNetScale: null,
+	_yNetScale: null,
+
 	_graphWidth: 1000,
 	_graphHeight: 500,
 	_graphMargins: {
@@ -70,11 +95,14 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 	},
 
 	_setUpAxis: function(option) {
+		var data, xScale, yScale, d3XAxis, d3Line;
 
 		if (option === 'mem')
 			data = this._memStatsData;
 		else if (option === 'cpu')
 			data = this._cpuStatsData;
+		else if (option === 'net')
+			data = this._sentAvgStats.concat(this._recvAvgStats);
 
 		xScale = d3.scale.linear().range([this._graphMargins.left, this._graphWidth - this._graphMargins.right]).domain([d3.min(data, function(d) {
 			return d.time;
@@ -133,11 +161,27 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 				.orient('left');
 			this._d3CpuLine = d3Line;
 		}
+		else if (option === 'net') {
+			this._xNetScale = xScale;
+			this._yNetScale = yScale;
+			this._d3NetXAxis = d3XAxis;
+			this._d3NetYAxis = d3.svg.axis()
+				.scale(this._yNetScale)
+				.tickFormat(function (d) {
+					return Util.humanizeMem(d) + '/sec';
+				})
+				.orient('left');
+			this._d3NetSentLine = d3Line;
+			this._d3NetRecvLine = d3Line;
+
+		}
 	},
 
 	_createGraph: function(option) {
+		var vis, xAxis, yAxis, line, data;
+
 		if (option === 'mem') {
-			var vis = d3.select('#MemVisualisation');
+			vis = d3.select('#MemVisualisation');
 			this._setUpAxis('mem');
 			xAxis = this._d3MemXAxis;
 			yAxis = this._d3MemYAxis;
@@ -145,13 +189,51 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 			data = this._memStatsData;
 		}
 		else if (option === 'cpu') {
-			var vis = d3.select('#CpuVisualisation');
+			vis = d3.select('#CpuVisualisation');
 			this._setUpAxis('cpu');
 			xAxis = this._d3CpuXAxis;
 			yAxis = this._d3CpuYAxis;
 			line = this._d3CpuLine;
 			data = this._cpuStatsData;
 		}
+		else if (option === 'net') {
+			vis = d3.select('#NetVisualisation');
+			this._setUpAxis('net');
+			xAxis = this._d3NetXAxis;
+			yAxis = this._d3NetYAxis;
+
+			var legend = vis.append('g')
+				.attr('x', this._graphWidth - 70)
+				.attr('y', 50)
+				.style('font-size', '17px');
+
+			var legendData = [
+				{
+					text: 'Recieved',
+					color: 'red'
+				},
+				{
+					text: 'Sent',
+					color: 'green'
+				}
+			];
+			var legendSpacing = 20;
+
+			for (var i = legendData.length - 1; i >= 0; i--) {
+
+				legend.append('text')
+					.attr('x', this._graphWidth - 70)
+					.attr('y', 80 + i * legendSpacing)
+					.text(legendData[i].text);
+				legend.append('rect')
+					.attr('x', this._graphWidth - 90)
+					.attr('y', 67 + i * legendSpacing)
+					.attr('width', 15)
+					.attr('height', 15)
+					.style('fill', legendData[i].color)
+					.style('stroke', 'black');
+			}
+		}
 
 		vis.append('svg:g')
 		.attr('class', 'x-axis')
@@ -163,15 +245,45 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 		.attr('transform', 'translate(' + this._graphMargins.left + ',0)')
 		.call(yAxis);
 
-		vis.append('svg:path')
-			.attr('d', line(data))
-			.attr('class', 'line')
-			.attr('stroke', 'blue')
-			.attr('stroke-width', 2)
-			.attr('fill', 'none');
+		if (option === 'cpu' || option === 'mem') {
+
+			vis.append('svg:path')
+				.attr('d', line(data))
+				.attr('class', 'line')
+				.attr('stroke', 'blue')
+				.attr('stroke-width', 2)
+				.attr('fill', 'none');
+		}
+		else if (option === 'net') {
+
+			vis.append('svg:path')
+				.attr('d', this._d3NetSentLine(this._sentAvgStats))
+				.attr('class', 'lineSent')
+				.attr('stroke', 'red')
+				.attr('stroke-width', 2)
+				.attr('fill', 'none');
+
+			vis.append('svg:path')
+				.attr('d', this._d3NetRecvLine(this._recvAvgStats))
+				.attr('class', 'lineRecv')
+				.attr('stroke', 'green')
+				.attr('stroke-width', 2)
+				.attr('fill', 'none');
+		}
+
 	},
 
-	_addNewData: function(oldData, newData) {
+	_addNewData: function(oldData, newData, option) {
+		var size;
+		if (option === 'mem')
+			size = this._memStatsSize;
+		else if (option === 'cpu')
+			size = this._cpuStatsSize;
+		else if (option === 'sent' || option === 'recv')
+			size = this._netStatsSize;
+		else if (option === 'sent_avg' || option === 'recv_avg')
+			size = this._netStatsSize - this._netAvgSize + 1;
+
 		// make a space for new data
 		for (var i = oldData.length - 1; i > 0; i--) {
 			oldData[i].time = oldData[i - 1].time;
@@ -181,13 +293,13 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 		oldData.push({time: 0, value: parseInt(newData)});
 
 		// remove extra items
-		if (oldData.length > this._memStatsSize) {
+		if (oldData.length > size) {
 			oldData.shift();
 		}
 	},
 
 	_updateMemGraph: function() {
-		svg = d3.select('#MemVisualisation');
+		var svg = d3.select('#MemVisualisation');
 
 		this._setUpAxis('mem');
 
@@ -202,7 +314,7 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 	},
 
 	_updateCpuGraph: function() {
-		svg = d3.select('#CpuVisualisation');
+		var svg = d3.select('#CpuVisualisation');
 
 		this._setUpAxis('cpu');
 
@@ -216,6 +328,51 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 		.call(this._d3CpuYAxis);
 	},
 
+	_updateNetGraph: function() {
+		var svg = d3.select('#NetVisualisation');
+
+		this._setUpAxis('net');
+
+		svg.select('.lineSent')
+		.attr('d', this._d3NetSentLine(this._sentAvgStats));
+		svg.select('.lineRecv')
+		.attr('d', this._d3NetRecvLine(this._recvAvgStats));
+
+		svg.select('.x-axis')
+		.call(this._d3NetXAxis);
+
+		svg.select('.y-axis')
+		.call(this._d3NetYAxis);
+	},
+
+	_updateAverage: function(option, reset) {
+		var data, res, tempSum;
+		if (option === 'sent') {
+			data = this._sentStatsData;
+			res = this._sentAvgStats;
+		}
+		else if (option === 'recv') {
+			data = this._recvStatsData;
+			res = this._recvAvgStats;
+		}
+
+		if (reset) {
+			for (i = 0; i <= this._netStatsSize - this._netAvgSize; i++) {
+				tempSum = 0;
+				for (j = 0; j < this._netAvgSize; j++) {
+					tempSum += data[i + j].value;
+				}
+				tempSum /= this._netAvgSize;
+				res[i].value = tempSum;
+			}
+		}
+		else {
+			tempSum = res[res.length - 1].value + (data[data.length - 1].value - data[data.length - 1 - this._netAvgSize].value) / this._netAvgSize;
+
+			this._addNewData(res, tempSum, 'sent_avg');
+		}
+	},
+
 	onSocketMessage: function(e) {
 		var textMsg;
 		if (typeof e.data === 'string') {
@@ -249,6 +406,12 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 				else if (setting[0] === 'cpu_stats_interval') {
 					cpuStatsInterval = parseInt(setting[1]);
 				}
+				else if (setting[0] === 'net_stats_size') {
+					this._netStatsSize = parseInt(setting[1]);
+				}
+				else if (setting[0] === 'net_stats_interval') {
+					this._netStatsInterval = parseInt(setting[1]);
+				}
 			}
 
 			// Fix the axes according to changed data
@@ -284,6 +447,12 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 
 			this._cpuStatsSize = cpuStatsSize;
 			this._cpuStatsInterval = cpuStatsInterval;
+
+			this._initStatsData('sent', this._netStatsSize, this._netStatsInterval, true);
+			this._initStatsData('recv', this._netStatsSize, this._netStatsInterval, true);
+			this._initStatsData('sent_avg', this._netStatsSize - this._netAvgSize + 1, this._netStatsInterval, true);
+			this._initStatsData('recv_avg', this._netStatsSize - this._netAvgSize + 1, this._netStatsInterval, true);
+
 		}
 		else if (textMsg.startsWith('mem_stats')) {
 			textMsg = textMsg.split(' ')[1];
@@ -299,7 +468,7 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 			else {
 				// this is a notification data; append to _memStatsData
 				data = textMsg.trim();
-				this._addNewData(this._memStatsData, data);
+				this._addNewData(this._memStatsData, data, 'mem');
 				this._updateMemGraph();
 			}
 		}
@@ -318,10 +487,54 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 			else {
 				// this is a notification data; append to _cpuStatsData
 				data = textMsg.trim();
-				this._addNewData(this._cpuStatsData, data);
+				this._addNewData(this._cpuStatsData, data, 'cpu');
 				this._updateCpuGraph();
 			}
 		}
+		else if (textMsg.startsWith('sent_activity')) {
+			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._sentStatsData.length - 1, j = data.length - 1; i >= 0 && j >= 0; i--, j--) {
+					this._sentStatsData[i].value = parseInt(data[j]) / this._netStatsInterval;
+				}
+				this._updateAverage('sent', true);
+
+				if ($('#NetVisualisation').html() === '')
+					this._createGraph('net');
+			}
+			else {
+				// this is a notification data; append to _sentStatsData
+				data = textMsg.trim();
+				this._addNewData(this._sentStatsData, parseInt(data) / this._netStatsInterval, 'sent');
+				this._updateAverage('sent', false);
+				this._updateNetGraph();
+			}
+		}
+		else if (textMsg.startsWith('recv_activity')) {
+			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._recvStatsData.length - 1, j = data.length - 1; i >= 0 && j >= 0; i--, j--) {
+					this._recvStatsData[i].value = parseInt(data[j]) / this._netStatsInterval;
+				}
+				this._updateAverage('recv', true);
+
+				if ($('#NetVisualisation').html() === '')
+					this._createGraph('net');
+			}
+			else {
+				// this is a notification data; append to _recvStatsData
+				data = textMsg.trim();
+				this._addNewData(this._recvStatsData, parseInt(data) / this._netStatsInterval, 'recv');
+				this._updateAverage('recv', false);
+				this._updateNetGraph();
+			}
+		}
 	},
 
 	onSocketClose: function() {
@@ -331,4 +544,4 @@ var AdminSocketAnalytics = AdminSocketBase.extend({
 
 Admin.Analytics = function(host) {
 	return new AdminSocketAnalytics(host);
-};
+};
\ No newline at end of file
diff --git a/wsd/Admin.cpp b/wsd/Admin.cpp
index 3d4a8fb6..deeaecc0 100644
--- a/wsd/Admin.cpp
+++ b/wsd/Admin.cpp
@@ -104,7 +104,9 @@ void AdminSocketHandler::handleMessage(bool /* fin */, WSOpCode /* code */,
              tokens[0] == "active_users_count" ||
              tokens[0] == "active_docs_count" ||
              tokens[0] == "mem_stats" ||
-             tokens[0] == "cpu_stats")
+             tokens[0] == "cpu_stats" ||
+             tokens[0] == "sent_activity" ||
+             tokens[0] == "recv_activity")
     {
         const std::string result = model.query(tokens[0]);
         if (!result.empty())
@@ -170,7 +172,9 @@ void AdminSocketHandler::handleMessage(bool /* fin */, WSOpCode /* code */,
             << "mem_stats_size=" << model.query("mem_stats_size") << ' '
             << "mem_stats_interval=" << std::to_string(_admin->getMemStatsInterval()) << ' '
             << "cpu_stats_size="  << model.query("cpu_stats_size") << ' '
-            << "cpu_stats_interval=" << std::to_string(_admin->getCpuStatsInterval()) << ' ';
+            << "cpu_stats_interval=" << std::to_string(_admin->getCpuStatsInterval()) << ' '
+            << "net_stats_size=" << model.query("net_stats_size") << ' '
+            << "net_stats_interval=" << std::to_string(_admin->getNetStatsInterval()) << ' ';
 
         const DocProcSettings& docProcSettings = _admin->getDefDocProcSettings();
         oss << "limit_virt_mem_mb=" << docProcSettings.LimitVirtMemMb << ' '
@@ -321,8 +325,11 @@ Admin::Admin() :
     _forKitWritePipe(-1),
     _lastTotalMemory(0),
     _lastJiffies(0),
+    _lastSentCount(0),
+    _lastRecvCount(0),
     _memStatsTaskIntervalMs(5000),
-    _cpuStatsTaskIntervalMs(2000)
+    _cpuStatsTaskIntervalMs(2000),
+    _networkStatsIntervalMs(5000)
 {
     LOG_INF("Admin ctor.");
 
@@ -338,28 +345,30 @@ Admin::~Admin()
 
 void Admin::pollingThread()
 {
-    std::chrono::steady_clock::time_point lastCPU, lastMem;
+    std::chrono::steady_clock::time_point lastCPU, lastMem, lastNet;
 
     _model.setThreadOwner(std::this_thread::get_id());
 
     lastCPU = std::chrono::steady_clock::now();
     lastMem = lastCPU;
+    lastNet = lastCPU;
 
     while (!_stop && !TerminationFlag && !ShutdownRequestFlag)
     {
         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)
         {
+            size_t currentJiffies = getTotalCpuUsage();
             auto cpuPercent = 100 * 1000 * currentJiffies / (sysconf (_SC_CLK_TCK) * _cpuStatsTaskIntervalMs);
             _model.addCpuStats(cpuPercent);
 
             lastCPU = now;
             cpuWait += _cpuStatsTaskIntervalMs;
         }
+
         int memWait = _memStatsTaskIntervalMs -
             std::chrono::duration_cast<std::chrono::milliseconds>(now - lastMem).count();
         if (memWait <= 0)
@@ -377,8 +386,25 @@ void Admin::pollingThread()
             memWait += _memStatsTaskIntervalMs;
         }
 
+        int netWait = _networkStatsIntervalMs -
+            std::chrono::duration_cast<std::chrono::milliseconds>(now - lastNet).count();
+        if(netWait <= 0)
+        {
+            uint64_t sentCount = _model.getSentBytesTotal();
+            uint64_t recvCount = _model.getRecvBytesTotal();
+
+            _model.addSentStats(sentCount - _lastSentCount);
+            _model.addRecvStats(recvCount - _lastRecvCount);
+
+            LOG_TRC("Total Data sent: " << sentCount << ", recv: " << recvCount);
+            _lastRecvCount = recvCount;
+            _lastSentCount = sentCount;
+
+            lastNet = now;
+            netWait += _networkStatsIntervalMs;
+        }
         // Handle websockets & other work.
-        int timeout = std::min(cpuWait, memWait);
+        int timeout = std::min(std::min(cpuWait, memWait), netWait);
         LOG_TRC("Admin poll for " << timeout << "ms");
         poll(timeout);
     }
@@ -463,6 +489,11 @@ unsigned Admin::getCpuStatsInterval()
     return _cpuStatsTaskIntervalMs;
 }
 
+unsigned Admin::getNetStatsInterval()
+{
+    return _networkStatsIntervalMs;
+}
+
 AdminModel& Admin::getModel()
 {
     return _model;
diff --git a/wsd/Admin.hpp b/wsd/Admin.hpp
index 5ca87572..18acab4a 100644
--- a/wsd/Admin.hpp
+++ b/wsd/Admin.hpp
@@ -95,6 +95,8 @@ public:
 
     unsigned getCpuStatsInterval();
 
+    unsigned getNetStatsInterval();
+
     void rescheduleMemTimer(unsigned interval);
 
     void rescheduleCpuTimer(unsigned interval);
@@ -124,11 +126,13 @@ private:
     int _forKitWritePipe;
     size_t _lastTotalMemory;
     size_t _lastJiffies;
+    uint64_t _lastSentCount;
+    uint64_t _lastRecvCount;
 
     std::atomic<int> _memStatsTaskIntervalMs;
     std::atomic<int> _cpuStatsTaskIntervalMs;
-
     DocProcSettings _defDocProcSettings;
+    std::atomic<int> _networkStatsIntervalMs;
 };
 
 #endif
diff --git a/wsd/AdminModel.cpp b/wsd/AdminModel.cpp
index bcbdd1d1..073d886c 100644
--- a/wsd/AdminModel.cpp
+++ b/wsd/AdminModel.cpp
@@ -238,6 +238,18 @@ std::string AdminModel::query(const std::string& command)
     {
         return std::to_string(_cpuStatsSize);
     }
+    else if (token == "sent_activity")
+    {
+        return getSentActivity();
+    }
+    else if (token == "recv_activity")
+    {
+        return getRecvActivity();
+    }
+    else if (token == "net_stats_size")
+    {
+        return std::to_string(std::max(_sentStatsSize, _recvStatsSize));
+    }
 
     return std::string("");
 }
@@ -349,6 +361,28 @@ void AdminModel::addCpuStats(unsigned cpuUsage)
     notify("cpu_stats " + std::to_string(cpuUsage));
 }
 
+void AdminModel::addSentStats(uint64_t sent)
+{
+    assertCorrectThread();
+
+    _sentStats.push_back(sent);
+    if (_sentStats.size() > _sentStatsSize)
+        _sentStats.pop_front();
+
+    notify("sent_activity " + std::to_string(sent));
+}
+
+void AdminModel::addRecvStats(uint64_t recv)
+{
+    assertCorrectThread();
+
+    _recvStats.push_back(recv);
+    if (_recvStats.size() > _recvStatsSize)
+        _recvStats.pop_front();
+
+    notify("recv_activity " + std::to_string(recv));
+}
+
 void AdminModel::setCpuStatsSize(unsigned size)
 {
     assertCorrectThread();
@@ -550,6 +584,32 @@ std::string AdminModel::getCpuStats()
     return oss.str();
 }
 
+std::string AdminModel::getSentActivity()
+{
+    assertCorrectThread();
+
+    std::ostringstream oss;
+    for (const auto& i: _sentStats)
+    {
+        oss << i << ',';
+    }
+
+    return oss.str();
+}
+
+std::string AdminModel::getRecvActivity()
+{
+    assertCorrectThread();
+
+    std::ostringstream oss;
+    for (const auto& i: _recvStats)
+    {
+        oss << i << ',';
+    }
+
+    return oss.str();
+}
+
 unsigned AdminModel::getTotalActiveViews()
 {
     assertCorrectThread();
diff --git a/wsd/AdminModel.hpp b/wsd/AdminModel.hpp
index 96231bda..e9eed373 100644
--- a/wsd/AdminModel.hpp
+++ b/wsd/AdminModel.hpp
@@ -221,6 +221,10 @@ public:
 
     void addCpuStats(unsigned cpuUsage);
 
+    void addSentStats(uint64_t sent);
+
+    void addRecvStats(uint64_t recv);
+
     void setCpuStatsSize(unsigned size);
 
     void setMemStatsSize(unsigned size);
@@ -243,6 +247,10 @@ public:
 private:
     std::string getMemStats();
 
+    std::string getSentActivity();
+
+    std::string getRecvActivity();
+
     std::string getCpuStats();
 
     unsigned getTotalActiveViews();
@@ -261,6 +269,12 @@ private:
     std::list<unsigned> _cpuStats;
     unsigned _cpuStatsSize = 100;
 
+    std::list<unsigned> _sentStats;
+    unsigned _sentStatsSize = 100;
+
+    std::list<unsigned> _recvStats;
+    unsigned _recvStatsSize = 100;
+
     uint64_t _sentBytesTotal;
     uint64_t _recvBytesTotal;
 
diff --git a/wsd/DocumentBroker.cpp b/wsd/DocumentBroker.cpp
index 844bff78..d4ac586a 100644
--- a/wsd/DocumentBroker.cpp
+++ b/wsd/DocumentBroker.cpp
@@ -249,8 +249,8 @@ void DocumentBroker::pollThread()
             // send change since last notification.
             Admin::instance().addBytes(getDocKey(),
                                        // connection drop transiently reduces this.
-                                       std::max(sent - adminSent, uint64_t(0)),
-                                       std::max(recv - adminRecv, uint64_t(0)));
+                                       (sent > adminSent ? (sent - adminSent): uint64_t(0)),
+                                       (recv > adminRecv ? (recv - adminRecv): uint64_t(0)));
             LOG_INF("Doc [" << _docKey << "] added sent: " << sent << " recv: " << recv << " bytes to totals");
             adminSent = sent;
             adminRecv = recv;


More information about the Libreoffice-commits mailing list