RFR: 8302744: Refactor Hotspot container detection code [v3]
Thomas Stuefe
stuefe at openjdk.org
Mon May 27 11:32:11 UTC 2024
On Thu, 23 May 2024 14:00:30 GMT, Severin Gehwolf <sgehwolf at openjdk.org> wrote:
>> Please review this container detection code refactoring in hotspot. The main point of this is to
>>
>> - get rid of the `GET_CONTAINER_INFO` macros which hide too many things under the hood
>> - prevent refactoring of the code (since `GET_CONTAINER_INFO` macros short-return and are therefore not portable; at least not without some risk)
>> - make the code easier to understand
>> - allow for better testing via `gtest`
>> - separate multi-line parsing from single line parsing for clarity.
>>
>> Testing:
>> - [x] GHA
>> - [x] `gtest:cgroupTest` tests
>> - [x] Container tests on Linux with cgroup v1 (legacy) and cgroup v2. All pass.
>>
>> Thoughts?
>
> Severin Gehwolf has updated the pull request with a new target base due to a merge or a rebase. The incremental webrev excludes the unrelated changes brought in by the merge/rebase. The pull request contains 16 additional commits since the last revision:
>
> - Add proper comments for parsing utility functions
> - Add a test for a large string read
> - Add convenience function for 'max' handling
>
> This now makes limit_from_str a private method
> - Fix general read string cases.
> - Get rid of the templated function
> - Use enum class for TupleValue
> - Merge branch 'master' into jdk-8302744-cleanup-getcontainer-info
> - Fix TestMemoryAwareness for cgroup v2
>
> It only reads the swap value, thus doesn't print:
> "Memory and Swap Limit is" but rather prints:
> "Swap Limit is". This is fine, since for cg v2
> the memory limit and the swap limits are in different
> files.
> - Fix whitespace
> - Handle cpu quota for cgroups v1 specially
> - ... and 6 more: https://git.openjdk.org/jdk/compare/ad824a8e...c41d3183
This is a really nice cleanup. Some more remarks inline, but its nearing the finish line from my point of view.
There is some potential for more concise code, (e.g. the many `is_ok` you tend to be using, with subsequent error handling, could mostly be combined to one line), but that is starting to be really nitpicky.
Is the file move of test/hotspot/gtest/runtime/test_cgroupSubsystem_linux.cpp necessary? Difficult to see what changed.
src/hotspot/os/linux/cgroupSubsystem_linux.cpp line 564:
> 562: log_debug(os, container)("read_string: filename is null");
> 563: return false;
> 564: }
I think we can just assume and assert that filename != nullptr. Its always a string literal AFAICS.
src/hotspot/os/linux/cgroupSubsystem_linux.cpp line 634:
> 632: log_debug(os, container)("read_numerical_key_value: filename is null");
> 633: return false;
> 634: }
Same here, would assert filename != null
src/hotspot/os/linux/cgroupSubsystem_linux.cpp line 643:
> 641: log_debug(os, container)("read_numerical_key_value: key or return pointer is null");
> 642: return false;
> 643: }
Same here, should be asserted.
src/hotspot/os/linux/cgroupSubsystem_linux.cpp line 668:
> 666: fclose(fp);
> 667: return false;
> 668: }
Do we really explicitly need to handle empty file here? If not, just scratch this section and rely on the block below.
src/hotspot/os/linux/cgroupSubsystem_linux.cpp line 673:
> 671: // File consists of multiple lines in a "key value"
> 672: // fashion, we have to find the key.
> 673: const int key_len = (int)strlen(key);
Use size_t. No need for the cast then.
src/hotspot/os/linux/cgroupSubsystem_linux.cpp line 687:
> 685: break;
> 686: }
> 687: }
Why use `strstr` for the key? If it has to start at line begin, you could just strncmp:
Proposal:
if (strncmp(line, key, key_len) == 0 && isspace(line[key_len])) {
const char* value_substr = line + key_len + 1;
...
}
src/hotspot/os/linux/cgroupSubsystem_linux.cpp line 715:
> 713: break;
> 714: }
> 715: }
Section could be shortened to just:
const int matched = sscanf(buf, (tup == TupleValue::FIRST) ? "%1023s %*s" : "%*s %1023s", token);
Also consider just making it a bool instead of enum. E.g. `bool use_first`. Expression then is shortened to:
const int matched = sscanf(buf, use_first ? "%1023s %*s" : "%*s %1023s", token);
src/hotspot/os/linux/cgroupSubsystem_linux.hpp line 142:
> 140: * up to the first new line character ('\n') whichever comes first.
> 141: */
> 142: bool read_string(const char* filename, char* buf);
Nice comments.
I think the common convention is: either specify both output buffer and output buffer size, or - if you always expect a certain output buffer size - specify argument as `char buf[1024]`. Thinking this through, the former may be a bit cleaner since it allows you to scrap all the literal 1024 inside read_string for the bufsize argument.
-------------
PR Review: https://git.openjdk.org/jdk/pull/19060#pullrequestreview-2080563720
PR Review Comment: https://git.openjdk.org/jdk/pull/19060#discussion_r1615830305
PR Review Comment: https://git.openjdk.org/jdk/pull/19060#discussion_r1615843281
PR Review Comment: https://git.openjdk.org/jdk/pull/19060#discussion_r1615844605
PR Review Comment: https://git.openjdk.org/jdk/pull/19060#discussion_r1615847232
PR Review Comment: https://git.openjdk.org/jdk/pull/19060#discussion_r1615858810
PR Review Comment: https://git.openjdk.org/jdk/pull/19060#discussion_r1615861707
PR Review Comment: https://git.openjdk.org/jdk/pull/19060#discussion_r1615871045
PR Review Comment: https://git.openjdk.org/jdk/pull/19060#discussion_r1615832279
More information about the hotspot-runtime-dev
mailing list