Skip to content

Commit a6006f3

Browse files
authored
Update process memory metrics to report OS resident memory (#17482)
* Use resident memory for process metrics across platforms * Align process memory metric with top
1 parent da250b8 commit a6006f3

1 file changed

Lines changed: 112 additions & 1 deletion

File tree

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/ProcessMetrics.java

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,38 @@
2222
import org.apache.iotdb.commons.service.metric.enums.Tag;
2323
import org.apache.iotdb.metrics.AbstractMetricService;
2424
import org.apache.iotdb.metrics.MetricConstant;
25+
import org.apache.iotdb.metrics.config.MetricConfig;
26+
import org.apache.iotdb.metrics.config.MetricConfigDescriptor;
2527
import org.apache.iotdb.metrics.metricsets.IMetricSet;
2628
import org.apache.iotdb.metrics.utils.MetricLevel;
2729
import org.apache.iotdb.metrics.utils.MetricType;
2830
import org.apache.iotdb.metrics.utils.SystemMetric;
2931

32+
import com.sun.jna.Library;
33+
import com.sun.jna.Native;
34+
import com.sun.jna.Structure;
35+
import com.sun.jna.platform.win32.BaseTSD.SIZE_T;
36+
import com.sun.jna.platform.win32.Kernel32;
37+
import com.sun.jna.platform.win32.WinNT;
3038
import com.sun.management.OperatingSystemMXBean;
39+
import org.slf4j.Logger;
40+
import org.slf4j.LoggerFactory;
3141

42+
import java.io.BufferedReader;
43+
import java.io.IOException;
44+
import java.io.InputStreamReader;
3245
import java.lang.management.ManagementFactory;
46+
import java.nio.file.Files;
47+
import java.nio.file.Path;
48+
import java.nio.file.Paths;
3349

3450
public class ProcessMetrics implements IMetricSet {
51+
private static final Logger LOGGER = LoggerFactory.getLogger(ProcessMetrics.class);
52+
private static final MetricConfig CONFIG = MetricConfigDescriptor.getInstance().getMetricConfig();
3553
private final OperatingSystemMXBean sunOsMxBean;
3654
private final Runtime runtime;
3755
private static final String PROCESS = "process";
56+
private static final String LINUX_RSS_PREFIX = "VmRSS:";
3857
private long lastUpdateTime = 0L;
3958
private volatile long processCpuLoad = 0L;
4059
private volatile long processCpuTime = 0L;
@@ -213,7 +232,68 @@ private void removeProcessStatusInfo(AbstractMetricService metricService) {
213232
}
214233

215234
private long getProcessUsedMemory() {
216-
return runtime.totalMemory() - runtime.freeMemory();
235+
long residentMemory = getResidentMemory();
236+
return residentMemory > 0 ? residentMemory : runtime.totalMemory() - runtime.freeMemory();
237+
}
238+
239+
private long getResidentMemory() {
240+
if (CONFIG.getPid().isEmpty()) {
241+
return 0L;
242+
}
243+
try {
244+
switch (CONFIG.getSystemType()) {
245+
case LINUX:
246+
return getLinuxResidentMemory();
247+
case MAC:
248+
return getMacResidentMemory();
249+
case WINDOWS:
250+
return getWindowsResidentMemory();
251+
default:
252+
return 0L;
253+
}
254+
} catch (Exception e) {
255+
LOGGER.debug("Failed to get process resident memory for pid {}", CONFIG.getPid(), e);
256+
return 0L;
257+
}
258+
}
259+
260+
private long getLinuxResidentMemory() throws IOException {
261+
Path statusPath = Paths.get(String.format("/proc/%s/status", CONFIG.getPid()));
262+
if (!Files.exists(statusPath)) {
263+
return 0L;
264+
}
265+
for (String line : Files.readAllLines(statusPath)) {
266+
if (line.startsWith(LINUX_RSS_PREFIX)) {
267+
String[] parts = line.trim().split("\\s+");
268+
if (parts.length >= 2) {
269+
return Long.parseLong(parts[1]) * 1024L;
270+
}
271+
}
272+
}
273+
return 0L;
274+
}
275+
276+
private long getMacResidentMemory() throws IOException, InterruptedException {
277+
Process process = runtime.exec(new String[] {"ps", "-o", "rss=", "-p", CONFIG.getPid()});
278+
try (BufferedReader input =
279+
new BufferedReader(new InputStreamReader(process.getInputStream()))) {
280+
String line = input.readLine();
281+
int exitCode = process.waitFor();
282+
if (exitCode == 0 && line != null && !line.trim().isEmpty()) {
283+
return Long.parseLong(line.trim()) * 1024L;
284+
}
285+
}
286+
return 0L;
287+
}
288+
289+
private long getWindowsResidentMemory() {
290+
WinNT.HANDLE hProcess = Kernel32.INSTANCE.GetCurrentProcess();
291+
ProcessMemoryCounters counters = new ProcessMemoryCounters();
292+
boolean success = PsapiExt.INSTANCE.GetProcessMemoryInfo(hProcess, counters, counters.size());
293+
if (!success) {
294+
return 0L;
295+
}
296+
return counters.workingSetSize.longValue();
217297
}
218298

219299
private long getProcessStatus() {
@@ -233,4 +313,35 @@ private double getProcessMemoryRatio() {
233313
long totalPhysicalMemorySize = sunOsMxBean.getTotalPhysicalMemorySize();
234314
return (double) processUsedMemory / (double) totalPhysicalMemorySize * 100;
235315
}
316+
317+
public interface PsapiExt extends Library {
318+
PsapiExt INSTANCE = Native.load("psapi", PsapiExt.class);
319+
320+
boolean GetProcessMemoryInfo(WinNT.HANDLE process, ProcessMemoryCounters counters, int size);
321+
}
322+
323+
@Structure.FieldOrder({
324+
"cb",
325+
"pageFaultCount",
326+
"peakWorkingSetSize",
327+
"workingSetSize",
328+
"quotaPeakPagedPoolUsage",
329+
"quotaPagedPoolUsage",
330+
"quotaPeakNonPagedPoolUsage",
331+
"quotaNonPagedPoolUsage",
332+
"pagefileUsage",
333+
"peakPagefileUsage"
334+
})
335+
public static class ProcessMemoryCounters extends Structure {
336+
public int cb = size();
337+
public int pageFaultCount;
338+
public SIZE_T peakWorkingSetSize;
339+
public SIZE_T workingSetSize;
340+
public SIZE_T quotaPeakPagedPoolUsage;
341+
public SIZE_T quotaPagedPoolUsage;
342+
public SIZE_T quotaPeakNonPagedPoolUsage;
343+
public SIZE_T quotaNonPagedPoolUsage;
344+
public SIZE_T pagefileUsage;
345+
public SIZE_T peakPagefileUsage;
346+
}
236347
}

0 commit comments

Comments
 (0)