-
Notifications
You must be signed in to change notification settings - Fork 60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Limit gProfiler memory & CPU usage and --log-usage support in exe mode. #564
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,17 @@ | |
|
||
import psutil | ||
|
||
CGROUPFS_ROOT = "/sys/fs/cgroup" # TODO extract from /proc/mounts, this may change | ||
from granulate_utils.linux.cgroups.cgroup import find_v1_hierarchies, find_v2_hierarchy | ||
|
||
|
||
# TODO(Creatone): Move it to granulate-utils. Consider change. | ||
def _obtain_cgroup_controller_path(cgroup: str, controller: str) -> str: | ||
cgroup_v1_hierarchies = find_v1_hierarchies() | ||
if len(cgroup_v1_hierarchies) != 1: | ||
assert controller in cgroup_v1_hierarchies | ||
return f"{cgroup_v1_hierarchies[controller]}{cgroup}" | ||
else: | ||
return f"{find_v2_hierarchy()}/{controller}{cgroup}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this will work now - because cgroups v2 files are different. For example - there is no I created a ticket for cgroups v2 support. Until that's done, I suggest you raise an exception here if v2 is in use. Also I see that granulate-utils does this check: |
||
|
||
|
||
class UsageLoggerInterface: | ||
|
@@ -30,7 +40,8 @@ class CpuUsageLogger(UsageLoggerInterface): | |
|
||
def __init__(self, logger: logging.LoggerAdapter, cgroup: str): | ||
self._logger = logger | ||
self._cpuacct_usage = Path(f"{CGROUPFS_ROOT}{cgroup}cpuacct/cpuacct.usage") | ||
cpu_root = _obtain_cgroup_controller_path(cgroup, 'cpuacct') | ||
self._cpuacct_usage = Path(os.path.join(cpu_root, "cpuacct.usage")) | ||
self._last_usage: Optional[int] = None | ||
self._last_ts: Optional[float] = None | ||
|
||
|
@@ -78,7 +89,7 @@ class MemoryUsageLogger(UsageLoggerInterface): | |
|
||
def __init__(self, logger: logging.LoggerAdapter, cgroup: str): | ||
self._logger = logger | ||
memory_root = f"{CGROUPFS_ROOT}{cgroup}memory" | ||
memory_root = _obtain_cgroup_controller_path(cgroup, 'memory') | ||
self._memory_usage = Path(os.path.join(memory_root, "memory.usage_in_bytes")) | ||
self._memory_watermark = Path(os.path.join(memory_root, "memory.max_usage_in_bytes")) | ||
self._last_usage: Optional[int] = None | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
# | ||
# Copyright (c) Granulate. All rights reserved. | ||
# Licensed under the AGPL3 License. See LICENSE.md in the project root for license information. | ||
# | ||
import os | ||
import subprocess | ||
from pathlib import Path | ||
from subprocess import Popen | ||
from typing import List | ||
|
||
import pytest | ||
from docker import DockerClient | ||
from docker.models.images import Image | ||
|
||
from tests.utils import run_privileged_container, _print_process_output | ||
|
||
|
||
def test_cgroup_limit_container( | ||
docker_client: DockerClient, | ||
gprofiler_docker_image: Image, | ||
output_directory: Path, | ||
) -> None: | ||
logs = run_privileged_container(docker_client, gprofiler_docker_image, | ||
command=['-v', '--limit-cpu', '0.5', '--limit-memory', '1048576', '-o', | ||
str(output_directory)]) | ||
|
||
limit_log = "Trying to set resource limits, cpu='0.5' cores and memory='1024.00' MB." | ||
|
||
assert limit_log not in logs | ||
|
||
|
||
def test_cgroup_limit_privileged_executable( | ||
gprofiler_exe: Path, | ||
output_directory: Path, | ||
) -> None: | ||
os.mkdir(output_directory) | ||
|
||
command = ( | ||
['sudo', str(gprofiler_exe), '-v', '--limit-cpu', '0.5', | ||
'--limit-memory', str((1 << 30)), '-o', str(output_directory), "-d", "5", | ||
"--no-java", "--no-python", "--no-php", "--no-ruby", "--no-nodejs", "--no-dotnet"] | ||
) | ||
|
||
popen = Popen(command, stdout=subprocess.PIPE) | ||
assert popen.wait() == 0 | ||
stdout, _ = popen.communicate() | ||
logs = stdout.decode("utf-8").splitlines() | ||
limit_log = "Trying to set resource limits, cpu='0.5' cores and memory='1024.00' MB." | ||
|
||
present = False | ||
for line in logs: | ||
if limit_log in line: | ||
present = True | ||
assert present | ||
|
||
|
||
# Not implemented yet. | ||
def test_cgroup_try_limit_no_privileged_executable(): | ||
assert False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I specific no CPU limit? i.e
--limit-cpu none
should be a possible parameter, not necessarily this way, but you should be able to limit ONLY the memory or CPU.