[Ezbench-dev,3/3] smartezbench: allow specifying if a task is user- or auto-requested

Submitted by Martin Peres on March 15, 2017, 1:44 p.m.

Details

Message ID 20170315134448.21577-4-martin.peres@linux.intel.com
State New
Headers show
Series "Separate user- and auto-requested tasks" ( rev: 1 ) in EzBench

Not browsing as part of any series.

Commit Message

Martin Peres March 15, 2017, 1:44 p.m.
We will first run user-requested tasks, then handle auto-requested
ones. We also reset the auto tasks after every call to run(), to
make sure the decision to run something is always up to date!
---
 python-modules/ezbench/smartezbench.py | 127 ++++++++++++++++++++++-----------
 1 file changed, 85 insertions(+), 42 deletions(-)

Patch hide | download patch | download mbox

diff --git a/python-modules/ezbench/smartezbench.py b/python-modules/ezbench/smartezbench.py
index aea406a..466079d 100644
--- a/python-modules/ezbench/smartezbench.py
+++ b/python-modules/ezbench/smartezbench.py
@@ -92,7 +92,8 @@  def list_smart_ezbench_report_names(ezbench_dir, updatedSince = 0):
     return reports
 
 class TaskEntry:
-    def __init__(self, commit, test, rounds, resumeResultFile = None):
+    def __init__(self, commit, test, rounds, resumeResultFile = None,
+                 user_requested = True):
         self.commit = commit
         self.test = test
         self.rounds = rounds
@@ -100,6 +101,7 @@  class TaskEntry:
         self.start_date = None
         self.exec_time = None
         self.build_time = None
+        self.user_requested = user_requested
 
         self.cur_round = 1
         self.last_round_completed_date = None
@@ -186,6 +188,9 @@  class TaskEntry:
             else:
                 string += "(no estimation available)"
 
+        if not self.user_requested:
+            string += " (autogenerated)"
+
         return string
 
 GitCommit = namedtuple('GitCommit', 'sha1 timestamp')
@@ -311,6 +316,13 @@  class SmartEzbench:
             del self.state['commits']
             upgraded = True
 
+        if version == 2:
+            self.__log(Criticality.II, "state: v2 -> v3: create a new 'auto' sections for tasks")
+            self.state['version'] = 3
+            self.state['tasks']['auto'] = dict()
+            self.state['tasks']['auto']['commits'] = dict()
+            upgraded = True
+
         if upgraded:
             self.__save_state()
 
@@ -523,12 +535,16 @@  class SmartEzbench:
 
         return total_rounds
 
-    def __add_test_unlocked__(self, commit, test, rounds):
+    def __add_test_unlocked__(self, commit, test, rounds, user_requested=True):
         scm = self.repo()
         if scm is not None:
             commit = scm.full_version_name(commit)
 
-        commits = self.state['tasks']['user']['commits']
+        if user_requested:
+            commits = self.state['tasks']['user']['commits']
+        else:
+            commits = self.state['tasks']['auto']['commits']
+
         if rounds is None:
             return commits[commit]['tests'][test]['rounds']
 
@@ -538,14 +554,14 @@  class SmartEzbench:
         if self.__running_mode_unlocked__(check_running=False) == RunningMode.DONE:
             self.__set_running_mode_unlocked__(RunningMode.RUN)
 
-    def add_test(self, commit, test, rounds = None):
+    def add_test(self, commit, test, rounds = None, user_requested=True):
         self.__reload_state(keep_lock=True)
         total_rounds = self.__add_test_unlocked__(commit, test, rounds)
         self.__save_state()
         self.__release_lock()
         return total_rounds
 
