You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.7 KiB
139 lines
4.7 KiB
# Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
|
# Use of this source code is governed by a BSD-style license that can be |
|
# found in the LICENSE file. |
|
"""A generation of a set of tasks. |
|
|
|
Part of the Chrome build flags optimization. |
|
|
|
This module contains the base generation class. This class contains the tasks of |
|
this current generation. The generation will not evolve to the next generation |
|
until all the tasks in this generation are done executing. It also contains a |
|
set of tasks that could potentially be used to generate the next generation, |
|
e.g., in the genetic algorithm, a set of good species will be kept to evolve to |
|
the successive generations. For the hill climbing algorithm example, the |
|
candidate_pool will contain a current task t being evaluated and the exe_set |
|
will contains all the task t's neighbor. |
|
""" |
|
|
|
__author__ = 'yuhenglong@google.com (Yuheng Long)' |
|
|
|
|
|
class NoneOverridingError(Exception): |
|
"""Define an Exception class for subclasses not overriding certain methods.""" |
|
pass |
|
|
|
|
|
class Generation(object): |
|
"""A generation of a framework run. |
|
|
|
The base class of generation. Concrete subclasses, e.g., GAGeneration should |
|
override the Next and IsImproved method to implement algorithm specific |
|
applications. |
|
""" |
|
|
|
def __init__(self, exe_set, candidate_pool): |
|
"""Set up the tasks set of this generation. |
|
|
|
Args: |
|
exe_set: A set of tasks to be run. |
|
candidate_pool: A set of tasks to be considered to be used to generate the |
|
next generation. |
|
""" |
|
|
|
self._exe_set = exe_set |
|
self._candidate_pool = candidate_pool |
|
|
|
# Keeping the record of how many tasks are pending. Pending tasks are the |
|
# ones that have been sent out to the next stage for execution but have not |
|
# finished. A generation is not ready for the reproduction of the new |
|
# generations until all its pending tasks have been executed. |
|
self._pending = len(exe_set) |
|
|
|
def CandidatePool(self): |
|
"""Return the candidate tasks of this generation.""" |
|
|
|
return self._candidate_pool |
|
|
|
def Pool(self): |
|
"""Return the task set of this generation.""" |
|
|
|
return self._exe_set |
|
|
|
def Done(self): |
|
"""All the tasks in this generation are done. |
|
|
|
Returns: |
|
True if all the tasks have been executed. That is the number of pending |
|
task is 0. |
|
""" |
|
|
|
return self._pending == 0 |
|
|
|
def UpdateTask(self, task): |
|
"""Match a task t in this generation that is equal to the input task. |
|
|
|
This method is called when the input task has just finished execution. This |
|
method finds out whether there is a pending task t in the current generation |
|
that is the same as the input task. Two tasks are the same if their flag |
|
options are the same. A task is pending if it has not been performed. |
|
If there is a pending task t that matches the input task, task t will be |
|
substituted with the input task in this generation. In that case, the input |
|
task, as well as its build and test results encapsulated in the task, will |
|
be stored in the current generation. These results could be used to produce |
|
the next generation. |
|
If there is a match, the current generation will have one less pending task. |
|
When there is no pending task, the generation can be used to produce the |
|
next generation. |
|
The caller of this function is responsible for not calling this method on |
|
the same task more than once. |
|
|
|
Args: |
|
task: A task that has its results ready. |
|
|
|
Returns: |
|
Whether the input task belongs to this generation. |
|
""" |
|
|
|
# If there is a match, the input task belongs to this generation. |
|
if task not in self._exe_set: |
|
return False |
|
|
|
# Remove the place holder task in this generation and store the new input |
|
# task and its result. |
|
self._exe_set.remove(task) |
|
self._exe_set.add(task) |
|
|
|
# The current generation will have one less task to wait on. |
|
self._pending -= 1 |
|
|
|
assert self._pending >= 0 |
|
|
|
return True |
|
|
|
def IsImproved(self): |
|
"""True if this generation has improvement upon its parent generation. |
|
|
|
Raises: |
|
NoneOverridingError: The subclass should override this method. |
|
""" |
|
raise NoneOverridingError('Must be implemented by child class') |
|
|
|
def Next(self, _): |
|
"""Calculate the next generation. |
|
|
|
This is the core of the framework implementation. It must be overridden by |
|
the concrete subclass to implement algorithm specific generations. |
|
|
|
Args: |
|
_: A set of tasks that have been generated before. The overridden method |
|
in the subclasses can use this so as not to generate task that has been |
|
generated before. |
|
|
|
Returns: |
|
A set of new generations. |
|
|
|
Raises: |
|
NoneOverridingError: The subclass should override this method. |
|
""" |
|
|
|
raise NoneOverridingError('Must be implemented by child class')
|
|
|