Skip to content

Commit 24892ee

Browse files
authored
Merge pull request #26424 from pgunapal/26412-addComputedGCTimePerCycleMetric
Added GcTime per Cycle computed metrics to MpMetrics5x
2 parents 43ec8f2 + 45d9ab4 commit 24892ee

File tree

3 files changed

+210
-218
lines changed

3 files changed

+210
-218
lines changed

dev/io.openliberty.microprofile.metrics.5.0.monitor.internal/src/io/openliberty/microprofile/metrics/internal/monitor/computed/internal/ComputedMappingTable.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,15 @@ private ComputedMappingTable() {
5454
MetricUnits.PERCENT, "base", "memory.usedHeap", "memory.maxHeap"}};
5555
mappingTable.put("memoryStats", memoryTable);
5656

57-
// String[][] gcTable = new String[][] { { "gc.time.per.cycle",
58-
// "gc.time.per.cycle.description",
59-
// Constants.GAUGE, MetricUnits.SECONDS, "base", "gc.time", "gc.total" } };
60-
// mappingTable.put("gcStats", gcTable);
57+
String[][] gcTable = new String[][] {
58+
{ "gc.time.per.cycle", "gc.time.per.cycle.description", Constants.GAUGE, MetricUnits.SECONDS,
59+
"base", "gc.time", "gc.total" } };
60+
mappingTable.put("gcStats", gcTable);
6161

6262
// Vendor Metrics
6363
String[][] servletTable = new String[][]{
6464
{"servlet.request.elapsedTime.per.request", "servlet.request.elapsedTime.per.request.description",
65-
Constants.GAUGE, MetricUnits.SECONDS, "vendor", "servlet.responseTime.total", "servlet.request.total"}};
65+
Constants.GAUGE, MetricUnits.SECONDS, "vendor", "servlet.responseTime.total", "servlet.request.total"}};
6666
mappingTable.put("ServletStats", servletTable);
6767

6868
String[][] connectionPoolTable = new String[][]{

dev/io.openliberty.microprofile.metrics.5.0.monitor.internal/src/io/openliberty/microprofile/metrics/internal/monitor/computed/internal/ComputedMonitorMetricsHandler.java

Lines changed: 77 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
*******************************************************************************/
1313
package io.openliberty.microprofile.metrics.internal.monitor.computed.internal;
1414

15+
import java.lang.management.GarbageCollectorMXBean;
16+
import java.lang.management.ManagementFactory;
17+
import java.time.Duration;
1518
import java.util.HashSet;
1619
import java.util.List;
1720
import java.util.Map;
@@ -138,16 +141,14 @@ public void createComputedBaseMetrics() {
138141

139142
// Add the duration metrics to the computation set, no appName for base metrics.
140143
cmm = new ComputedMonitorMetrics(
141-
MetricRegistry.BASE_SCOPE, mid,
142-
Constants.DURATION, null);
144+
MetricRegistry.BASE_SCOPE, mid, Constants.DURATION, null);
143145
computedMonitorMetricsSet.add(cmm);
144146

145147
// Add the total count metric to the computation set, no appName for base metrics.
146148
MetricID totalCountMetricID = new MetricID(
147149
metricTotalCountName, metricTagNames);
148150
cmm = new ComputedMonitorMetrics(
149-
MetricRegistry.BASE_SCOPE, totalCountMetricID,
150-
Constants.TOTAL, null);
151+
MetricRegistry.BASE_SCOPE, totalCountMetricID, Constants.TOTAL, null);
151152
computedMonitorMetricsSet.add(cmm);
152153

153154
// Once the existing metrics needed for calculation are cached, register new computed metric in the Metric Registry.
@@ -385,8 +386,8 @@ public Double getComputedValue(MetricID metricId) {
385386
}
386387

