Skip to content
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

Support cgroup2 #44

Merged
merged 21 commits into from
Apr 5, 2022
Merged

Support cgroup2 #44

merged 21 commits into from
Apr 5, 2022

Conversation

emadolsky
Copy link
Contributor

CGroup-V2 has a different architecture which is unified. Since it is not yet supported in go, it makes sense to currently have the
support. This commit adds the functionality to set GOMAXPROCS in cgroup2 enabled systems.

Also there were lint errors because of build annotation comments which are fixed in a separate commit.

This PR resolves #21.

@CLAassistant
Copy link

CLAassistant commented Jan 4, 2022

CLA assistant check
All committers have signed the CLA.

CGroup-V2 has a different architecture which is unified. Since it
is not yet supported in go, it makes sense to currently have the
support. This commit adds the functionality to set GOMAXPROCS in
cgroup2 enabled systems.
@ardan-bkennedy
Copy link

Can someone at Uber provide information about if this project is still being supported? I'm considering to fork the project so it can be maintained.

@alxn
Copy link
Member

alxn commented Jan 27, 2022

Thanks for the PR - we are looking for a reviewer internally. @prashantv and @akshayjshah have left the building...

@akshayjshah
Copy link
Contributor

Happy to look at this PR, Alun, but I'd love to also get a stamp from someone who can speak authoritatively for Uber infra.

@brettbuddin
Copy link

brettbuddin commented Feb 9, 2022

Has anyone had a chance to review this yet? We've recently upgraded Flatcar and are running into cgroup V2 issues. If this is on track to be merged, we can just wait for it instead of forking and applying a patch.

Thanks for good work here, everyone. 😄

@ardan-bkennedy
Copy link

You don't need to wait. Run this command at the root of your project where the go.mod file is located

go get github.com/emadolsky/automaxprocs@master

Then switch your import to using this.

"github.com/emadolsky/automaxprocs/maxprocs"

Everything will work.

@dprotaso
Copy link
Contributor

@alxn are you able to find an internal reviewer?

@dprotaso
Copy link
Contributor

cc @abhinav

Copy link
Contributor

@akshayjshah akshayjshah left a comment

Choose a reason for hiding this comment

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

Thanks for the PR, @emadolsky! I'm not at Uber any more and didn't actually author this code, but it's nice to see this package still providing some value for the community.

I've left some comments on the PR (which hopefully the current Uber folks agree with). I'd wait for a review from one of the current maintainers before making any changes, though - in practice, they may not be accepting PRs for this package at all. In the meantime, it looks like you're the maintainer of the new automaxprocs! 😸

internal/cgroups/cgroup.go Outdated Show resolved Hide resolved
internal/cgroups/cgroups.go Outdated Show resolved Hide resolved
internal/cgroups/cgroups.go Outdated Show resolved Hide resolved
internal/cgroups/cgroups.go Outdated Show resolved Hide resolved
internal/cgroups/cgroups.go Outdated Show resolved Hide resolved
}

