Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions src/hotspot/os/linux/cgroupSubsystem_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ CgroupSubsystem* CgroupSubsystemFactory::create() {
CgroupV1MemoryController* memory = nullptr;
CgroupV1Controller* cpuset = nullptr;
CgroupV1CpuController* cpu = nullptr;
CgroupV1Controller* cpuacct = nullptr;
CgroupV1CpuacctController* cpuacct = nullptr;
CgroupV1Controller* pids = nullptr;
CgroupInfo cg_infos[CG_INFO_LENGTH];
u1 cg_type_flags = INVALID_CGROUPS_GENERIC;
Expand Down Expand Up @@ -105,9 +105,10 @@ CgroupSubsystem* CgroupSubsystemFactory::create() {
CgroupV2CpuController* cpu = new CgroupV2CpuController(CgroupV2Controller(cg_infos[CPU_IDX]._mount_path,
cg_infos[CPU_IDX]._cgroup_path,
cg_infos[CPU_IDX]._read_only));
CgroupV2CpuacctController* cpuacct = new CgroupV2CpuacctController(cpu);
log_debug(os, container)("Detected cgroups v2 unified hierarchy");
cleanup(cg_infos);
return new CgroupV2Subsystem(memory, cpu, mem_other);
return new CgroupV2Subsystem(memory, cpu, cpuacct, mem_other);
}

/*
Expand Down Expand Up @@ -150,7 +151,7 @@ CgroupSubsystem* CgroupSubsystemFactory::create() {
cpu = new CgroupV1CpuController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only));
cpu->set_subsystem_path(info._cgroup_path);
} else if (strcmp(info._name, "cpuacct") == 0) {
cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only);
cpuacct = new CgroupV1CpuacctController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only));
cpuacct->set_subsystem_path(info._cgroup_path);
} else if (strcmp(info._name, "pids") == 0) {
pids = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only);
Expand Down Expand Up @@ -856,6 +857,10 @@ jlong CgroupSubsystem::memory_soft_limit_in_bytes() {
return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem);
}

jlong CgroupSubsystem::memory_throttle_limit_in_bytes() {
return memory_controller()->controller()->memory_throttle_limit_in_bytes();
}

jlong CgroupSubsystem::memory_usage_in_bytes() {
return memory_controller()->controller()->memory_usage_in_bytes();
}
Expand Down Expand Up @@ -884,6 +889,10 @@ int CgroupSubsystem::cpu_shares() {
return cpu_controller()->controller()->cpu_shares();
}

jlong CgroupSubsystem::cpu_usage_in_micros() {
return cpuacct_controller()->cpu_usage_in_micros();
}

void CgroupSubsystem::print_version_specific_info(outputStream* st) {
julong phys_mem = os::Linux::physical_memory();
memory_controller()->controller()->print_version_specific_info(st, phys_mem);
Expand Down
19 changes: 18 additions & 1 deletion src/hotspot/os/linux/cgroupSubsystem_linux.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -216,6 +216,18 @@ class CgroupCpuController: public CHeapObj<mtInternal> {
virtual const char* cgroup_path() = 0;
};

// Pure virtual class representing version agnostic CPU accounting controllers
class CgroupCpuacctController: public CHeapObj<mtInternal> {
public:
virtual jlong cpu_usage_in_micros() = 0;
virtual bool needs_hierarchy_adjustment() = 0;
virtual bool is_read_only() = 0;
virtual const char* subsystem_path() = 0;
virtual void set_subsystem_path(const char* cgroup_path) = 0;
virtual const char* mount_point() = 0;
virtual const char* cgroup_path() = 0;
};

// Pure virtual class representing version agnostic memory controllers
class CgroupMemoryController: public CHeapObj<mtInternal> {
public:
Expand All @@ -224,6 +236,7 @@ class CgroupMemoryController: public CHeapObj<mtInternal> {
virtual jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) = 0;
virtual jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) = 0;
virtual jlong memory_soft_limit_in_bytes(julong upper_bound) = 0;
virtual jlong memory_throttle_limit_in_bytes() = 0;
virtual jlong memory_max_usage_in_bytes() = 0;
virtual jlong rss_usage_in_bytes() = 0;
virtual jlong cache_usage_in_bytes() = 0;
Expand All @@ -250,15 +263,19 @@ class CgroupSubsystem: public CHeapObj<mtInternal> {
virtual const char * container_type() = 0;
virtual CachingCgroupController<CgroupMemoryController>* memory_controller() = 0;
virtual CachingCgroupController<CgroupCpuController>* cpu_controller() = 0;
virtual CgroupCpuacctController* cpuacct_controller() = 0;

int cpu_quota();
int cpu_period();
int cpu_shares();

jlong cpu_usage_in_micros();

jlong memory_usage_in_bytes();
jlong memory_and_swap_limit_in_bytes();
jlong memory_and_swap_usage_in_bytes();
jlong memory_soft_limit_in_bytes();
jlong memory_throttle_limit_in_bytes();
jlong memory_max_usage_in_bytes();
jlong rss_usage_in_bytes();
jlong cache_usage_in_bytes();
Expand Down
15 changes: 14 additions & 1 deletion src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,10 +248,16 @@ jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) {
}
}

jlong CgroupV1MemoryController::memory_throttle_limit_in_bytes() {
// Log this string at trace level so as to make tests happy.
log_trace(os, container)("Memory Throttle Limit is not supported.");
return OSCONTAINER_ERROR; // not supported
}

// Constructor
CgroupV1Subsystem::CgroupV1Subsystem(CgroupV1Controller* cpuset,
CgroupV1CpuController* cpu,
CgroupV1Controller* cpuacct,
CgroupV1CpuacctController* cpuacct,
CgroupV1Controller* pids,
CgroupV1MemoryController* memory) :
_cpuset(cpuset),
Expand Down Expand Up @@ -416,6 +422,13 @@ int CgroupV1CpuController::cpu_shares() {
return shares_int;
}

jlong CgroupV1CpuacctController::cpu_usage_in_micros() {
julong cpu_usage;
CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpuacct.usage", "CPU Usage", cpu_usage);
// Output is in nanoseconds, convert to microseconds.
return (jlong)cpu_usage / 1000;
}

Comment on lines +425 to +431
Copy link

@gerard-ziemski gerard-ziemski Jun 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @gerard-ziemski, thanks for making a comment in an OpenJDK project!

All comments and discussions in the OpenJDK Community must be made available under the OpenJDK Terms of Use. If you already are an OpenJDK Author, Committer or Reviewer, please click here to open a new issue so that we can record that fact. Please Use "Add GitHub user gerard-ziemski" for the summary.

If you are not an OpenJDK Author, Committer or Reviewer, simply check the box below to accept the OpenJDK Terms of Use for your comments.

Your comment will be automatically restored once you have accepted the OpenJDK Terms of Use.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I centered it around cgroup v2, which only reports the usage in micros. Cgroup v1 is deprecated for most systems so shouldn't really be used. It made more sense to use micros instead of padding the value most will see with a bunch of zeros.

/* pids_max
*
* Return the maximum number of tasks available to the process
Expand Down
37 changes: 34 additions & 3 deletions src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -82,6 +82,7 @@ class CgroupV1MemoryController final : public CgroupMemoryController {
jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override;
jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swap) override;
jlong memory_soft_limit_in_bytes(julong upper_bound) override;
jlong memory_throttle_limit_in_bytes() override;
jlong memory_max_usage_in_bytes() override;
jlong rss_usage_in_bytes() override;
jlong cache_usage_in_bytes() override;
Expand Down Expand Up @@ -140,12 +141,41 @@ class CgroupV1CpuController final : public CgroupCpuController {
}
};

class CgroupV1CpuacctController final : public CgroupCpuacctController {

private:
CgroupV1Controller _reader;
CgroupV1Controller* reader() { return &_reader; }
public:
jlong cpu_usage_in_micros() override;
void set_subsystem_path(const char *cgroup_path) override {
reader()->set_subsystem_path(cgroup_path);
}
bool is_read_only() override {
return reader()->is_read_only();
}
const char* subsystem_path() override {
return reader()->subsystem_path();
}
const char* mount_point() override {
return reader()->mount_point();
}
bool needs_hierarchy_adjustment() override {
return reader()->needs_hierarchy_adjustment();
}
const char* cgroup_path() override { return reader()->cgroup_path(); }

public:
CgroupV1CpuacctController(const CgroupV1Controller& reader) : _reader(reader) {
}
};

class CgroupV1Subsystem: public CgroupSubsystem {

public:
CgroupV1Subsystem(CgroupV1Controller* cpuset,
CgroupV1CpuController* cpu,
CgroupV1Controller* cpuacct,
CgroupV1CpuacctController* cpuacct,
CgroupV1Controller* pids,
CgroupV1MemoryController* memory);

Expand All @@ -165,13 +195,14 @@ class CgroupV1Subsystem: public CgroupSubsystem {
}
CachingCgroupController<CgroupMemoryController>* memory_controller() { return _memory; }
CachingCgroupController<CgroupCpuController>* cpu_controller() { return _cpu; }
CgroupCpuacctController* cpuacct_controller() { return _cpuacct; }

private:
/* controllers */
CachingCgroupController<CgroupMemoryController>* _memory = nullptr;
CgroupV1Controller* _cpuset = nullptr;
CachingCgroupController<CgroupCpuController>* _cpu = nullptr;
CgroupV1Controller* _cpuacct = nullptr;
CgroupV1CpuacctController* _cpuacct = nullptr;
CgroupV1Controller* _pids = nullptr;

};
Expand Down
26 changes: 23 additions & 3 deletions src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, 2025, Red Hat Inc.
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -114,12 +115,14 @@ int CgroupV2CpuController::cpu_quota() {
// Constructor
CgroupV2Subsystem::CgroupV2Subsystem(CgroupV2MemoryController * memory,
CgroupV2CpuController* cpu,
CgroupV2CpuacctController* cpuacct,
CgroupV2Controller unified) :
_unified(unified) {
CgroupUtil::adjust_controller(memory);
CgroupUtil::adjust_controller(cpu);
_memory = new CachingCgroupController<CgroupMemoryController>(memory);
_cpu = new CachingCgroupController<CgroupCpuController>(cpu);
_cpuacct = cpuacct;
}

bool CgroupV2Subsystem::is_containerized() {
Expand Down Expand Up @@ -152,6 +155,17 @@ int CgroupV2CpuController::cpu_period() {
return period;
}

jlong CgroupV2CpuController::cpu_usage_in_micros() {
julong cpu_usage;
bool is_ok = reader()->read_numerical_key_value("/cpu.stat", "usage_usec", &cpu_usage);
if (!is_ok) {
log_trace(os, container)("CPU Usage failed: %d", OSCONTAINER_ERROR);
return OSCONTAINER_ERROR;
}
log_trace(os, container)("CPU Usage is: " JULONG_FORMAT, cpu_usage);
return (jlong)cpu_usage;
}

/* memory_usage_in_bytes
*
* Return the amount of used memory used by this cgroup and descendents
Expand All @@ -173,10 +187,16 @@ jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong phys_mem) {
return mem_soft_limit;
}

jlong CgroupV2MemoryController::memory_throttle_limit_in_bytes() {
jlong mem_throttle_limit;
CONTAINER_READ_NUMBER_CHECKED_MAX(reader(), "/memory.high", "Memory Throttle Limit", mem_throttle_limit);
return mem_throttle_limit;
}

jlong CgroupV2MemoryController::memory_max_usage_in_bytes() {
// Log this string at trace level so as to make tests happy.
log_trace(os, container)("Maximum Memory Usage is not supported.");
return OSCONTAINER_ERROR; // not supported
julong mem_max_usage;
CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.peak", "Maximum Memory Usage", mem_max_usage);
return mem_max_usage;
}

jlong CgroupV2MemoryController::rss_usage_in_bytes() {
Expand Down
34 changes: 34 additions & 0 deletions src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, 2024, Red Hat Inc.
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -61,6 +62,34 @@ class CgroupV2CpuController: public CgroupCpuController {
int cpu_quota() override;
int cpu_period() override;
int cpu_shares() override;
jlong cpu_usage_in_micros();
bool is_read_only() override {
return reader()->is_read_only();
}
const char* subsystem_path() override {
return reader()->subsystem_path();
}
bool needs_hierarchy_adjustment() override {
return reader()->needs_hierarchy_adjustment();
}
void set_subsystem_path(const char* cgroup_path) override {
reader()->set_subsystem_path(cgroup_path);
}
const char* mount_point() override { return reader()->mount_point(); }
const char* cgroup_path() override { return reader()->cgroup_path(); }
};

class CgroupV2CpuacctController: public CgroupCpuacctController {
private:
CgroupV2CpuController* _reader;
CgroupV2CpuController* reader() { return _reader; }
public:
CgroupV2CpuacctController(CgroupV2CpuController* reader) : _reader(reader) {
}
// In cgroup v2, cpu usage is a part of the cpu controller.
jlong cpu_usage_in_micros() override {
return reader()->cpu_usage_in_micros();
}
bool is_read_only() override {
return reader()->is_read_only();
}
Expand Down Expand Up @@ -89,6 +118,7 @@ class CgroupV2MemoryController final: public CgroupMemoryController {
jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swp) override;
jlong memory_and_swap_usage_in_bytes(julong host_mem, julong host_swp) override;
jlong memory_soft_limit_in_bytes(julong upper_bound) override;
jlong memory_throttle_limit_in_bytes() override;
jlong memory_usage_in_bytes() override;
jlong memory_max_usage_in_bytes() override;
jlong rss_usage_in_bytes() override;
Expand Down Expand Up @@ -118,11 +148,14 @@ class CgroupV2Subsystem: public CgroupSubsystem {
CachingCgroupController<CgroupMemoryController>* _memory = nullptr;
CachingCgroupController<CgroupCpuController>* _cpu = nullptr;

CgroupCpuacctController* _cpuacct = nullptr;

CgroupV2Controller* unified() { return &_unified; }

public:
CgroupV2Subsystem(CgroupV2MemoryController * memory,
CgroupV2CpuController* cpu,
CgroupV2CpuacctController* cpuacct,
CgroupV2Controller unified);

char * cpu_cpuset_cpus() override;
Expand All @@ -137,6 +170,7 @@ class CgroupV2Subsystem: public CgroupSubsystem {
}
CachingCgroupController<CgroupMemoryController>* memory_controller() override { return _memory; }
CachingCgroupController<CgroupCpuController>* cpu_controller() override { return _cpu; }
CgroupCpuacctController* cpuacct_controller() override { return _cpuacct; };
};

#endif // CGROUP_V2_SUBSYSTEM_LINUX_HPP
12 changes: 11 additions & 1 deletion src/hotspot/os/linux/osContainer_linux.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -122,6 +122,11 @@ jlong OSContainer::memory_soft_limit_in_bytes() {
return cgroup_subsystem->memory_soft_limit_in_bytes();
}

jlong OSContainer::memory_throttle_limit_in_bytes() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
return cgroup_subsystem->memory_throttle_limit_in_bytes();
}

jlong OSContainer::memory_usage_in_bytes() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
return cgroup_subsystem->memory_usage_in_bytes();
Expand Down Expand Up @@ -177,6 +182,11 @@ int OSContainer::cpu_shares() {
return cgroup_subsystem->cpu_shares();
}

jlong OSContainer::cpu_usage_in_micros() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
return cgroup_subsystem->cpu_usage_in_micros();
}

jlong OSContainer::pids_max() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
return cgroup_subsystem->pids_max();
Expand Down
5 changes: 4 additions & 1 deletion src/hotspot/os/linux/osContainer_linux.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -54,6 +54,7 @@ class OSContainer: AllStatic {
static jlong memory_and_swap_limit_in_bytes();
static jlong memory_and_swap_usage_in_bytes();
static jlong memory_soft_limit_in_bytes();
static jlong memory_throttle_limit_in_bytes();
static jlong memory_usage_in_bytes();
static jlong memory_max_usage_in_bytes();
static jlong rss_usage_in_bytes();
Expand All @@ -69,6 +70,8 @@ class OSContainer: AllStatic {

static int cpu_shares();

static jlong cpu_usage_in_micros();

static jlong pids_max();
static jlong pids_current();
};
Expand Down
Loading