387388
public void calculateMetricValue() {
388-
double diffDuration = 0.0, diffTotalCount = 0.0;
389389
MetricRegistry mr;
390+
Double metricVal = null, diffDuration = null, diffTotalCount = null;
390391

391392
for (Map.Entry<MetricID, Set<ComputedMonitorMetrics>> entry : computationMetricsMap.entrySet()) {
392393
MetricID computedMetricID = entry.getKey();
@@ -397,7 +398,6 @@ public void calculateMetricValue() {
397398
}
398399

399400
String computedMetricName = computedMetricID.getName();
400-
401401
if (computedMetricName.equals("memory.heapUtilization")) {
402402
// Do not need to use the EWMA for the heap utilization calculation
403403
// memory utilization = usedHeap / maxHeap;
@@ -406,21 +406,64 @@ public void calculateMetricValue() {
406406
// Do not need to use the EWMA for the cpu utilization calculation
407407
// Can get it directly from com.ibm.ws.kernel.service.util.CpuInfo.getJavaCpuUsage()
408408
calculateProcessCpuUsage(computedMetricID);
409+
} else if (computedMetricName.equals("gc.time.per.cycle")) {
410+
// Need to retrieve the gc.time and gc.total from the GarbageCollectionMXBean directly,
411+
// instead of the mpMetrics-5.x API, since there is a known bug, where the gc.time from
412+
// the mpMetrics-5.x API returns as a Counter, which drops the decimal in the returned float value,
413+
// making the value not useful for computation.
414+
calculateEWMAValueForGC(computedMetricID, monitorMetrics);
409415
} else {
410416
for (ComputedMonitorMetrics cmm : monitorMetrics) {
411417
mr = getMetricRegistry(cmm.getMonitorMetricScope());
412-
418+
// Get the metric value.
419+
metricVal = getMetricValue(mr, cmm);
420+
if (metricVal != null) {
421+
if (cmm.getComputationType().equals(Constants.DURATION)) {
422+
diffDuration = cmm.getDifference(metricVal.doubleValue());
423+
} else if (cmm.getComputationType().equals(Constants.TOTAL)) {
424+
diffTotalCount = cmm.getDifference(metricVal.doubleValue());
425+
}
426+
}
427+
}
428+
if (diffDuration != null && diffTotalCount != null) {
429+
// Only compute the EWMA if we are able to retrieve the metrics for both Duration and Total count.
430+
calculateEWMAValue(computedMetricID, diffDuration, diffTotalCount);
431+
}
432+
}
433+
}
434+
}
435+
436+
private void calculateEWMAValueForGC(MetricID computedMetricID, Set<ComputedMonitorMetrics> monitorMetrics) {
437+
double currValue = 0.0, diffDuration = 0.0, diffTotalCount = 0.0;
438+
439+
// Get the collection of Garbage Collection MXBeans
440+
List<GarbageCollectorMXBean> gcMXBeansList = ManagementFactory.getGarbageCollectorMXBeans();
441+
442+
for (GarbageCollectorMXBean gcMXBean : gcMXBeansList) {
443+
for (ComputedMonitorMetrics cmm : monitorMetrics) {
444+
String gcName = gcMXBean.getName();
445+
String gcMetricsName = cmm.getMonitorMetricID().getTags().get("name");
446+
if (gcName.equals(gcMetricsName)) {
413447
if (cmm.getComputationType().equals(Constants.DURATION)) {
414-
diffDuration = getMetricValueDifference(mr, cmm);
448+
currValue = gcMXBean.getCollectionTime() * Constants.MILLISECONDCONVERSION;
449+
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
450+
Tr.debug(tc, "GarbageCollectionTime for + " + computedMetricID + " = " + currValue);
451+
}
452+
diffDuration = currValue < 0 ? -1.0 : cmm.getDifference(currValue);
415453
} else if (cmm.getComputationType().equals(Constants.TOTAL)) {
416-
diffTotalCount = getMetricValueDifference(mr, cmm);
454+
currValue = gcMXBean.getCollectionCount();
455+
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
456+
Tr.debug(tc, "GarbageCollectionCount for + " + computedMetricID + " = " + currValue);
457+
}
458+
diffTotalCount = currValue < 0 ? -1.0 : cmm.getDifference(currValue);
417459
}
418460
}
419-
calculateEWMAValue(computedMetricID, diffDuration, diffTotalCount);
420461
}
462+
calculateEWMAValue(computedMetricID, diffDuration, diffTotalCount);
421463
}
422464
}
423465