func cpuQuotaV2(cgroupv2MountPoint, cgroupv2CPUMax string) (float64, bool, error) {
cpuMaxParams, err := os.Open(path.Join(cgroupv2MountPoint, cgroupv2CPUMax))
Copy link
Contributor

Choose a reason for hiding this comment

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

Here you should also include the cgroup-path from /proc/self/cgroup, see https://man7.org/linux/man-pages/man7/cgroups.7.html

@codecov
Copy link

codecov bot commented Mar 29, 2022

Codecov Report

Merging #44 (57aa42c) into master (7ff767a) will increase coverage by 0.88%.
The diff coverage is 96.00%.

@@            Coverage Diff             @@
##           master      #44      +/-   ##
==========================================
+ Coverage   92.07%   92.95%   +0.88%     
==========================================
  Files           8        9       +1     
  Lines         164      213      +49     
==========================================
+ Hits          151      198      +47     
- Misses         10       11       +1     
- Partials        3        4       +1     
Impacted Files Coverage Δ
internal/cgroups/cgroups2.go 95.34% <95.34%> (ø)
internal/runtime/cpu_quota_linux.go 62.50% <100.00%> (+22.50%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7ff767a...57aa42c. Read the comment docs.

Copy link
Contributor

@abhinav abhinav left a comment

Choose a reason for hiding this comment

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

Hey folks, sorry for the delay. @mway and I will review this.
I've made an initial pass in terms of style and organization and made some updates.
In particular, I've moved the bulk of the v2 logic into separate files.

On top of that, I have limited knowledge of the underlying systems so I need some help understanding this:
Why is the mountpoint hard-coded to be /sys/fs/cgroup? As far as I can tell, mountinfo says "this is where cgroups2 is mounted", so should we not use whatever path is specified in mountinfo? Is it absolutely required for cgroups2 to mount to that path?

internal/cgroups/cgroups2.go Outdated Show resolved Hide resolved
Naming wise, "give" and "want" are equally informative and much shorter.
This CGroups2 has the same interface as the CGroups object.
This allows the logic in cpu_quota_linux to remain largely unchanged.
Turn the NewCGroupsForCurrentProcess and NewCGroups2ForCurrentProcess
functions into function references so that we can replace them from
tests.
Copy link
Contributor

@abhinav abhinav left a comment

Choose a reason for hiding this comment

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

I've made changes for readability, added more tests, and changed cpu_quota_linux so that the changes to the core logic are minimal.

This change LGTM now. I'm going to have someone else take a quick look over it, but it should be good to go otherwise.

Copy link
Member

@mway mway left a comment

Choose a reason for hiding this comment

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

lgtm

internal/cgroups/cgroups2.go Outdated Show resolved Hide resolved
internal/cgroups/cgroups2.go Outdated Show resolved Hide resolved
internal/cgroups/cgroups2.go Outdated Show resolved Hide resolved
internal/cgroups/cgroups2.go Outdated Show resolved Hide resolved
@abhinav abhinav merged commit ad6f05b into uber-go:master Apr 5, 2022
@ardan-bkennedy
Copy link

This change has not fixed the problem. I switched my code from "github.com/emadolsky/automaxprocs/maxprocs" to v1.5.0 and I am still getting that the CPU Quota is not defined.

@ardan-bkennedy
Copy link

ardan-bkennedy commented Apr 5, 2022

I noticed that in v1.5.0

https://github.com/uber-go/automaxprocs/blob/v1.5.0/internal/runtime/cpu_quota_linux.go#L35

func CPUQuotaToGOMAXPROCS(minValue int) (int, CPUQuotaStatus, error) {[Jason Lai, 5 years ago: • Import `automaxprocs/x/runtime`](https://sourcegraph.com/github.com/uber-go/automaxprocs/-/commit/572239b375b1ca6b76babeb8b0ee139dc35fd4d8)
	cgroups, err := newQueryer()
	if err != nil {
		return -1, CPUQuotaUndefined, err
	}

	quota, defined, err := cgroups.CPUQuota()
	if !defined || err != nil {
		return -1, CPUQuotaUndefined, err
	}

	maxProcs := int(math.Floor(quota))
	if minValue > 0 && maxProcs < minValue {
		return minValue, CPUQuotaMinUsed, nil
	}
	return maxProcs, CPUQuotaUsed, nil
}

var (
	_newCgroups2 = cg.NewCGroups2ForCurrentProcess
	_newCgroups  = cg.NewCGroupsForCurrentProcess
)

func newQueryer() (queryer, error) {
	cgroups, err := _newCgroups2()
	if err == nil {
		return cgroups, nil
	}
	if errors.Is(err, cg.ErrNotV2) {
		return _newCgroups()
	}
	return nil, err
}

In the emadolsky repo, it's working. I don't know enough to tell you why.

func CPUQuotaToGOMAXPROCS(minValue int) (int, CPUQuotaStatus, error) {
	var quota float64
	var defined bool
	var err error

	isV2, err := cg.IsCGroupV2()
	if err != nil {
		return -1, CPUQuotaUndefined, err
	}

	if isV2 {
		quota, defined, err = cg.CPUQuotaV2()
		if !defined || err != nil {
			return -1, CPUQuotaUndefined, err
		}
	} else {
		cgroups, err := cg.NewCGroupsForCurrentProcess()
		if err != nil {
			return -1, CPUQuotaUndefined, err
		}

		quota, defined, err = cgroups.CPUQuota()
		if !defined || err != nil {
			return -1, CPUQuotaUndefined, err
		}
	}

	maxProcs := int(math.Floor(quota))
	if minValue > 0 && maxProcs < minValue {
		return minValue, CPUQuotaMinUsed, nil
	}
	return maxProcs, CPUQuotaUsed, nil
}

@emadolsky
Copy link
Contributor Author

@abhinav - I also verify that the merged version doesn't work properly.

abhinav pushed a commit that referenced this pull request Apr 6, 2022
In #44, we accidentally turned v2 mountpoint detection
from "are any of the mountpoints v2 to "is the last mountpoint v2".
This fixes that condition and updates the test case to catch that in
the future.

Resolves #49
@bsergean
Copy link

I've add issue getting this working on k8s 1.26 (on google cloud), where apparently we use cgroup v2 ; I'm not positive that this is working.

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.

Support cgroups v2 and its unified hierarchy