changeset 272:b35a283eb016

Add resident memory timeseries chart to jvm-memory Reviewed-by: jerboaa Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-October/025532.html
author Andrew Azores <aazores@redhat.com>
date Thu, 26 Oct 2017 09:47:58 -0400
parents 671cfc1d001d
children 84d4e3e9d77a
files mock-api/endpoints/jvm-memory.endpoint.js src/app/components/jvm-info/jvm-memory/en.locale.yaml src/app/components/jvm-info/jvm-memory/jvm-memory.controller.js src/app/components/jvm-info/jvm-memory/jvm-memory.controller.spec.js src/app/components/jvm-info/jvm-memory/jvm-memory.html
diffstat 5 files changed, 199 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/mock-api/endpoints/jvm-memory.endpoint.js	Wed Oct 25 11:51:03 2017 -0400
+++ b/mock-api/endpoints/jvm-memory.endpoint.js	Thu Oct 26 09:47:58 2017 -0400
@@ -32,6 +32,7 @@
     metaspaceMinCapacity: { $numberLong: '0' },
     metaspaceCapacity: { $numberLong: (4096 * 1024 * 1024).toString() },
     metaspaceUsed: { $numberLong: _.round(4096 * 1024 * 1024 * Math.random()).toString() },
+    residentMemory: { $numberLong: _.round(2 * 1024 * 1024 * Math.random()).toString() },
     generations: [
       {
         capacity: { $numberLong: (100 * 1024 * 1024).toString() },
--- a/src/app/components/jvm-info/jvm-memory/en.locale.yaml	Wed Oct 25 11:51:03 2017 -0400
+++ b/src/app/components/jvm-info/jvm-memory/en.locale.yaml	Thu Oct 26 09:47:58 2017 -0400
@@ -3,11 +3,13 @@
   REFRESH_RATE_LABEL: Refresh Rate
   MAX_DATA_AGE_LABEL: Max Data Age
 
+  RESIDENT: Resident Set Size
   METASPACE: Metaspace
   COLLECTOR: '{{name}} generation ({{collector}} collector)'
   SPACE: Space {{index}}
   X_AXIS_LABEL: Time
-  Y_AXIS_LABEL: Bytes
+  Y_AXIS_LABEL_B: Bytes
+  Y_AXIS_LABEL_KB: Kibibytes
 
   refresh:
     DISABLED: Disabled
--- a/src/app/components/jvm-info/jvm-memory/jvm-memory.controller.js	Wed Oct 25 11:51:03 2017 -0400
+++ b/src/app/components/jvm-info/jvm-memory/jvm-memory.controller.js	Thu Oct 26 09:47:58 2017 -0400
@@ -47,6 +47,15 @@
     this._metricToNumber = metricToNumberFilter;
     this._scaleBytes = scaleBytesService;
 
+    this._residentData = {
+      timestamps: [],
+      used: []
+    };
+    this.residentSeriesData = {
+      xData: ['timestamp'],
+      yData: ['memory']
+    };
+
     this.metaspaceSnapshotData = {
       used: 0,
       total: 0
@@ -64,39 +73,71 @@
       units: 'B'
     };
 
-    $translate(['jvmMemory.X_AXIS_LABEL', 'jvmMemory.Y_AXIS_LABEL']).then(translations => {
-      this._xAxisLabel = translations['jvmMemory.X_AXIS_LABEL'];
-      this._yAxisLabel = translations['jvmMemory.Y_AXIS_LABEL'];
-      this.metaspaceLineConfig = {
-        chartId: 'metaspaceLineChart',
-        units: 'B',
-        axis: {
-          x: {
-            show: true,
-            type: 'timeseries',
-            label: {
-              text: this._xAxisLabel,
-              position: 'outer-center'
+    $translate(['jvmMemory.X_AXIS_LABEL',
+      'jvmMemory.Y_AXIS_LABEL_KB',
+      'jvmMemory.Y_AXIS_LABEL_B'])
+      .then(translations => {
+        this._xAxisLabel = translations['jvmMemory.X_AXIS_LABEL'];
+        this._yAxisLabelBytes = translations['jvmMemory.Y_AXIS_LABEL_B'];
+        this.residentLineConfig = {
+          chartId: 'residentLineChart',
+          units: 'KiB',
+          axis: {
+            x: {
+              show: true,
+              type: 'timeseries',
+              label: {
+                text: this._xAxisLabel,
+                position: 'outer-center'
+              },
+              tick : {
+                format: timestamp => this._dateFilter(timestamp, this._dateFormat.time.medium),
+                count: 5,
+                fit: false
+              }
             },
-            tick : {
-              format: timestamp => this._dateFilter(timestamp, this._dateFormat.time.medium),
-              count: 5,
-              fit: false
-            }
-          },
-          y: {
-            show: true,
-            min: 0,
-            padding: 0,
-            tick: 10,
-            label: {
-              text: this._yAxisLabel,
-              position: 'outer-middle'
+            y: {
+              show: true,
+              min: 0,
+              padding: 0,
+              tick: 10,
+              label: {
+                text: translations['jvmMemory.Y_AXIS_LABEL_KB'],
+                position: 'outer-middle'
+              }
             }
           }
-        }
-      };
-    });
+        };
+        this.metaspaceLineConfig = {
+          chartId: 'metaspaceLineChart',
+          units: 'B',
+          axis: {
+            x: {
+              show: true,
+              type: 'timeseries',
+              label: {
+                text: this._xAxisLabel,
+                position: 'outer-center'
+              },
+              tick : {
+                format: timestamp => this._dateFilter(timestamp, this._dateFormat.time.medium),
+                count: 5,
+                fit: false
+              }
+            },
+            y: {
+              show: true,
+              min: 0,
+              padding: 0,
+              tick: 10,
+              label: {
+                text: this._yAxisLabelBytes,
+                position: 'outer-middle'
+              }
+            }
+          }
+        };
+      });
     this.spaceBarConfigs = [];
     this._generationData = new Map();
     this.generationSnapshotData = {};
@@ -134,7 +175,7 @@
             padding: 0,
             tick: 10,
             label: {
-              text: this._yAxisLabel,
+              text: this._yAxisLabelBytes,
               position: 'outer-middle'
             }
           }
@@ -187,6 +228,14 @@
     return this._dataAgeLimit.toString();
   }
 
+  multichartResident () {
+    return new Promise(resolve =>
+      this._jvmMemoryService.getSnapshot(this.jvmId).then(resp =>
+        resolve(this.convertMemStat(resp.residentMemory))
+      )
+    );
+  }
+
   multichartMetaspace () {
     return new Promise(resolve =>
       this._jvmMemoryService.getSnapshot(this.jvmId).then(resp =>
@@ -238,6 +287,10 @@
 
       let timestamp = this._metricToNumber(update.timeStamp);
 
+      let residentUsed = this.convertMemStat(update.residentMemory);
+      this._residentData.timestamps.push(timestamp);
+      this._residentData.used.push(residentUsed);
+
       let metaspaceUsed = this.convertMemStat(update.metaspaceUsed);
       let metaspaceCapacity = this.convertMemStat(update.metaspaceCapacity);
 
@@ -277,6 +330,16 @@
     let now = this._getCurrentTimestamp();
     let limit = now - this._dataAgeLimit;
 
+    let residentSpliceCount = 0;
+    for (; residentSpliceCount < this._residentData.timestamps.length; residentSpliceCount++) {
+      let sample = this._residentData.timestamps[residentSpliceCount];
+      if (sample >= limit) {
+        break;
+      }
+    }
+    this._residentData.timestamps.splice(0, residentSpliceCount);
+    this._residentData.used.splice(0, residentSpliceCount);
+
     let metaspaceSpliceCount = 0;
     for (; metaspaceSpliceCount < this._metaspaceData.timestamps.length; metaspaceSpliceCount++) {
       let sample = this._metaspaceData.timestamps[metaspaceSpliceCount];
@@ -303,6 +366,11 @@
   }
 
   _updateLineCharts (keys) {
+    this.residentSeriesData = {
+      xData: ['timestamp'].concat(this._residentData.timestamps),
+      yData: ['memory'].concat(this._residentData.used)
+    };
+
     this.metaspaceSeriesData = {
       xData: ['timestamp'].concat(this._metaspaceData.timestamps),
       yData: ['memory'].concat(this._metaspaceData.used)
--- a/src/app/components/jvm-info/jvm-memory/jvm-memory.controller.spec.js	Wed Oct 25 11:51:03 2017 -0400
+++ b/src/app/components/jvm-info/jvm-memory/jvm-memory.controller.spec.js	Thu Oct 26 09:47:58 2017 -0400
@@ -109,6 +109,20 @@
     });
   });
 
+  describe('residentLineConfig', () => {
+    it('should be assigned after init', () => {
+      ctrl.should.have.ownProperty('residentLineConfig');
+    });
+
+    it('should provide an x-axis tick formatter', () => {
+      let fn = ctrl.residentLineConfig.axis.x.tick.format;
+      dateFilter.should.not.be.called();
+      fn(1234);
+      dateFilter.should.be.calledOnce();
+      dateFilter.should.be.calledWith(1234, dateFormat.time.medium);
+    });
+  });
+
   describe('metaspaceLineConfig', () => {
     it('should be assigned after init', () => {
       ctrl.should.have.ownProperty('metaspaceLineConfig');
@@ -203,18 +217,21 @@
   });
 
   describe('_update', () => {
-    let data;
+    let timestamp, data;
     beforeEach(() => {
+      timestamp = Date.now();
       data = [{
         agentId: 'foo-agentId',
         jvmId: 'foo-jvmId',
-        timeStamp: { $numberLong: Date.now().toString() },
+        timeStamp: { $numberLong: timestamp.toString() },
         metaspaceMaxCapacity: { $numberLong: '0' },
         metaspaceMinCapacity: { $numberLong: '0' },
         metaspaceCapacity: { $numberLong: (40 * 1024 * 1024).toString() },
         metaspaceUsed: { $numberLong: (20 * 1024 * 1024).toString() },
+        residentMemory: { $numberLong: (2 * 1024 * 1024).toString() },
         generations: [
           {
+            index: 0,
             capacity: { $numberLong: (10 * 1024 * 1024).toString() },
             collector: 'Shenandoah',
             maxCapacity: { $numberLong: (60 * 1024 * 1024).toString() },
@@ -235,6 +252,26 @@
       promise.then.yield(data);
     });
 
+    it('should add series data', () => {
+      ctrl._residentData.should.deepEqual({
+        timestamps: [timestamp, timestamp],
+        used: [2 * 1024 * 1024, 2 * 1024 * 1024]
+      });
+
+      ctrl._metaspaceData.should.deepEqual({
+        timestamps: [timestamp, timestamp],
+        used: [20 * 1024 * 1024, 20 * 1024 * 1024],
+        capacity: [40 * 1024 * 1024, 40 * 1024 * 1024]
+      });
+
+      ctrl._generationData.has(ctrl._getKey(0, 0)).should.be.true();
+      ctrl._generationData.get(ctrl._getKey(0, 0)).should.deepEqual({
+        timestamps: [timestamp, timestamp],
+        used: [30 * 1024 * 1024, 30 * 1024 * 1024],
+        capacity: [50 * 1024 * 1024, 50 * 1024 * 1024]
+      });
+    });
+
     it('should update metaspaceSnapshotData', () => {
       ctrl.metaspaceSnapshotData.should.deepEqual({
         used: 20,
@@ -333,6 +370,19 @@
   });
 
   describe('_trimData', () => {
+    it('should trim old resident data', () => {
+      let now = Date.now();
+      ctrl._residentData = {
+        timestamps: [now - 120 * 60 * 1000, now],
+        used: [100, 200],
+      };
+      ctrl._trimData();
+      ctrl._residentData.should.deepEqual({
+        timestamps: [now],
+        used: [200]
+      });
+    });
+
     it('should trim old metaspace data', () => {
       let now = Date.now();
       ctrl._metaspaceData = {
@@ -380,6 +430,27 @@
     });
   });
 
+  describe('multichartResident', () => {
+    it('should return a promise', () => {
+      let res = ctrl.multichartResident();
+      res.should.be.a.Promise();
+    });
+
+    it('should resolve jvm-memory resident memory stat', done => {
+      promise.then.should.be.calledOnce();
+      let res = ctrl.multichartResident();
+      res.then(v => {
+        v.should.equal(9001);
+        done();
+      });
+      promise.then.should.be.calledTwice();
+      let prom = promise.then.secondCall.args[0];
+      prom({
+        residentMemory: { $numberLong: '9001' }
+      });
+    });
+  });
+
   describe('multichartMetaspace', () => {
     it('should return a promise', () => {
       let res = ctrl.multichartMetaspace();
--- a/src/app/components/jvm-info/jvm-memory/jvm-memory.html	Wed Oct 25 11:51:03 2017 -0400
+++ b/src/app/components/jvm-info/jvm-memory/jvm-memory.html	Thu Oct 26 09:47:58 2017 -0400
@@ -32,6 +32,29 @@
       <div class="col">
         <div class="card-pf card-pf-view">
           <div class="card-pf-heading">
+            <label class="card-pf-title" translate>jvmMemory.RESIDENT</label>
+            <mc-add class="pull-right" svc-name="{{$ctrl.jvmId}}-rss" get-fn="$ctrl.multichartResident()"></mc-add>
+          </div>
+          <div class="card-pf-body">
+            <pf-line-chart
+               id="residentLineChart"
+               config="$ctrl.residentLineConfig"
+               chart-data="$ctrl.residentSeriesData"
+               ></pf-line-chart>
+          </div>
+        </div>
+      </div>
+
+    </div>
+
+  </div>
+
+  <div class="row row-cards-pf">
+    <div class="container-fluid container-cards-pf">
+
+      <div class="col">
+        <div class="card-pf card-pf-view">
+          <div class="card-pf-heading">
             <label class="card-pf-title" translate>jvmMemory.METASPACE</label>
             <mc-add class="pull-right" svc-name="{{$ctrl.jvmId}}-metaspace" get-fn="$ctrl.multichartMetaspace()"></mc-add>
           </div>