Skip to content

Commit ce8d34f

Browse files
authored
Merge pull request #4946 from MovingBlocks/feat/debugOverlayRSS
2 parents f105255 + f414d22 commit ce8d34f

7 files changed

Lines changed: 129 additions & 27 deletions

File tree

engine/src/main/java/org/terasology/engine/rendering/nui/layers/ingame/metrics/DebugOverlay.java

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.terasology.engine.persistence.StorageManager;
1616
import org.terasology.engine.registry.In;
1717
import org.terasology.engine.rendering.nui.CoreScreenLayer;
18+
import org.terasology.engine.utilities.OperatingSystemMemory;
1819
import org.terasology.engine.world.WorldProvider;
1920
import org.terasology.engine.world.chunks.Chunks;
2021
import org.terasology.nui.databinding.ReadOnlyBinding;
@@ -31,7 +32,7 @@
3132
*/
3233
public class DebugOverlay extends CoreScreenLayer {
3334

34-
public static final double MB_SIZE = 1048576.0;
35+
public static final float MB_SIZE = 1048576.0f;
3536

3637
@In
3738
private Config config;
@@ -72,13 +73,40 @@ public Boolean get() {
7273
});
7374

7475
UILabel debugLine1 = find("debugLine1", UILabel.class);
76+
77+
// This limit doesn't change after start-up.
78+
final long dataLimit = OperatingSystemMemory.isAvailable()
79+
? OperatingSystemMemory.dataAndStackSizeLimit() : -1;
80+
7581
if (debugLine1 != null) {
76-
debugLine1.bindText(new ReadOnlyBinding<String>() {
82+
debugLine1.bindText(new ReadOnlyBinding<>() {
7783
@Override
7884
public String get() {
79-
double memoryUsage = ((double) Runtime.getRuntime().totalMemory() - (double) Runtime.getRuntime().freeMemory()) / MB_SIZE;
80-
return String.format("FPS: %.2f, Memory Usage: %.2f MB, Total Memory: %.2f MB, Max Memory: %.2f MB",
81-
time.getFps(), memoryUsage, Runtime.getRuntime().totalMemory() / MB_SIZE, Runtime.getRuntime().maxMemory() / MB_SIZE);
85+
Runtime runtime = Runtime.getRuntime();
86+
long totalHeapSize = runtime.totalMemory();
87+
float usedHeapMemory = ((float) totalHeapSize - (float) runtime.freeMemory()) / MB_SIZE;
88+
String s = String.format(
89+
"FPS: %.1f, Heap Usage: %.1f MB, Total Heap: %.1f MB, Max Heap: %.1f MB",
90+
time.getFps(),
91+
usedHeapMemory,
92+
totalHeapSize / MB_SIZE,
93+
runtime.maxMemory() / MB_SIZE
94+
);
95+
if (OperatingSystemMemory.isAvailable()) {
96+
// Check data size, because that's the one comparable to Terasology#setMemoryLimit
97+
long dataSize = OperatingSystemMemory.dataAndStackSize();
98+
// How much bigger is that than the number reported by the Java runtime?
99+
long nonJavaHeapDataSize = dataSize - totalHeapSize;
100+
String limitString = (dataLimit > 0)
101+
? String.format(" / %.1f MB (%02d%%)", dataLimit / MB_SIZE, 100 * dataSize / dataLimit)
102+
: "";
103+
return String.format(
104+
"%s, Data: %.1f MB%s, Extra: %.1f MB",
105+
s, dataSize / MB_SIZE, limitString, nonJavaHeapDataSize / MB_SIZE
106+
);
107+
} else {
108+
return s;
109+
}
82110
}
83111
});
84112
}
@@ -158,7 +186,7 @@ public String get() {
158186
debugInfo.bindText(new ReadOnlyBinding<String>() {
159187
@Override
160188
public String get() {
161-
return String.format("[H] : Debug Documentation");
189+
return "[H] : Debug Documentation";
162190
}
163191
});
164192
}

engine/src/main/java/org/terasology/engine/rendering/nui/layers/ingame/metrics/MetricsMode.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ public MetricsMode(String name) {
4545
*/
4646
public abstract boolean isAvailable();
4747

48-
public abstract boolean isPerformanceManagerMode();
48+
public boolean isPerformanceManagerMode() {
49+
return false;
50+
}
4951

5052
/**
5153
* A (human readable) name for the metrics mode.

engine/src/main/java/org/terasology/engine/rendering/nui/layers/ingame/metrics/NetworkStatsMode.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,4 @@ public String getMetrics() {
5050
public boolean isAvailable() {
5151
return networkSystem.getMode() != NetworkMode.NONE;
5252
}
53-
54-
@Override
55-
public boolean isPerformanceManagerMode() {
56-
return false;
57-
}
5853
}

engine/src/main/java/org/terasology/engine/rendering/nui/layers/ingame/metrics/NullMetricsMode.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,4 @@ public String getMetrics() {
1717
public boolean isAvailable() {
1818
return true;
1919
}
20-
21-
@Override
22-
public boolean isPerformanceManagerMode() {
23-
return false;
24-
}
2520
}

engine/src/main/java/org/terasology/engine/rendering/nui/layers/ingame/metrics/RunningThreadsMode.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,4 @@ public String getMetrics() {
3030
public boolean isAvailable() {
3131
return true;
3232
}
33-
34-
@Override
35-
public boolean isPerformanceManagerMode() {
36-
return false;
37-
}
3833
}

engine/src/main/java/org/terasology/engine/rendering/nui/layers/ingame/metrics/WorldRendererMode.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,4 @@ public String getMetrics() {
2020
public boolean isAvailable() {
2121
return CoreRegistry.get(WorldRenderer.class) != null;
2222
}
23-
24-
@Override
25-
public boolean isPerformanceManagerMode() {
26-
return false;
27-
}
2823
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// Copyright 2021 The Terasology Foundation
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package org.terasology.engine.utilities;
5+
6+
import com.sun.jna.platform.unix.LibC;
7+
8+
import java.io.IOException;
9+
import java.io.UncheckedIOException;
10+
import java.nio.file.Files;
11+
import java.nio.file.Path;
12+
13+
/**
14+
* Monitor process memory usage.
15+
* <p>
16+
* This checks process's total memory usage as seen by the operating system.
17+
* This includes memory not managed by the JVM.
18+
*/
19+
public final class OperatingSystemMemory {
20+
public static final int PAGE_SIZE = 1 << 12; // 4 kB on x86 platforms
21+
22+
private static final Path PROC_STATM = Path.of("/proc/self/statm");
23+
24+
private OperatingSystemMemory() { }
25+
26+
public static boolean isAvailable() {
27+
return OS.IS_LINUX;
28+
}
29+
30+
public static long residentSetSize() {
31+
try {
32+
return STATM.RESIDENT.inBytes(Files.readString(PROC_STATM));
33+
} catch (IOException e) {
34+
throw new UncheckedIOException(e);
35+
}
36+
}
37+
38+
public static long dataAndStackSize() {
39+
try {
40+
return STATM.DATA.inBytes(Files.readString(PROC_STATM));
41+
} catch (IOException e) {
42+
throw new UncheckedIOException(e);
43+
}
44+
}
45+
46+
public static long dataAndStackSizeLimit() {
47+
final LibC.Rlimit dataLimit = new LibC.Rlimit();
48+
LibC.INSTANCE.getrlimit(LibC.RLIMIT_DATA, dataLimit);
49+
return dataLimit.rlim_cur;
50+
}
51+
52+
/**
53+
* The fields of /proc/[pid]/statm
54+
* <p>
55+
* Note from proc(5):
56+
* <blockquote><p>
57+
* Some of these values are inaccurate because of a kernel-internal scalability optimization.
58+
* If accurate values are required, use /proc/[pid]/smaps or /proc/[pid]/smaps_rollup instead,
59+
* which are much slower but provide accurate, detailed information.
60+
* </p></blockquote>
61+
*/
62+
enum STATM {
63+
/** total program size */
64+
SIZE(0),
65+
/** resident set size */
66+
RESIDENT(1),
67+
/** number of resident shared pages */
68+
SHARED(2),
69+
/** text (code) */
70+
TEXT(3),
71+
/** unused since Linux 2.6 */
72+
LIB(4),
73+
/** data + stack */
74+
DATA(5),
75+
/** unused since Linux 2.6 */
76+
DT(6);
77+
78+
private final short index;
79+
80+
STATM(int i) {
81+
index = (short) i;
82+
}
83+
84+
public long rawValue(String line) {
85+
return Long.parseLong(line.split(" ")[index]);
86+
}
87+
88+
public long inBytes(String line) {
89+
return rawValue(line) * PAGE_SIZE;
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)