Skip to content

Conversation

@kolyshkin
Copy link
Contributor

The existing function, ConvertCPUSharesToCgroupV2Value, do not have a way to return an error, and thus can accept invalid cgroup v1 (cpu-shares) values and can return invalid cgroup v2 (cpu-weight) values.

Add a new one, ConvertCPUSharesToCPUWeight, which is identical but can return meaningful errors. Mark the old one as deprecated. Amend the test case to test the new implementation (and, since both are using the same formula, existing implementation is tested, too, except for 0).

Related to opencontainers/runc#4755

The existing function, ConvertCPUSharesToCgroupV2Value, do not have a
way to return an error, and thus can accept invalid cgroup v1
(cpu-shares) values and can return invalid cgroup v2 (cpu-weight)
values.

Add a new one, ConvertCPUSharesToCPUWeight, which is identical but can
return meaningful errors. Mark the old one as deprecated. Amend the test
case to test the new implementation (and, since both are using the same
formula, existing implementation is tested, too, except for 0).

Related to runc issue 4755.

Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
@kolyshkin
Copy link
Contributor Author

@opencontainers/cgroups-maintainers PTAL

@haircommander
Copy link
Contributor

LGTM

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

thx! found some minor issues, and left a suggestion

// the formula for cpuShares is y = (1 + ((x - 2) * 9999) / 262142)
// convert from [2-262144] to [1-10000]
// 262144 comes from Linux kernel definition "#define MAX_SHARES (1UL << 18)"
// there is need to convert from the cgroup v1 configuration to cgroup v2.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// there is need to convert from the cgroup v1 configuration to cgroup v2.
// there is a need to convert from the cgroup v1 configuration to cgroup v2.

t.Errorf("ConvertCPUSharesToCPUWeight(%d): expected error, got nil", tc.in)
}
} else if err != nil {
t.Errorf("ConvertCPUSharesToCPUWeight(%d): expected error, got nil", tc.in)
Copy link
Member

Choose a reason for hiding this comment

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

The error message here doesn't match what's expected (we do not expect an error here)

Comment on lines +548 to +549
for _, tc := range cases {
got, err := ConvertCPUSharesToCPUWeight(tc.in)
Copy link
Member

Choose a reason for hiding this comment

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

We might as well make it a subtests; for the "should have no error" case, we can check both the error and the output.

for _, tc := range cases {
	t.Run(strconv.FormatUint(tc.in, 10), func(t *testing.T) {
		got, err := ConvertCPUSharesToCPUWeight(tc.in)
		if tc.isErr {
			if err == nil {
				t.Error("expected error, got nil")
			}
		} else {
			if err != nil {
				t.Errorf("expected no error, got: %v", err)
			}
			if got != tc.out {
				t.Errorf("want %d, got %d", tc.out, got)
			}
		}
	})
}

Or, if we want the tests to be more descriptive on intent, and make sure we're matching the right error;

func TestConvertCPUSharesToCPUWeight(t *testing.T) {
	cases := []struct {
		doc     string
		in, out uint64
		expErr  string
	}{
		{doc: "valid zero", in: 0, out: 0},
		{doc: "valid min value", in: 2, out: 1},
		{doc: "valid max value", in: 262144, out: 10000},
		{doc: "out of bound min", in: 1, expErr: "cpu-shares should be between 2 and 262144"},
		{doc: "out of bound max", in: 262145, expErr: "cpu-shares should be between 2 and 262144"},
	}
	for _, tc := range cases {
		t.Run(tc.doc, func(t *testing.T) {
			got, err := ConvertCPUSharesToCPUWeight(tc.in)
			if tc.expErr != "" {
				if err == nil || err.Error() != tc.expErr {
					t.Errorf("expected error %q, got %v", tc.expErr, err)
				}
				return
			}

			if err != nil {
				t.Errorf("expected no error, got: %v", err)
			}
			if got != tc.out {
				t.Errorf("want %d, got %d", tc.out, got)
			}
		})
	}
}

@kolyshkin
Copy link
Contributor Author

In the light of kubernetes/kubernetes#131216 and containers/crun#1767 I'm going to rework this.

@kolyshkin kolyshkin marked this pull request as draft May 29, 2025 21:17
@kolyshkin
Copy link
Contributor Author

Closing in favor of #20

@kolyshkin kolyshkin closed this Jun 6, 2025
@kolyshkin kolyshkin deleted the cpu-shares branch June 6, 2025 17:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants