Skip to content

Commit fbe0db6

Browse files
committed
Support for Heap after GC stats (#1265)
Signed-off-by: Andriy Redko <andriy.redko@aiven.io>
1 parent a80979c commit fbe0db6

File tree

2 files changed

+118
-6
lines changed

2 files changed

+118
-6
lines changed

server/src/main/java/org/opensearch/monitor/jvm/JvmStats.java

Lines changed: 82 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
package org.opensearch.monitor.jvm;
3434

35+
import org.opensearch.Version;
3536
import org.opensearch.common.io.stream.StreamInput;
3637
import org.opensearch.common.io.stream.StreamOutput;
3738
import org.opensearch.common.io.stream.Writeable;
@@ -85,6 +86,11 @@ public static JvmStats jvmStats() {
8586
try {
8687
MemoryUsage usage = memoryPoolMXBean.getUsage();
8788
MemoryUsage peakUsage = memoryPoolMXBean.getPeakUsage();
89+
MemoryUsage collectionUsage = memoryPoolMXBean.getCollectionUsage();
90+
// For some pools, the collection usage may not be supported and the method returns null.
91+
if (collectionUsage == null) {
92+
collectionUsage = new MemoryUsage(0, 0, 0, 0);
93+
}
8894
String name = GcNames.getByMemoryPoolName(memoryPoolMXBean.getName(), null);
8995
if (name == null) { // if we can't resolve it, its not interesting.... (Per Gen, Code Cache)
9096
continue;
@@ -93,8 +99,13 @@ public static JvmStats jvmStats() {
9399
usage.getUsed() < 0 ? 0 : usage.getUsed(),
94100
usage.getMax() < 0 ? 0 : usage.getMax(),
95101
peakUsage.getUsed() < 0 ? 0 : peakUsage.getUsed(),
96-
peakUsage.getMax() < 0 ? 0 : peakUsage.getMax()
97-
));
102+
peakUsage.getMax() < 0 ? 0 : peakUsage.getMax(),
103+
new MemoryPoolGcStats(
104+
collectionUsage.getUsed() < 0 ? 0 : collectionUsage.getUsed(),
105+
collectionUsage.getMax() < 0 ? 0 : collectionUsage.getMax()
106+
)
107+
));
108+
98109
} catch (final Exception ignored) {
99110

100111
}
@@ -223,6 +234,12 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
223234
builder.humanReadableField(Fields.PEAK_USED_IN_BYTES, Fields.PEAK_USED, new ByteSizeValue(pool.peakUsed));
224235
builder.humanReadableField(Fields.PEAK_MAX_IN_BYTES, Fields.PEAK_MAX, new ByteSizeValue(pool.peakMax));
225236

237+
builder.startObject(Fields.LAST_GC_STATS);
238+
builder.humanReadableField(Fields.USED_IN_BYTES, Fields.USED, new ByteSizeValue(pool.getLastGcStats().used));
239+
builder.humanReadableField(Fields.MAX_IN_BYTES, Fields.MAX, new ByteSizeValue(pool.getLastGcStats().max));
240+
builder.field(Fields.USAGE_PERCENT, pool.getLastGcStats().getUsagePercent());
241+
builder.endObject();
242+
226243
builder.endObject();
227244
}
228245
builder.endObject();
@@ -299,7 +316,9 @@ static final class Fields {
299316
static final String PEAK_USED_IN_BYTES = "peak_used_in_bytes";
300317
static final String PEAK_MAX = "peak_max";
301318
static final String PEAK_MAX_IN_BYTES = "peak_max_in_bytes";
302-
319+
static final String USAGE_PERCENT = "usage_percent";
320+
static final String LAST_GC_STATS = "last_gc_stats";
321+
303322
static final String THREADS = "threads";
304323
static final String COUNT = "count";
305324
static final String PEAK_COUNT = "peak_count";
@@ -414,6 +433,48 @@ public int getPeakCount() {
414433
return peakCount;
415434
}
416435
}
436+
437+
/**
438+
* Stores the memory usage after the Java virtual machine
439+
* most recently expended effort in recycling unused objects
440+
* in particular memory pool.
441+
*/
442+
public static class MemoryPoolGcStats implements Writeable {
443+
444+
private final long used;
445+
private final long max;
446+
447+
public MemoryPoolGcStats(long used, long max) {
448+
this.used = used;
449+
this.max = max;
450+
}
451+
452+
public MemoryPoolGcStats(StreamInput in) throws IOException {
453+
used = in.readVLong();
454+
max = in.readVLong();
455+
}
456+
457+
@Override
458+
public void writeTo(StreamOutput out) throws IOException {
459+
out.writeVLong(used);
460+
out.writeVLong(max);
461+
}
462+
463+
public ByteSizeValue getUsed() {
464+
return new ByteSizeValue(used);
465+
}
466+
467+
public ByteSizeValue getMax() {
468+
return new ByteSizeValue(max);
469+
}
470+
471+
public short getUsagePercent() {
472+
if (max == 0) {
473+
return -1;
474+
}
475+
return (short) (used * 100 / max);
476+
}
477+
}
417478

