-
Notifications
You must be signed in to change notification settings - Fork 119
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
Rework EAS acceptance tests to inherit from LisaTest #197
Rework EAS acceptance tests to inherit from LisaTest #197
Conversation
This commit gives Executors a list of structs containing metadata about the experiments it runs. The primary motivation for this is so that tests subclassing LisaTest can use this information in their test_* methods. For example, tests can use the 'out_dir' member to construct Trappy Ftrace objects.
…s" param On "periodic" rt-app workloads, the "tasks" param specifies how many instances of the given task configuration should be instantiated. For example, if the tests_conf contains: "wloads" : { "my_periodic" : { "type" : "rt-app", "conf" : { "class" : "periodic", "params" : { "duty_cycle_pct": 100, "duration_s" : 5, "period_ms": 10 }, "tasks" : 10 // <-- Create 10 tasks }, } then 10 tasks with the given "params" will be created. This commit adds the same functionality for tasks within a "type" of "profile. Example: "fmig" : { "type" : "rt-app", "conf" : { "class" : "profile", "params" : { "small" : { "kind" : "Periodic", "params" : { "duty_cycle_pct": 10, "duration_s": 5, "period_ms": 10, }, "tasks" : 2 }, "big" : { "kind" : "Periodic", "params" : { "duty_cycle_pct": 100, "duration_s" : 5, "period_ms": 10 }, "tasks" : 4 }, }, }, }, The above will create a workload that runs 4 100% tasks and 2 10% periodic tasks in parallel.
Re-order imports according to PEP8 [1]. Also remove duplicate `import json`. [1] https://www.python.org/dev/peps/pep-0008/#imports
This adds a class EasTest that inherits from LisaTest to provide a common set of functions for EAS acceptance tests.
Now that all the EAS acceptance tests have been ported to use the EasTest class this code is no longer 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.
I love this refactoring, thanks @bjackman for the effort!
Perhaps we can improve something before merging but I think we are already in a quite good status.
Since we are changing so much, I would really like a slightly better sequencing for some patches.
# WORKLOAD: execution | ||
self._wload_run(exp_idx, tc, wl_idx, wload, itr_idx) | ||
exp_idx += 1 | ||
self.experiments.append({ |
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.
I like this idea to initialize all the confs and do the actual execution only after.
I'm wondering if it could make more sense here to use a namedtuple to represent one experiment, e.g.
from collections import namedtuple
Experiment = namedtuple('Experiment', ['wload_name', 'wload', 'conf', 'iteration' ,'out_dir'])
self.experiments.append(Experiment(wl_idx, wload, tc, itr_idx, os.path.join(test_dir, str(itr_idx)))
This should perhaps simplify the following code cause you can:
- loop on Experiment tuples, which are passed directly to the _wload_run (with ** expansion if required)
- remove some dictionary access lines by replacing them with simpler calls, e.g. exp.wload_name instead of exp['wload_name']
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.
Nice, will give that a go.
@@ -464,38 +473,38 @@ def _wload_init(self, tc, wl_idx): | |||
wload = self._wload_conf(wl_idx, wlspec) | |||
|
|||
# Keep track of platform configuration | |||
self.te.test_dir = '{}/{}:{}:{}'\ |
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.
That's just a cosmetics chunk... can you keep them on a separate patch (maybe before)?
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.
|
||
# Keep track of kernel configuration and version | ||
config = self.target.config | ||
with gzip.open(os.path.join(self.te.test_dir, 'kernel.config'), 'wb') as fh: |
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.
Again, these two chunks are cosmetics... keep in the same separate patch with the previous one.
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 on the change to the format call, but not on the self.te.test_dir -> test_dir:
Before this change, self.te.test_dir
is global state that is picked up later in _wload_run_init
. I could put this change in a previous patch which also modifies _wload_run and _wload_init to take a test_dir argument, but it seems unnecessary given that it will immediately be undone...
logging.debug(r'%14s - out_dir [%s]', 'Executor', self.te.out_dir) | ||
os.system('mkdir -p ' + self.te.out_dir) | ||
def _wload_run_init(self, experiment): | ||
experiment['out_dir'] = _get_experiment_out_dir(experiment) |
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.
isn't the out_dir already defined for each experiment in line 149?
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.
Yep, looks like this is leakage from another version of the commit.
.format(exp_idx, self._exp_count, | ||
tc_idx, wl_idx, | ||
run_idx, self._iterations)) | ||
.format(exp_idx, self._exp_count, # todo len(self.experiments?) |
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.
Here is where we can simplify a bit using the namedtuple, maybe by also s/experiment/exp/
And the #todo, either do it or remove it from the patch ;-)
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.
Removed the todo; it would be nice to get rid of the calculation of self._exp_count
in __init__
but for now I think it's more trouble than it's worth.
Re: s/experiment/exp/: why? We aren't short on horizontal space (the format
call has to be broken up, but it would be anyway), so why not be totally clear on what the variable refers to?
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.
I agree on using clear names... just wondering is exp can be a shorter still clear name.
No main concerns if you prefer to keep experiment ;-)
{ | ||
"modules" : [ "bl" ], | ||
"tools" : [ "rt-app" ], | ||
"ftrace" : { // TODO make these inherited |
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.
How do you want to inherit these?
In any case, if we do not do it now let's remove the comment as well from the committed code.
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.
Sorry, commit leakage again here. I was thinking about the fact that we want to specify the required events in order to avoid enormous traces, but they are the same for all the EAS tests. This is something to improve later, I think.
cls.env.ftrace.stop() | ||
trace = cls.env.ftrace.get_trace(cls.trace_file) | ||
conf_basename = "wake_migration.config" | ||
# TODO... |
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.
What?
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.
Oops, more commit leakage.
# TODO... | ||
phase_duration = WORKLOAD_DURATION_S | ||
|
||
def _assert_switch(self, experiment, expected_switch_to, phases): |
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.
Again, this seems more an update to the test than a refactoring, isn't it?
Maybe we can still use one additional patch with these changes?
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, I'll split this up.
phase_duration = WORKLOAD_DURATION_S | ||
|
||
def _assert_switch(self, experiment, expected_switch_to, phases): | ||
if expected_switch_to == "big": |
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.
Cannot we really avoid this big.LITTLE-ism? Perhaps not right now... :-/
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.
Yeah, I think this is something to remove later.
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.
The EAS acceptance tests are all about big.LITTLE I'm afraid. They use the "bl" module of target!
"""Wake Migration: BIG -> LITLLE: 2""" | ||
|
||
# little - big - little - big | ||
# ^ | ||
# We want to test that this big to little migration happens. So we skip | ||
# the first two phases. | ||
expected_time = self.offset + 2 * self.phase_duration |
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.
That patch is changing so much... we should really try to split it in two, or three if required, to make more easy to understand what it is doing...
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, will split this patch into one that ports to EasTest and one that factors out the commonality between the switch tests.
Base class for EAS tests | ||
""" | ||
|
||
set_is_big_little = True |
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.
This is not used anywhere in the commit. Should it be moved to the commit where it is actually used?
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.
Ah, this is a missing feature in the EasTest class - we need to set the "is_big_little" flag. Will add the missing code, I'll put it in this commit.
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.
Thanks a lot for the quick review! I have to be honest, I was expecting to have a chance to do my own self-review before anyone else got looked at it (hence the "TODO" leaks), probably I shouldn't have clicked "submit"!
# WORKLOAD: execution | ||
self._wload_run(exp_idx, tc, wl_idx, wload, itr_idx) | ||
exp_idx += 1 | ||
self.experiments.append({ |
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.
Nice, will give that a go.
@@ -464,38 +473,38 @@ def _wload_init(self, tc, wl_idx): | |||
wload = self._wload_conf(wl_idx, wlspec) | |||
|
|||
# Keep track of platform configuration | |||
self.te.test_dir = '{}/{}:{}:{}'\ |
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.
|
||
# Keep track of kernel configuration and version | ||
config = self.target.config | ||
with gzip.open(os.path.join(self.te.test_dir, 'kernel.config'), 'wb') as fh: |
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 on the change to the format call, but not on the self.te.test_dir -> test_dir:
Before this change, self.te.test_dir
is global state that is picked up later in _wload_run_init
. I could put this change in a previous patch which also modifies _wload_run and _wload_init to take a test_dir argument, but it seems unnecessary given that it will immediately be undone...
logging.debug(r'%14s - out_dir [%s]', 'Executor', self.te.out_dir) | ||
os.system('mkdir -p ' + self.te.out_dir) | ||
def _wload_run_init(self, experiment): | ||
experiment['out_dir'] = _get_experiment_out_dir(experiment) |
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.
Yep, looks like this is leakage from another version of the commit.
@@ -376,9 +376,7 @@ def _wload_rtapp(self, wl_idx, wlspec, cpus): | |||
if conf['class'] == 'profile': | |||
params = {} | |||
# Load each task specification | |||
for task_name in conf['params']: | |||
task = conf['params'][task_name] | |||
task_name = conf['prefix'] + task_name |
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.
That's a mistake. I think I'll drop this commit.
{ | ||
"modules" : [ "bl" ], | ||
"tools" : [ "rt-app" ], | ||
"ftrace" : { // TODO make these inherited |
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.
Sorry, commit leakage again here. I was thinking about the fact that we want to specify the required events in order to avoid enormous traces, but they are the same for all the EAS tests. This is something to improve later, I think.
cls.env.ftrace.stop() | ||
trace = cls.env.ftrace.get_trace(cls.trace_file) | ||
conf_basename = "wake_migration.config" | ||
# TODO... |
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.
Oops, more commit leakage.
# TODO... | ||
phase_duration = WORKLOAD_DURATION_S | ||
|
||
def _assert_switch(self, experiment, expected_switch_to, phases): |
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, I'll split this up.
phase_duration = WORKLOAD_DURATION_S | ||
|
||
def _assert_switch(self, experiment, expected_switch_to, phases): | ||
if expected_switch_to == "big": |
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.
Yeah, I think this is something to remove later.
"""Wake Migration: BIG -> LITLLE: 2""" | ||
|
||
# little - big - little - big | ||
# ^ | ||
# We want to test that this big to little migration happens. So we skip | ||
# the first two phases. | ||
expected_time = self.offset + 2 * self.phase_duration |
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, will split this patch into one that ports to EasTest and one that factors out the commonality between the switch tests.
msg="Not all tasks are running on LITTLE cores for at least {}% of their execution time"\ | ||
.format(EXPECTED_RESIDENCY_PCT)) | ||
|
||
.format(EXPECTED_RESIDENCY_PCT)) |
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.
Why remove the indentation? It's a continuation line and pep8 says "Make sure to indent the continued line appropriately".
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.
Oops, this is editor noise, will undo.
Since this PR is enormous and I'm rapidly discovering that the GitHub interface is fair from ideal I will rework this and submit a separate PR as v2 unless anyone objects. |
switch_from = self.te.target.bl.bigs | ||
switch_to = self.te.target.bl.littles | ||
else: | ||
raise Exception("Invalid expected_switch_to") |
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.
ValueError
is more specific than Exception
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.
raise Exception("Invalid expected_switch_to") | ||
|
||
expected_time = (self.get_start_time(experiment) + | ||
WORKLOAD_DURATION_S * phases) |
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.
I know we are almost never consistent with this part of pep8, but it recommends breaking line before the +
and removing the spaces around the *
because it takes higher preference
expected_time = (self.get_start_time(experiment)
+ WORKLOAD_DURATION_S*phases)
https://www.python.org/dev/peps/pep-0008/#should-a-line-break-before-or-after-a-binary-operator
https://www.python.org/dev/peps/pep-0008/#other-recommendations
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.
Ah, I didn't know about that. Will change.
While you are at it, you could fix "targt" in the log output in |
background=False) | ||
cls.env.ftrace.stop() | ||
trace = cls.env.ftrace.get_trace(cls.trace_file) | ||
conf_basename = "wake_migration.config" |
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 forgot to git add tests/eas/wake_migration.config
I've tried running this, but it explodes in a ball of flames. Some of the errors that I see, other than what I have pointed out in the review:
Why is it even looking at energy?
|
@JaviMerino Re: hwmon error: It looks at hwmon because it's in the default Devlib modules. I thought that that error was due to the way I'd set up my kernel (the hwmon module doesn't produce any errors but it produces empty data, hence they key errors) and disabled hwmon in my target.config. My plan was in a separate PR to a) make hwmon disabled by default (only enabled on tests that need it) and b) make it fail more gracefully when the board doesn't support it as expected. Since you're seeing the error too, I'll take a look at it before submitting v2 of this. Re: missing wake_migration.config, I noticed that shortly after submitting the PR :$ will be back in v2. Re: s/targt/target/: will do. |
The HWMon issue is present in master too, but it doesn't manifest because the existing acceptance tests don't call I'm going to disable hwmon in the test configs (unfortunately I can't see a way to disable using energy meters in general, only hwmon specifically), and raise a separate issue to figure out why HWMon isn't working. Disabling it in the test configs is reasonably sensible anyway since they don't need energy readings, having hwmon just slows things down. |
superseded by v2: #202 |
test_
methodsAlso some miscellaneous cleanups that seem to me to be related to this.