-    def add_testset(self, commit, testset, rounds = 1, ensure=False):
+    def add_testset(self, commit, testset, rounds = 1, ensure=False, user_requested=True):
         self.__reload_state(keep_lock=True)
 
         self.__log(Criticality.II, "Add the testset {} ({} tests)".format(testset.name,
@@ -553,14 +569,14 @@  class SmartEzbench:
 
         for test in sorted(testset.keys()):
             if not ensure:
-                self.__add_test_unlocked__(commit, test, testset[test] * rounds)
+                self.__add_test_unlocked__(commit, test, testset[test] * rounds, user_requested)
             else:
-                self.__force_test_rounds_unlocked__(commit, test, testset[test] * rounds)
+                self.__force_test_rounds_unlocked__(commit, test, testset[test] * rounds, user_requested)
 
         self.__save_state()
         self.__release_lock()
 
-    def __force_test_rounds_unlocked__(self, commit, test, at_least):
+    def __force_test_rounds_unlocked__(self, commit, test, at_least, user_requested=True):
         scm = self.repo()
         if scm is not None:
             commit = scm.full_version_name(commit)
@@ -570,7 +586,11 @@  class SmartEzbench:
         else:
             at_least = int(at_least)
 
-        commits = self.state['tasks']['user']['commits']
+        if user_requested:
+            commits = self.state['tasks']['user']['commits']
+        else:
+            commits = self.state['tasks']['auto']['commits']
+
         if commit not in commits:
             commits[commit] = dict()
             commits[commit]["tests"] = dict()
@@ -587,9 +607,9 @@  class SmartEzbench:
         else:
             return 0
 
-    def force_test_rounds(self, commit, test, at_least):
+    def force_test_rounds(self, commit, test, at_least, user_requested=True):
         self.__reload_state(keep_lock=True)
-        ret = self.__force_test_rounds_unlocked__(commit, test, at_least)
+        ret = self.__force_test_rounds_unlocked__(commit, test, at_least, user_requested)
         self.__save_state()
         self.__release_lock()
 
@@ -622,10 +642,7 @@  class SmartEzbench:
 
         return c, tl, self._events_str
 
-    def __prioritize_runs(self, task_tree, deployed_version, resumable_tasks):
-        task_list = deque()
-
-        # Aggregate all the subtests
+    def __aggregate_subtests__(self, task_tree):
         for commit in task_tree:
             test_subtests = dict()
             test_rounds = dict()
@@ -646,6 +663,20 @@  class SmartEzbench:
                 task_tree[commit]["tests"][full_name] = dict()
                 task_tree[commit]["tests"][full_name]["rounds"] = test_rounds[basename]
 
+    def __prioritize_runs_add_by_commit__(self, task_list, task_tree, user_requested=True):
+        # Add all the remaining tasks in whatever order!
+        for commit in task_tree:
+            for test in task_tree[commit]["tests"]:
+                rounds = task_tree[commit]["tests"][test]["rounds"]
+                task_list.append(TaskEntry(commit, test, rounds, user_requested))
+
+    def __prioritize_runs(self, task_tree_user, task_tree_auto, deployed_version, resumable_tasks):
+        task_list = deque()
+
+        # Aggregate all the subtests
+        self.__aggregate_subtests__(task_tree_user)
+        self.__aggregate_subtests__(task_tree_auto)
+
         # Schedule resumable tasks. First the already-deployed
         # versions, other versions later
         for task in resumable_tasks:
@@ -663,19 +694,19 @@  class SmartEzbench:
             # Get rid of the task
             self.__task_tree_add_test__(task_tree, entry.commit, entry.test, -1)
 
-        # Schedule the tests using the already-deployed version after
-        # all resumable tasks
-        if deployed_version is not None and deployed_version in task_tree:
-            for test in task_tree[deployed_version]["tests"]:
-                rounds = task_tree[deployed_version]["tests"][test]["rounds"]
-                task_list.append(TaskEntry(deployed_version, test, rounds))
-            del task_tree[deployed_version]
+        # Add all the task wanted by the user that can be run on the
+        # currently-deployed component
+        if deployed_version is not None and deployed_version in task_tree_user:
+            for test in task_tree_user[deployed_version]["tests"]:
+                rounds = task_tree_user[deployed_version]["tests"][test]["rounds"]
+                task_list.append(TaskEntry(deployed_version, test, rounds,
+                                           user_requested=True))
+            del task_tree_user[deployed_version]
 
-        # Add all the remaining tasks in whatever order!
-        for commit in task_tree:
-            for test in task_tree[commit]["tests"]:
-                rounds = task_tree[commit]["tests"][test]["rounds"]
-                task_list.append(TaskEntry(commit, test, rounds))
+        # Schedule the user-requested tests first, then the automatic. Add them
+        # in whatever order
+        self.__prioritize_runs_add_by_commit__(task_list, task_tree_user, user_requested=True)
+        self.__prioritize_runs_add_by_commit__(task_list, task_tree_auto, user_requested=False)
 
         return task_list
 
@@ -726,6 +757,14 @@  class SmartEzbench:
         return True
 
     @classmethod
+    def __remove_existing_tasks_from_tree(cls, report, task_tree):
+        for commit in report.commits:
+            for result in commit.results.values():
+                for key in result.results():
+                    full_name = Test.partial_name(result.test.full_name, [key])
+                    SmartEzbench.__remove_task_from_tasktree__(task_tree, commit.full_sha1, full_name, len(result.result(key)))
+
+    @classmethod
     def __generate_task_and_events_list__(cls, q, state, log_folder, scm):
         exit_code = 1
         task_tree = list()
@@ -748,13 +787,11 @@  class SmartEzbench:
                 events_str.append(str(event))
 
             # Walk down the report and get rid of every run that has already been made!
-            task_tree = copy.deepcopy(self.state['tasks']['user']['commits'])
+            task_tree_user = copy.deepcopy(state['tasks']['user']['commits'])
+            cls.__remove_existing_tasks_from_tree(report, task_tree_user)
 
-            for commit in report.commits:
-                for result in commit.results.values():
-                    for key in result.results():
-                        full_name = Test.partial_name(result.test.full_name, [key])
-                        SmartEzbench.__remove_task_from_tasktree__(task_tree, commit.full_sha1, full_name, len(result.result(key)))
+            task_tree_auto = copy.deepcopy(state['tasks']['auto']['commits'])
+            cls.__remove_existing_tasks_from_tree(report, task_tree_user)
 
             resumable_tasks = report.journal.incomplete_tests()
 
@@ -773,7 +810,7 @@  class SmartEzbench:
             pass
 
         # Return the result
-        q.put((exit_code, task_tree, events_str, resumable_tasks))
+        q.put((exit_code, task_tree_user, task_tree_auto, events_str, resumable_tasks))
 
     def run(self):
         self.__log(Criticality.II, "----------------------")
@@ -808,23 +845,29 @@  class SmartEzbench:
         p = multiprocessing.Process(target=SmartEzbench.__generate_task_and_events_list__,
                                     args=(q, self.state, self.log_folder, self.repo()))
         p.start()
-        exit_code, task_tree, self._events_str, resumable_tasks = q.get()
+        exit_code, task_tree_user, task_tree_auto, self._events_str, resumable_tasks = q.get()
         p.join()
 
-        if len(task_tree) == 0:
+        if len(task_tree_user) == 0 and len(task_tree_auto) == 0:
             self.__log(Criticality.II, "Nothing left to do, exit")
             return False
 
-        task_tree_str = pprint.pformat(task_tree)
-        self.__log(Criticality.II, "Task list: {tsk_str}".format(tsk_str=task_tree_str))
+        task_tree_user_str = pprint.pformat(task_tree_user)
+        task_tree_auto_str = pprint.pformat(task_tree_auto)
+        self.__log(Criticality.II, "Task list (user): {tsk_str}".format(tsk_str=task_tree_user_str))
+        self.__log(Criticality.II, "Task list (auto): {tsk_str}".format(tsk_str=task_tree_auto_str))
         self.__log(Criticality.II, "Incomplete runs: {}".format([r['result_file'] for r in resumable_tasks]))
 
-        # Lock the report for further changes (like for profiles)
-        self.__write_attribute__('beenRunBefore', True)
+        # Write all the changes to the state
+        self.__reload_state(keep_lock=True)
+        self.state['tasks']['auto']['commits'] = dict()
+        self.__write_attribute_unlocked__('beenRunBefore', True)
+        self.__save_state()
+        self.__release_lock()
 
         # Prioritize --> return a list of commits to do in order
         self._task_lock.acquire()
-        self._task_list = self.__prioritize_runs(task_tree, deployed_commit, resumable_tasks)
+        self._task_list = self.__prioritize_runs(task_tree_user, task_tree_auto, deployed_commit, resumable_tasks)
 
         # Call the hook file, telling we started running
         self.__call_hook__('start_running_tests')
@@ -1127,7 +1170,7 @@  class SmartEzbench:
             self.__log(Criticality.DD, "Add all the tasks using commit {}".format(commit))
             for t in tasks_sorted:
                 if t[1] == commit:
-                    added = self.__force_test_rounds_unlocked__(t[1], t[2], t[3])
+                    added = self.__force_test_rounds_unlocked__(t[1], t[2], t[3], user_requested=False)
                     if added > 0:
                         self.__log(Criticality.II,
                                 "Scheduled {} more runs for the test {} on commit {}".format(added, t[2], commit))