418479
public static class MemoryPool implements Writeable {
419480

@@ -422,13 +483,15 @@ public static class MemoryPool implements Writeable {
422483
private final long max;
423484
private final long peakUsed;
424485
private final long peakMax;
486+
private final MemoryPoolGcStats lastGcStats;
425487

426-
public MemoryPool(String name, long used, long max, long peakUsed, long peakMax) {
488+
public MemoryPool(String name, long used, long max, long peakUsed, long peakMax, MemoryPoolGcStats lastGcStats) {
427489
this.name = name;
428490
this.used = used;
429491
this.max = max;
430492
this.peakUsed = peakUsed;
431493
this.peakMax = peakMax;
494+
this.lastGcStats = lastGcStats;
432495
}
433496

434497
public MemoryPool(StreamInput in) throws IOException {
@@ -437,6 +500,11 @@ public MemoryPool(StreamInput in) throws IOException {
437500
max = in.readVLong();
438501
peakUsed = in.readVLong();
439502
peakMax = in.readVLong();
503+
if (in.getVersion().onOrAfter(Version.V_1_2_0)) {
504+
lastGcStats = new MemoryPoolGcStats(in);
505+
} else {
506+
lastGcStats = new MemoryPoolGcStats(0, 0);
507+
}
440508
}
441509

442510
@Override
@@ -446,6 +514,9 @@ public void writeTo(StreamOutput out) throws IOException {
446514
out.writeVLong(max);
447515
out.writeVLong(peakUsed);
448516
out.writeVLong(peakMax);
517+
if (out.getVersion().onOrAfter(Version.V_1_2_0)) {
518+
lastGcStats.writeTo(out);
519+
}
449520
}
450521

451522
public String getName() {
@@ -467,6 +538,13 @@ public ByteSizeValue getPeakUsed() {
467538
public ByteSizeValue getPeakMax() {
468539
return new ByteSizeValue(peakMax);
469540
}
541+
542+
/**
543+
* Returns the heap usage after last garbage collection cycle
544+
*/
545+
public MemoryPoolGcStats getLastGcStats() {
546+
return lastGcStats;
547+
}
470548
}
471549

472550
public static class Mem implements Writeable, Iterable<MemoryPool> {

server/src/test/java/org/opensearch/action/admin/cluster/node/stats/NodeStatsTests.java

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
import org.opensearch.test.VersionUtils;
5555
import org.opensearch.threadpool.ThreadPoolStats;
5656
import org.opensearch.transport.TransportStats;
57-
import org.opensearch.action.admin.cluster.node.stats.NodeStats;
5857

5958
import java.io.IOException;
6059
import java.util.ArrayList;
@@ -63,9 +62,15 @@
6362
import java.util.Iterator;
6463
import java.util.List;
6564
import java.util.Map;
65+
import java.util.function.Function;
66+
import java.util.stream.Collectors;
67+
import java.util.stream.StreamSupport;
6668

6769
import static java.util.Collections.emptyMap;
6870
import static java.util.Collections.emptySet;
71+
import static org.hamcrest.CoreMatchers.is;
72+
import static org.hamcrest.CoreMatchers.not;
73+
import static org.hamcrest.collection.IsEmptyCollection.empty;
6974

7075
public class NodeStatsTests extends OpenSearchTestCase {
7176
public void testSerialization() throws IOException {
@@ -149,6 +154,34 @@ public void testSerialization() throws IOException {
149154
assertEquals(mem.getNonHeapCommitted(), deserializedMem.getNonHeapCommitted());
150155
assertEquals(mem.getNonHeapUsed(), deserializedMem.getNonHeapUsed());
151156
assertEquals(mem.getHeapMax(), deserializedMem.getHeapMax());
157+
158+
final Map<String, JvmStats.MemoryPool> pools = StreamSupport
159+
.stream(mem.spliterator(), false)
160+
.collect(Collectors.toMap(JvmStats.MemoryPool::getName, Function.identity()));
161+
162+
final Map<String, JvmStats.MemoryPool> deserializedPools = StreamSupport
163+
.stream(deserializedMem.spliterator(), false)
164+
.collect(Collectors.toMap(JvmStats.MemoryPool::getName, Function.identity()));
165+
166+
assertThat(pools.keySet(), not(empty()));
167+
assertThat(deserializedPools.keySet(), not(empty()));
168+
169+
for (final Map.Entry<String, JvmStats.MemoryPool> entry: pools.entrySet()) {
170+
assertThat(deserializedPools.containsKey(entry.getKey()), is(true));
171+
assertEquals(entry.getValue().getName(), deserializedPools.get(entry.getKey()).getName());
172+
assertEquals(entry.getValue().getMax(), deserializedPools.get(entry.getKey()).getMax());
173+
assertEquals(entry.getValue().getPeakMax(), deserializedPools.get(entry.getKey()).getPeakMax());
174+
assertEquals(entry.getValue().getPeakUsed(), deserializedPools.get(entry.getKey()).getPeakUsed());
175+
assertEquals(entry.getValue().getUsed(), deserializedPools.get(entry.getKey()).getUsed());
176+
177+
assertEquals(entry.getValue().getLastGcStats().getUsed(),
178+
deserializedPools.get(entry.getKey()).getLastGcStats().getUsed());
179+
assertEquals(entry.getValue().getLastGcStats().getMax(),
180+
deserializedPools.get(entry.getKey()).getLastGcStats().getMax());
181+
assertEquals(entry.getValue().getLastGcStats().getUsagePercent(),
182+
deserializedPools.get(entry.getKey()).getLastGcStats().getUsagePercent());
183+
}
184+
152185
JvmStats.Classes classes = jvm.getClasses();
153186
assertEquals(classes.getLoadedClassCount(), deserializedJvm.getClasses().getLoadedClassCount());
154187
assertEquals(classes.getTotalLoadedClassCount(), deserializedJvm.getClasses().getTotalLoadedClassCount());
@@ -397,7 +430,8 @@ public static NodeStats createNodeStats() {
397430
List<JvmStats.MemoryPool> memoryPools = new ArrayList<>(numMemoryPools);
398431
for (int i = 0; i < numMemoryPools; i++) {
399432
memoryPools.add(new JvmStats.MemoryPool(randomAlphaOfLengthBetween(3, 10), randomNonNegativeLong(),
400-
randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong()));
433+
randomNonNegativeLong(), randomNonNegativeLong(), randomNonNegativeLong(),
434+
new JvmStats.MemoryPoolGcStats(randomNonNegativeLong(), randomNonNegativeLong())));
401435
}
402436
JvmStats.Threads threads = new JvmStats.Threads(randomIntBetween(1, 1000), randomIntBetween(1, 1000));
403437
int numGarbageCollectors = randomIntBetween(0, 10);

0 commit comments

Comments
 (0)