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

Read exactly two tokens from Linux transparent huge pages sysfs config #37065

Closed
wants to merge 20 commits into from
Closed

Read exactly two tokens from Linux transparent huge pages sysfs config #37065

wants to merge 20 commits into from

Conversation

jayaddison
Copy link
Contributor

There was an unexpected and hard-to-spot issue here: the /sys/kernel/mm/transparent_hugepage/enabled file contains three entries, and the std::ifstream reader was reading two values on each loop iteration, resulting in incorrect behaviour.

Resolves #37064

Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or

(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or

(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.

(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.

…ing while loop

There was an unexpected and hard-to-spot issue here: the /sys/kernel/mm/transparent_hugepage/enabled file contains three entries, and the std::ifstream reader was reading two values on each loop iteration, resulting in incorrect behaviour.
@nodejs-github-bot nodejs-github-bot added the c++ Issues and PRs that require attention from people who are familiar with C++. label Jan 25, 2021
@nodejs-github-bot

This comment has been minimized.

@RaisinTen
Copy link
Contributor

Thanks for fixing this! 🎉

Note to whoever lands this

The commit message needs to be amended to include:

Fixes: https://github.com/nodejs/node/issues/37064

and be wrapped at 72 columns.

@RaisinTen RaisinTen added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jan 26, 2021
@jayaddison
Copy link
Contributor Author

Thanks @RaisinTen, and my mistake regarding the commit message linewrapping, I'll note that for next time.

I was considering adding a small amount of test coverage here; it's been a while since I've coded much C++ so it could take a little while, but that offer stands if it'd be useful. I'd also vaguely considered refactoring this to support an arbitrary number of tokens in the hugepages flag file (by checking for presence of any of a -- possibly std::set -- of valid 'positive' values while reading the file token-by-token).

@RaisinTen
Copy link
Contributor

RaisinTen commented Jan 26, 2021

I was considering adding a small amount of test coverage here; it's been a while since I've coded much C++ so it could take a little while, but that offer stands if it'd be useful.

I'm curious to know how you would approach testing this. For reference, here is an already existing test file to test
the --use-largepages option: https://github.com/nodejs/node/blob/master/test/parallel/test-startup-large-pages.js.

I'd also vaguely considered refactoring this to support an arbitrary number of tokens in the hugepages flag file (by checking for presence of any of a -- possibly std::set -- of valid 'positive' values while reading the file token-by-token).

I tried to edit the file locally by following this guide:
https://www.kernel.org/doc/html/latest/admin-guide/mm/transhuge.html#global-thp-controls
and it seems, the file has a format that allows it to have only these three tokens in this sequence separated by spaces
with only one of them surrounded by [] according to what we echo into it:

always madvise never

So, I don't think using a std::set here is necessary.

@jayaddison
Copy link
Contributor Author

I'm curious to know how you would approach testing this.

It looks tricky to test this logic while providing fixtures that simulate the contents of /sys/kernel/mm/transparent_hugepage/enabled, outside of a host system.

I noticed that there is existing use of the gtest framework within the test suite, and understand that it may be possible to use that to mock file streams. If those conditions hold true, we might be able to extract the logic into a function that accepts a file stream as an argument, and confirm the behaviour of that function without any filesystem reads on a host system.

So, I don't think using a std::set here is necessary.

Ok, agreed - using a set may be over-engineering the problem.

@jayaddison jayaddison changed the title Simplify kernel transparent_hugepage enabled flag check by removing while loop Fixup: inspect kernel transparent_hugepage flag values without assuming their length or ordering Jan 26, 2021
@RaisinTen
Copy link
Contributor

Would be interesting to have that test. 👍
Removing the author ready label now since you're still working on this.

@RaisinTen RaisinTen removed the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jan 26, 2021
jayaddison and others added 4 commits January 26, 2021 16:25
Co-authored-by: Darshan Sen <raisinten@gmail.com>
…stem huge tables configuration on Linux-based systems
…o determine huge tables enabled state based on the contents of a configuration stream
@jayaddison
Copy link
Contributor Author

For reference (it doesn't look like this should affect the changes suggested here) - the logic to produce the contents of the /sys/kernel/mm/transparent_hugepage/enabled kernel configuration file is available here: https://github.com/torvalds/linux/blob/13391c60da3308ed9980de0168f74cce6c62ac1d/mm/huge_memory.c#L162-L177

@jayaddison
Copy link
Contributor Author

The most recent commits (excluding lint fixes) extract two separate functions to, respectively, read the Linux huge tables configuration, and determine whether huge tables are configured as enabled.

I've now learned that although gtest is present in the codebase, gmock is not. Either way, gmock looks intended for use for testing C++ classes, not file-level functions.

One possibility might be to change the linkage of the IsTransparentHugePagesConfigured function (via use of static / extern keywords) so that the cctests can link to and exercise the logic within it. That makes me a little wary because it doesn't seem to be an existing pattern within the test suite, and also it has the potential to affect the contents of distributed binaries.

I'll puzzle over this for a little while and any guidance would be appreciated.

@jayaddison
Copy link
Contributor Author

Despite some further investigation, I'm currently uncertain about how to proceed, given questions around how to make the (non-public) IsTransparentHugePagesConfigured unit-test-able. I'm planning to pause work on this until we have some more ideas about how to resolve that.

@RaisinTen
Copy link
Contributor

Thanks for trying to test this out. I'm not sure about testing this either if there is no way to mock the file.

If the code isn't testable, I think it would be better to stick to your initial commit as a fix for the issue you brought up as it solves its purpose and is more concise and also readable. Additionally, I would consider adding a comment mentioning the link to the logic behind producing the kernel config file that you mentioned as I didn't come across any better explanation of the file format.

I'm adding a review wanted label. Let's wait and see what others have to say about this.

cc @gabrielschulhof would you please take a look at this fix when you're free?

@RaisinTen RaisinTen added the review wanted PRs that need reviews. label Jan 27, 2021
@jayaddison
Copy link
Contributor Author

Thanks @RaisinTen; I agree with all of your analysis there. For the purposes of not hiding history, I'll walk back to the initial change by reverting the subsequent commits, and then I'll add an explanatory comment.

@nodejs-github-bot

This comment has been minimized.

@jayaddison
Copy link
Contributor Author

As an aside: reading this Percona article about the performance impact of transparent huge pages has led me to look further back to the Linux v2.6.38 series kernel where it looks like the feature was introduced (ref).

It would be good to take time and aim for maximal version compatibility in any changes applied here.

@jayaddison
Copy link
Contributor Author

(initially it does appear that the file format has remained stable since introduction, but there could be debug options or other good reasons why the format changed in the interim)

@jayaddison jayaddison changed the title Fixup: inspect kernel transparent_hugepage flag values without assuming their length or ordering Read exactly two tokens from Linux transparent huge pages sysfs config Jan 28, 2021
@jayaddison
Copy link
Contributor Author

There are one or two further simplifications possible here:

  • A std::ifstream object's close member function will automatically be called when the object is destroyed; this may enable some conditional-clause rewrites
  • Since we are only reading a fixed number of tokens, we could sequentially read these using a single variable

@jayaddison
Copy link
Contributor Author

The edits described in my previous comment are available to read as code here.

After checking that the changes in this pull request are valid, we could discuss whether the extra edits are worth including.

@jayaddison jayaddison closed this Jan 29, 2021
@jayaddison jayaddison reopened this Jan 29, 2021
@jayaddison
Copy link
Contributor Author

@RaisinTen Please could you re-add the author ready label to this pull request? I'm comfortable that this is ready for review again now.

@nodejs-github-bot
Copy link
Collaborator

@RaisinTen RaisinTen added the author ready PRs that have at least one approval, no pending requests for changes, and a CI started. label Jan 30, 2021
@RaisinTen
Copy link
Contributor

LGTM!

@Trott Trott requested a review from lundibundi January 31, 2021 14:47
RaisinTen pushed a commit that referenced this pull request Feb 2, 2021
There was an unexpected and hard-to-spot issue here:
the /sys/kernel/mm/transparent_hugepage/enabled file contains three
entries, and the std::ifstream reader was reading two values on each
loop iteration, resulting in incorrect behaviour.

Fixes: #37064

PR-URL: #37065
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@RaisinTen
Copy link
Contributor

Landed in a0c0875 🎉

@RaisinTen RaisinTen closed this Feb 2, 2021
@jayaddison jayaddison deleted the transparent-hugepage-read branch February 2, 2021 13:55
@RaisinTen RaisinTen removed the review wanted PRs that need reviews. label Feb 5, 2021
danielleadams pushed a commit that referenced this pull request Feb 16, 2021
There was an unexpected and hard-to-spot issue here:
the /sys/kernel/mm/transparent_hugepage/enabled file contains three
entries, and the std::ifstream reader was reading two values on each
loop iteration, resulting in incorrect behaviour.

Fixes: #37064

PR-URL: #37065
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
This was referenced Feb 16, 2021
targos pushed a commit that referenced this pull request May 1, 2021
There was an unexpected and hard-to-spot issue here:
the /sys/kernel/mm/transparent_hugepage/enabled file contains three
entries, and the std::ifstream reader was reading two values on each
loop iteration, resulting in incorrect behaviour.

Fixes: #37064

PR-URL: #37065
Reviewed-By: Darshan Sen <raisinten@gmail.com>
Reviewed-By: Rich Trott <rtrott@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
@danielleadams danielleadams mentioned this pull request May 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. c++ Issues and PRs that require attention from people who are familiar with C++.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Linux: transparent hugepage flag logic issue
5 participants