Skip to content

Commit

Permalink
Merge branch 'ant-media:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Himpoke authored Nov 5, 2024
2 parents f01c59e + 1571e8d commit 402269c
Show file tree
Hide file tree
Showing 3 changed files with 418 additions and 12 deletions.
162 changes: 160 additions & 2 deletions src/main/java/io/antmedia/SystemUtils.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
package io.antmedia;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;

import javax.management.MBeanServer;

import org.apache.commons.lang3.StringUtils;
import org.bytedeco.javacpp.Pointer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -62,6 +69,8 @@
public class SystemUtils {

public static final String HEAPDUMP_HPROF = "heapdump.hprof";
public static final long MAX_CONTAINER_MEMORY_LIMIT_BYTES = 109951162777600L; //100TB
public static final String MAX_MEMORY_CGROUP_V2 = "max";

/**
* Obtain Operating System's name.
Expand Down Expand Up @@ -104,6 +113,8 @@ public class SystemUtils {
public static final int WINDOWS = 2;

public static final int OS_TYPE;

public static Boolean containerized = null;

static {
String osName = SystemUtils.osName.toLowerCase();
Expand Down Expand Up @@ -227,6 +238,25 @@ public static long osCommittedVirtualMemory() {
* @return bytes size
*/
public static long osTotalPhysicalMemory() {
if(containerized == null){
containerized = isContainerized();
}

if(containerized) {
try{
return getMemoryLimitFromCgroup();

}catch (IOException e) {
logger.debug("Could not get memory limit from c group. {}", e.getMessage());
}
}

return getTotalPhysicalMemorySize();

}

public static long getTotalPhysicalMemorySize(){

final OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
if (osBean instanceof UnixOperatingSystemMXBean) {
return (((UnixOperatingSystemMXBean) osBean).getTotalPhysicalMemorySize());
Expand All @@ -240,8 +270,10 @@ public static long osTotalPhysicalMemory() {
return -1L;
}
}

}


/**
* Obtain Free Physical Memory from Operating System's RAM.
*
Expand Down Expand Up @@ -273,7 +305,21 @@ public static long osFreePhysicalMemory() {
* @return the amount of available physical memory
*/
public static long osAvailableMemory() {
return Pointer.availablePhysicalBytes();
if(containerized == null){
containerized = isContainerized();
}

if(containerized) {
try{
return getMemAvailableFromCgroup();

}catch (IOException e) {
logger.debug("Could not get mem available from cgroup. Will return os free physical memory instead.");
return osFreePhysicalMemory();
}
}

return availablePhysicalBytes();
}

/**
Expand Down Expand Up @@ -698,7 +744,6 @@ public static void getHeapDump(String filepath) {
}
}


private static HotSpotDiagnosticMXBean getHotspotMBean() {
try {
synchronized (SystemUtils.class) {
Expand All @@ -715,5 +760,118 @@ private static HotSpotDiagnosticMXBean getHotspotMBean() {
}
return hotspotMBean;
}

public static long availablePhysicalBytes(){
return Pointer.availablePhysicalBytes();
}

public static boolean isContainerized() {
try {
Path dockerEnvPath = Paths.get("/.dockerenv");

// 1. Check for .dockerenv file
if (Files.exists(dockerEnvPath)) {
logger.debug("Container detected via .dockerenv file");
return true;
}

// 2. Check env variable
String container = System.getenv("container");
if(StringUtils.isNotBlank(container)){
logger.debug("Container detected via env variable.");
return true;
}

// 3. Check cgroup info
Path cgroupPath = Paths.get("/proc/self/cgroup");
if (Files.exists(cgroupPath)) {
List<String> cgroupContent = Files.readAllLines(cgroupPath);
for (String line : cgroupContent) {
if (line.contains("docker") ||
line.contains("lxc") ||
line.contains("kubepods") ||
line.contains("containerd")) {
logger.debug("Container detected via cgroup: {}", line);
return true;
}
}
}

} catch (Exception e) {
logger.error("Error during container detection: {}", e.getMessage());

}

return false;
}

public static Long getMemoryLimitFromCgroup() throws IOException {
long memoryLimit;

// Try reading memory limit for cgroups v1
if (Files.exists(Paths.get("/sys/fs/cgroup/memory/memory.limit_in_bytes"))) {
String memoryLimitString = readCgroupFile("/sys/fs/cgroup/memory/memory.limit_in_bytes");

memoryLimit = Long.parseLong(memoryLimitString);

// In cgroups v1, if the memory limit for a container isn't set, it typically returns 9223372036854771712 (2^63-1).
// However, this value may vary based on the architecture.
// Therefore, we consider it acceptable if the returned memory limit exceeds 100TB, indicating that the limit is not configured using cgroups.
if(memoryLimit > MAX_CONTAINER_MEMORY_LIMIT_BYTES || memoryLimit == 0 || memoryLimit == -1) {
memoryLimit = getTotalPhysicalMemorySize();
}

// Try reading memory limit for cgroups v2
} else if (Files.exists(Paths.get("/sys/fs/cgroup/memory.max"))) {
String memoryLimitString = readCgroupFile("/sys/fs/cgroup/memory.max");

if(MAX_MEMORY_CGROUP_V2.equals(memoryLimitString)){ // memory limit is not set using cgroups v2
memoryLimit = getTotalPhysicalMemorySize();
}else{
memoryLimit = Long.parseLong(memoryLimitString);
}


} else {
logger.debug("Could not find cgroup max memory file. Will return os physical memory instead.");
return getTotalPhysicalMemorySize();
}

return memoryLimit;
}

public static Long getMemAvailableFromCgroup() throws IOException {
Long memoryUsage;
Long memoryLimit;

// Try reading memory usage and limit for cgroups v1
if (Files.exists(Paths.get("/sys/fs/cgroup/memory/memory.usage_in_bytes")) &&
Files.exists(Paths.get("/sys/fs/cgroup/memory/memory.limit_in_bytes"))) {
String memoryUsageString = readCgroupFile("/sys/fs/cgroup/memory/memory.usage_in_bytes");
memoryUsage = Long.parseLong(memoryUsageString);
memoryLimit = getMemoryLimitFromCgroup();

// Try reading memory usage and limit for cgroups v2
} else if (Files.exists(Paths.get("/sys/fs/cgroup/memory.current")) &&
Files.exists(Paths.get("/sys/fs/cgroup/memory.max"))) {

String memoryUsageString = readCgroupFile("/sys/fs/cgroup/memory.current");
memoryUsage = Long.parseLong(memoryUsageString);
memoryLimit = getMemoryLimitFromCgroup();

} else {
logger.debug("Could not find cgroup memory files. Will return os free physical memory instead.");
return osFreePhysicalMemory();
}

// Calculate available memory
return memoryLimit - memoryUsage;
}

public static String readCgroupFile(String filePath) throws IOException {
try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {
return reader.readLine().trim();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2150,7 +2150,7 @@ public void testAddIPCamera() {

streamSourceRest.setAppCtx(appContext);

StatsCollector monitorService = new StatsCollector();
StatsCollector monitorService = spy(StatsCollector.class);

when(appContext.getBean(IStatsCollector.BEAN_NAME)).thenReturn(monitorService);

Expand Down Expand Up @@ -2181,6 +2181,8 @@ public void testAddIPCamera() {
int cpuLoad2 = 70;
int cpuLimit2 = 80;

when(monitorService.getMemoryLoad()).thenReturn(20);


monitorService.setCpuLimit(cpuLimit2);
monitorService.setCpuLoad(cpuLoad2);
Expand Down
Loading

0 comments on commit 402269c

Please sign in to comment.