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

add memory cgroup controller #16

Merged
merged 13 commits into from
May 24, 2021
Merged

add memory cgroup controller #16

merged 13 commits into from
May 24, 2021

Conversation

tsturzl
Copy link
Collaborator

@tsturzl tsturzl commented May 21, 2021

Solves part of #9. Should be passing runtime-tools tests, as well as included unit tests.

@utam0k
Copy link
Member

utam0k commented May 22, 2021

@tsturzl
It's a nice work!
The CI is failing, please check it.

@utam0k utam0k mentioned this pull request May 22, 2021
@utam0k utam0k self-requested a review May 22, 2021 00:51
@tsturzl
Copy link
Collaborator Author

tsturzl commented May 22, 2021

Things should be working now. I think I'd like to wait until the hugetlb support is merged in since the subsystem changes that were made are more elegant than what I did. I'll just integrate with those changes once they're merged in.

@utam0k
Copy link
Member

utam0k commented May 22, 2021

Thank you very much. The tests all passed 🎉
This PR is ready to be merged, but I'll wait for utam0k#15 to be merged.

@utam0k
Copy link
Member

utam0k commented May 22, 2021

@tsturzl
Sorry to keep you waiting. I've merged the other one.

@tsturzl
Copy link
Collaborator Author

tsturzl commented May 24, 2021

Should be good to go! If you wanna run the CI quick I confirmed that the CI is passing on my fork(https://github.com/tsturzl/youki/runs/2652443431).

One change to note is my final commit. I noticed searching for the mounts and cgroup subsystems the filter->collect->pop routine was probably not needed. I might be wrong, but it seems like the vector that gets created by both is just going to be one element long. This probably creates some additional overhead and seems unneeded, so my last commit includes a change that simply replaces this with the find method on iterators, which just returns the first result that matches a filter. Let me know if you think this is problematic for any reason and I can omit that change. Alternatively if we actually only need the last element from the vector there is also the last method which replaces collect, instead returning a single value instead of allocating a vector. See: utam0k@6d5157b

@utam0k
Copy link
Member

utam0k commented May 24, 2021

That's right! It's nice to work!

One change to note is my final commit. I noticed searching for the mounts and cgroup subsystems the filter->collect->pop routine was probably not needed. I might be wrong, but it seems like the vector that gets created by both is just going to be one element long. This probably creates some additional overhead and seems unneeded, so my last commit includes a change that simply replaces this with the find method on iterators, which just returns the first result that matches a filter. Let me know if you think this is problematic for any reason and I can omit that change. Alternatively if we actually only need the last element from the vector there is also the last method which replaces collect, instead returning a single value instead of allocating a vector. See: 6d5157b

match Self::set_i64(val, &path) {
Ok(_) => Ok(()),
Err(e) => {
// we need to look into the raw OS error for an EBUSY status
Copy link
Member

Choose a reason for hiding this comment

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

This was a tough one. Thank you very much 👍

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@utam0k the challenge was fun! I tried to follow the runc code as cloesly as I could on this one since there were a few caveats, but it was a good learning experience.

Copy link
Member

Choose a reason for hiding this comment

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

That was so good! I'm learning from your PR review now too.

Comment on lines 205 to 226
let limit = resource.limit.unwrap_or(-1);
let mut swap = resource.swap.unwrap_or(0);

if limit == -1 && swap == 0 {
if cgroup_root.join(CGROUP_MEMORY_SWAP_LIMIT).exists() {
swap = -1;
}
}

// According to runc we need to change the write sequence of
// limit and swap so it won't fail, because the new and old
// values don't fit the kernel's validation
// see:
// https://github.com/opencontainers/runc/blob/master/libcontainer/cgroups/fs/memory.go#L89
if limit != 0 && swap != 0 {
let current_limit = Self::get_memory_limit(cgroup_root)?;

if swap == -1 || current_limit < swap {
Self::set_swap(swap, cgroup_root)?;
Self::set_memory(limit, cgroup_root)?;
return Ok(());
}
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be easier to use Option to make the code easier.
Also, swap can turn off mut by determining the value at the time of allocation.

@utam0k
Copy link
Member

utam0k commented May 24, 2021

@tsturzl
All in all, very good! I just made a few comments to make the code a little easier to understand.

@tsturzl
Copy link
Collaborator Author

tsturzl commented May 24, 2021

@utam0k I think I can just give this a final pass and clean up the code in general. I'll make the changes soon and push.

// limit and swap so it won't fail, because the new and old
// values don't fit the kernel's validation
// see:
// https://github.com/opencontainers/runc/blob/master/libcontainer/cgroups/fs/memory.go#L89
Copy link
Member

Choose a reason for hiding this comment

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

This is a very good comment, but it can be made even better by making it a permalink.

@utam0k utam0k mentioned this pull request May 24, 2021
@tsturzl
Copy link
Collaborator Author

tsturzl commented May 24, 2021

Ok, so a couple things. I replaced the 2 previous type specific set_ methods with a single set which takes any type that implements ToString. I took your advice and refactored to use pattern matching on Options rather the punning None values to a default and then matching on those values. I originally wrote that portion of code as closely to the runc implementation as possible, but I agree it's not very idiomatic Rust. I'm still torn on the pattern matching approach, it doesn't seem entirely as clear, but maybe there's a better way to do it that I'm not seeing. Matching into 2 different Options like this gets a bit tricky.

I also cleaned up the mess of code that was looking for the EBUSY errno.

Let me know what you think.

@utam0k
Copy link
Member

utam0k commented May 24, 2021

@tsturzl I think this is good enough for this PR.

@utam0k utam0k merged commit 910514e into youki-dev:main May 24, 2021
@utam0k utam0k mentioned this pull request May 24, 2021
11 tasks
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.

2 participants