466+
424467
public void calculateHeapUsage(MetricID computedMetricID, Set<ComputedMonitorMetrics> monitorMetrics) {
425468
double usedHeap = 0.0, maxHeap = 0.0, heapUsage = 0.0;
426469
MetricRegistry mr = getMetricRegistry(MetricRegistry.BASE_SCOPE);
@@ -459,31 +502,37 @@ public void calculateProcessCpuUsage(MetricID computedMetricID) {
459502
finalComputedMetricsMap.put(computedMetricID, processCpuUsage);
460503
}
461504

462-
public double getMetricValueDifference(MetricRegistry mr, ComputedMonitorMetrics cmm) {
463-
double currentValue = 0.0, diff = 0.0;
505+
public Double getMetricValue(MetricRegistry mr, ComputedMonitorMetrics cmm) {
506+
Number metricNum = null;
507+
Double currentValue = null;
464508

465509
Metric metricValue = mr.getMetric(cmm.getMonitorMetricID());
466510
if (metricValue instanceof Gauge) {
467511
Gauge<?> currentGauge = (Gauge<?>) metricValue;
468-
currentValue = currentGauge.getValue().doubleValue();
512+
metricNum = currentGauge.getValue();
469513
} else if (metricValue instanceof Counter) {
470514
Counter currentCount = (Counter) metricValue;
471-
Long currentLongValue = currentCount.getCount();
472-
currentValue = currentLongValue.doubleValue();
515+
metricNum = currentCount.getCount();
473516
} else if (metricValue instanceof org.eclipse.microprofile.metrics.Timer) {
474517
org.eclipse.microprofile.metrics.Timer currentTimer = (org.eclipse.microprofile.metrics.Timer) metricValue;
475518
if (cmm.getComputationType().equals(Constants.DURATION)) {
476-
Integer currentIntValueInNanos = currentTimer.getElapsedTime()
477-
.getNano();
478-
currentValue = (currentIntValueInNanos.doubleValue()) * Constants.NANOSECONDCONVERSION;
519+
Duration currentDur = currentTimer.getElapsedTime();
520+
if (currentDur != null) {
521+
metricNum = currentDur.getNano();
522+
currentValue = (metricNum.doubleValue()) * Constants.NANOSECONDCONVERSION; // to seconds.
523+
}
479524
} else {
480525
// Get Total Counter Value for Timer
481-
Long currentLongValue = currentTimer.getCount();
482-
currentValue = currentLongValue.doubleValue();
526+
metricNum = currentTimer.getCount();
483527
}
484528
}
485-
diff = cmm.getDifference(currentValue);
486-
return diff;
529+
530+
if (metricNum != null && currentValue == null) {
531+
// If the metricValue is present and the currentValue is not already set.
532+
currentValue = metricNum.doubleValue();
533+
}
534+
535+
return currentValue;
487536
}
488537

489538
public MetricRegistry getMetricRegistry(String scope) {
@@ -495,7 +544,9 @@ public void calculateEWMAValue(MetricID computedMetricID, double duration, doubl
495544
double computedVal = 0.0;
496545

497546
// Calculate the new computed metric.
498-
computedVal = duration / totalCount;
547+
// If the duration or the totalCount is a negative value, set the computedValue to be -1.0
548+
// Should only happen when calculating the gc.time.per.cycle.
549+
computedVal = ((duration < 0.0) || (totalCount < 0.0)) ? -1.0 : (duration / totalCount);
499550

500551
// Only the computed metricIDs that require EWMA will be passed into this method.
501552
EWMA ewmaObj = (EWMA) finalComputedMetricsMap.get(computedMetricID);
@@ -505,16 +556,13 @@ public void calculateEWMAValue(MetricID computedMetricID, double duration, doubl
505556
double alpha = calculateAlpha(EWMA_MOVING_WINDOW_INTERVAL); // 5 min moving window
506557
ewmaObj = new EWMA(alpha);
507558

508-
// EWMA[0] will be equal directly to the initially calculated frequency
509-
double initialValue = (duration == 0.0 || totalCount == 0.0)
510-
? 0.0
511-
: computedVal;
559+
// EWMA[0] will be equal directly to the initially calculated value.
560+
double initialValue = (duration == 0.0 || totalCount == 0.0) ? 0.0 : computedVal;
512561
ewmaObj.updateNewValue(initialValue);
513562
} else {
514563
if ((duration == 0.0 || totalCount == 0.0)) {
515564
// If nothing changed during the current sampling period, get the previously calculated EWMA value and feed it into it again.
516-
if (TraceComponent.isAnyTracingEnabled()
517-
&& tc.isDebugEnabled()) {
565+
if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) {
518566
Tr.debug(tc, "Idling - There were no new data in the sampling period, getting the previously calculated EWMA value to feed into it again.");
519567
}
520568
ewmaObj.updateNewValue(ewmaObj.getAveragedValue());

0 commit comments

Comments
 (0)