Skip to content
Merged
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
35 changes: 35 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,41 @@ AS_IF([test "x$enable_criu" != "xno"], [

], [AC_MSG_NOTICE([CRIU support disabled per user request])])

AC_MSG_CHECKING([for log2])
AC_LINK_IFELSE([
AC_LANG_PROGRAM([
#include <math.h>
#include <stdlib.h>
], [
double result = log2 ((double) rand ());
return (int) result;
])
], [
# log2 works without -lm (musl libc)
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_LOG2], [1], [Define if log2 is available])
], [
# Try with -lm (glibc)
LIBS="$LIBS -lm"
AC_LINK_IFELSE([
AC_LANG_PROGRAM([
#include <math.h>
#include <stdlib.h>
], [
double result = log2 ((double) rand ());
return (int) result;
])
], [
# log2 works with -lm
AC_MSG_RESULT([yes (with -lm)])
AC_DEFINE([HAVE_LOG2], [1], [Define if log2 is available])
], [
# log2 not available - restore LIBS and fail
AC_MSG_RESULT([no])
AC_MSG_ERROR([*** log2 function is required but not found])
])
])

FOUND_LIBS=$LIBS
LIBS=""

Expand Down
5 changes: 4 additions & 1 deletion crun.1
Original file line number Diff line number Diff line change
Expand Up @@ -846,7 +846,10 @@ allbox;
l l l l
l l l l .
\fBOCI (x)\fP \fBcgroup 2 value (y)\fP \fBconversion\fP \fBcomment\fP
shares cpu.weight y = (1 + ((x - 2) * 9999) / 262142) T{
shares cpu.weight T{
y=10^((log2(x)^2 + 125 * log2(x)) / 612.0 - 7.0 / 34.0)
T}
T{
convert from [2-262144] to [1-10000]
T}
period cpu.max y = x T{
Expand Down
10 changes: 5 additions & 5 deletions crun.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -712,11 +712,11 @@ they are converted when needed from the cgroup v1 configuration.

## CPU controller

| OCI (x) | cgroup 2 value (y) | conversion | comment |
|---|---|---|---|
| shares | cpu.weight | y = (1 + ((x - 2) \* 9999) / 262142) | convert from [2-262144] to [1-10000]|
| period | cpu.max | y = x| period and quota are written together|
| quota | cpu.max | y = x| period and quota are written together|
| OCI (x) | cgroup 2 value (y) | conversion | comment |
|---------|--------------------|---------------------------------------------------------|---------------------------------------|
| shares | cpu.weight | y=10^((log2(x)^2 + 125 * log2(x)) / 612.0 - 7.0 / 34.0) | convert from [2-262144] to [1-10000] |
| period | cpu.max | y = x | period and quota are written together |
| quota | cpu.max | y = x | period and quota are written together |

## blkio controller

Expand Down
21 changes: 19 additions & 2 deletions src/libcrun/cgroup-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
#include "container.h"
#include "utils.h"

#include <stdint.h>
#include <math.h>

enum
{
CGROUP_MEMORY = 1 << 0,
Expand Down Expand Up @@ -76,8 +79,22 @@ int libcrun_cgroup_pause_unpause_path (const char *cgroup_path, const bool pause
static inline uint64_t
convert_shares_to_weight (uint64_t shares)
{
/* convert linearly from 2-262144 to 1-10000. */
return (1 + ((shares - 2) * 9999) / 262142);
double l, exponent;
Copy link

Choose a reason for hiding this comment

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

suggestion: Variable naming could be more descriptive for clarity.

Consider renaming 'l' to 'log_shares' and 'exponent' to 'weight_exponent' for better readability and maintainability.

Suggested implementation:

  double log_shares, weight_exponent;
  log_shares = log2 ((double) shares);


/* The value of 0 means "unset". */
if (shares == 0)
return 0;
if (shares <= 2)
return 1;
if (shares >= 262144)
return 10000;

l = log2 ((double) shares);

/* Quadratic function which fits min, max, and default. */
exponent = (l * l + 125 * l) / 612.0 - 7.0 / 34.0;

return (uint64_t) ceil (pow (10, exponent));
}

int initialize_cpuset_subsystem (const char *path, libcrun_error_t *err);
Expand Down
2 changes: 1 addition & 1 deletion tests/alpine-build/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM alpine

RUN apk add gcc automake autoconf libtool gettext pkgconf git make musl-dev \
python3 libcap-dev libseccomp-dev yajl-dev argp-standalone go-md2man
python3 libcap-dev libseccomp-dev yajl-dev argp-standalone go-md2man gperf

COPY run-tests.sh /usr/local/bin

Expand Down
31 changes: 17 additions & 14 deletions tests/test_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,23 +291,26 @@ def test_resources_cpu_weight_systemd():
sys.stderr.write("# found wrong CPUWeight for the systemd scope\n")
return 1

run_crun_command(['update', '--cpu-share', '4321', cid])
# this is the expected cpu weight after the conversion from the CPUShares
expected_weight = "165"
for values in [(2, 1), (3, 2), (1024, 100), (260000, 9929), (262144, 10000)]:
cpu_shares = values[0]
# this is the expected cpu weight after the conversion from the CPUShares
expected_weight = str(values[1])

out = run_crun_command(["exec", cid, "/init", "cat", "/sys/fs/cgroup/cpu.weight"])
if expected_weight not in out:
sys.stderr.write("# found wrong CPUWeight %s for the container cgroup\n" % out)
return -1
run_crun_command(['update', '--cpu-share', str(cpu_shares), cid])
Copy link

Choose a reason for hiding this comment

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

suggestion (testing): Test uses substring matching for weight validation, which may lead to false positives.

if expected_weight not in out: may yield false positives (e.g., '100' matches '1000'). Use exact matching or strip whitespace before comparison for accurate validation.


out = subprocess.check_output(['systemctl', 'show','-PCPUWeight', scope ], close_fds=False).decode().strip()
# as above
if out != expected_weight:
out = subprocess.check_output(['systemctl', '--user', 'show','-PCPUWeight', scope ], close_fds=False).decode().strip()
out = run_crun_command(["exec", cid, "/init", "cat", "/sys/fs/cgroup/cpu.weight"])
if expected_weight not in out:
sys.stderr.write("found wrong CPUWeight %s instead of %s for the container cgroup\n" % (out, expected_weight))
return -1
Comment on lines +302 to +304
Copy link

Choose a reason for hiding this comment

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

issue (code-quality): Avoid conditionals in tests. (no-conditionals-in-tests)

ExplanationAvoid complex code, like conditionals, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:

  • loops
  • conditionals

Some ways to fix this:

  • Use parametrized tests to get rid of the loop.
  • Move the complex logic into helpers.
  • Move the complex part into pytest fixtures.

Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / Don't Put Logic in Tests


if out != expected_weight:
sys.stderr.write("# found wrong CPUWeight for the systemd scope\n")
return 1
out = subprocess.check_output(['systemctl', 'show','-PCPUWeight', scope ], close_fds=False).decode().strip()
# as above
if out != expected_weight:
out = subprocess.check_output(['systemctl', '--user', 'show','-PCPUWeight', scope ], close_fds=False).decode().strip()
Comment on lines +308 to +309
Copy link

Choose a reason for hiding this comment

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

issue (code-quality): Avoid conditionals in tests. (no-conditionals-in-tests)

ExplanationAvoid complex code, like conditionals, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:

  • loops
  • conditionals

Some ways to fix this:

  • Use parametrized tests to get rid of the loop.
  • Move the complex logic into helpers.
  • Move the complex part into pytest fixtures.

Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / Don't Put Logic in Tests


if out != expected_weight:
sys.stderr.write("found wrong CPUWeight for the systemd scope\n")
return 1
Comment on lines +311 to +313
Copy link

Choose a reason for hiding this comment

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

issue (code-quality): Avoid conditionals in tests. (no-conditionals-in-tests)

ExplanationAvoid complex code, like conditionals, in test functions.

Google's software engineering guidelines says:
"Clear tests are trivially correct upon inspection"
To reach that avoid complex code in tests:

  • loops
  • conditionals

Some ways to fix this:

  • Use parametrized tests to get rid of the loop.
  • Move the complex logic into helpers.
  • Move the complex part into pytest fixtures.

Complexity is most often introduced in the form of logic. Logic is defined via the imperative parts of programming languages such as operators, loops, and conditionals. When a piece of code contains logic, you need to do a bit of mental computation to determine its result instead of just reading it off of the screen. It doesn't take much logic to make a test more difficult to reason about.

Software Engineering at Google / Don't Put Logic in Tests

finally:
if cid is not None:
run_crun_command(["delete", "-f", cid])
Expand Down
Loading