-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
Sort a few python dicts for deterministic builds, even with python 3.5 and earlier. #14119
Sort a few python dicts for deterministic builds, even with python 3.5 and earlier. #14119
Conversation
To reproduce the issue this addresses, run "cmake -B96b_nitrogen" twice with Python 3.5. Observe the order of the flash partition table changing in: "build{1,2}/zephyr/include/generated/generated_dts_board.conf" and "generated_dts_board_unfixed.h" Dictionaries are iterated in a random order by Python 3.5 and before. This could have caused "Unstable" CI in PR zephyrproject-rtos#13921 and maybe others. Anyway we want builds to be determimistic by default. Explicit randomness can be added for better coverage but not by default. Signed-off-by: Marc Herbert <[email protected]>
for node_path in reduced.keys(): | ||
# sorted() otherwise Python < 3.6 randomizes the order of the flash | ||
# partition table | ||
for node_path in sorted(reduced.keys()): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like I missed this earlier, but could get rid of the .keys()
. x in dict
, for x in dict
, sorted(dict)
, etc., always uses the keys.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed but I'd like to keep this particular commit as minimal as possible :-) Not just for aesthetic reasons but also cherry-picking for testing / backporting etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, fine with me.
scripts/gen_kobject_list.py
Outdated
eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems) | ||
syms = eh.get_symbols() | ||
max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8 | ||
objs = eh.find_kobjects(syms) | ||
if len(objs) == 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can do if not objs:
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.
scripts/gen_priv_stacks.py
Outdated
eh = ElfHelper(args.kernel, args.verbose, kobjects, []) | ||
syms = eh.get_symbols() | ||
max_threads = syms["CONFIG_MAX_THREAD_BYTES"] * 8 | ||
objs = eh.find_kobjects(syms) | ||
if len(objs) == 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do.
scripts/gen_priv_stacks.py
Outdated
@@ -101,10 +101,14 @@ def parse_args(): | |||
def main(): | |||
parse_args() | |||
|
|||
assert args.kernel, "--kernel ELF required for --gperf-output" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a required=True
on the parser.add_argument()
that adds --kernel
, so this might not be needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, I saw the mostly duplicated main()
so I blindly copied the assert from the other script. Will remove.
@@ -269,10 +276,14 @@ def main(): | |||
parse_args() | |||
|
|||
if args.gperf_output: | |||
assert args.kernel, "--kernel ELF required for --gperf-output" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe
if not args.kernel:
sys.exit("--kernel must be passed if --gperf-output is")
would be a bit more purist.
It's more of a usage error than a runtime error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a usage error but... a pretty stupid, "trial-and-error" one so I didn't want to spend too many lines of code on it.
Codecov Report
@@ Coverage Diff @@
## master #14119 +/- ##
=======================================
Coverage 52.68% 52.68%
=======================================
Files 307 307
Lines 45473 45473
Branches 10530 10530
=======================================
Hits 23956 23956
Misses 16640 16640
Partials 4877 4877 Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
other than the minor issues @ulfalizer noted this LGTM
Dictionaries are iterated in a random order by Python 3.5 and before. This could have caused "Unstable" CI in PR zephyrproject-rtos#13921 and maybe others. Anyway we want builds to be determimistic by default. Explicit randomness can be added for better coverage but not by default. 1. When running "make kobj_types_h_target" repeatedly one can observe that the following .h files keep changing in build/zephyr/include/generated/: - kobj-types-enum.h - otype-to-str.h - otype-to-size.h Switching kobjects to OrderedDict makes these 3 .h files deterministic. 2. When running this test repeatedly with CONFIG_USERSPACE=y: rm build/zephyr/*.gperf && make -C build obj_list ... the dict used for --gperf-output seems to be deterministic, probably because its keys are all integers (memory addresses). However we can't take that for granted with Python < 3.6 so out of caution also switch the output of find_objects() in elf_helper.py to a sorted OrderedDict. PS: I would normally prefer official Python documentation to StackOverflow however this one is a good summary and has all the multiple pointers to the... official Python documentation. Signed-off-by: Marc Herbert <[email protected]>
0bf4e64
to
1d3dff3
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still think the assert
for reporting a usage error looks confusing, but won't block over it.
Thanks for the very prompt reviews. For the record this is a "screenshot" of a typical diff: https://gist.github.com/nashif/675dd70be922f0200c181d6a65baeafb There's also one last |
See commit messages.