Yuheng Long | 16d7a52 | 2013-07-19 16:29:13 -0700 | [diff] [blame] | 1 | # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| 2 | # Use of this source code is governed by a BSD-style license that can be |
| 3 | # found in the LICENSE file. |
| 4 | |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 5 | """A generation of a set of tasks. |
| 6 | |
Yuheng Long | 49358b7 | 2013-07-10 14:45:29 -0700 | [diff] [blame] | 7 | Part of the Chrome build flags optimization. |
| 8 | |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 9 | This module contains the base generation class. This class contains the tasks of |
| 10 | this current generation. The generation will not evolve to the next generation |
| 11 | until all the tasks in this generation are done executing. It also contains a |
| 12 | set of tasks that could potentially be used to generate the next generation, |
| 13 | e.g., in the genetic algorithm, a set of good species will be kept to evolve to |
| 14 | the successive generations. For the hill climbing algorithm example, the |
| 15 | candidate_pool will contain a current task t being evaluated and the exe_pool |
| 16 | will contains all the task t's neighbor. |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 17 | """ |
| 18 | |
| 19 | __author__ = 'yuhenglong@google.com (Yuheng Long)' |
| 20 | |
| 21 | |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 22 | class NoneOverridingError(Exception): |
| 23 | """Define an Exception class for subclasses not overriding certain methods.""" |
| 24 | pass |
| 25 | |
| 26 | |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 27 | class Generation(object): |
| 28 | """A generation of a framework run. |
| 29 | |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 30 | The base class of generation. Concrete subclasses, e.g., GAGeneration should |
| 31 | override the Next and Improve method to implement algorithm specific |
| 32 | applications. |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 33 | """ |
| 34 | |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 35 | def __init__(self, exe_pool, candidate_pool): |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 36 | """Set up the tasks set of this generation. |
| 37 | |
| 38 | Args: |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 39 | exe_pool: A set of tasks to be run. |
| 40 | candidate_pool: A set of tasks to be considered to be used to generate the |
| 41 | next generation. |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 42 | """ |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 43 | |
| 44 | self._exe_pool = exe_pool |
| 45 | self._candidate_pool = candidate_pool |
| 46 | |
| 47 | # Keeping the record of how many tasks are pending. Pending tasks are the |
| 48 | # ones that have been sent out to the next stage for execution but have not |
| 49 | # finished. A generation is not ready for the reproduction of the new |
| 50 | # generations until all its pending tasks have been executed. |
| 51 | self._pending = len(exe_pool) |
| 52 | |
| 53 | def Pool(self): |
| 54 | """Return the task set of this generation.""" |
| 55 | |
| 56 | return self._exe_pool |
| 57 | |
| 58 | def Done(self): |
| 59 | """All the tasks in this generation are done. |
| 60 | |
| 61 | Returns: |
| 62 | True if all the tasks have been executed. That is the number of pending |
| 63 | task is 0. |
| 64 | """ |
| 65 | |
| 66 | return self._pending == 0 |
| 67 | |
| 68 | def UpdateTask(self, task): |
| 69 | """Match a task t in this generation that is equal to the input task. |
| 70 | |
| 71 | This method is called when the input task has just finished execution. This |
| 72 | method finds out whether there is a pending task t in the current generation |
| 73 | that is the same as the input task. Two tasks are the same if their flag |
| 74 | options are the same. A task is pending if it has not been performed. |
| 75 | If there is a pending task t that matches the input task, task t will be |
| 76 | substituted with the input task in this generation. In that case, the input |
| 77 | task, as well as its build and test results encapsulated in the task, will |
| 78 | be stored in the current generation. These results could be used to produce |
| 79 | the next generation. |
| 80 | If there is a match, the current generation will have one less pending task. |
| 81 | When there is no pending task, the generation can be used to produce the |
| 82 | next generation. |
| 83 | The caller of this function is responsible for not calling this method on |
| 84 | the same task more than once. |
| 85 | |
| 86 | Args: |
| 87 | task: A task that has its results ready. |
Yuheng Long | a5712a2 | 2013-07-22 13:51:17 -0700 | [diff] [blame] | 88 | |
| 89 | Returns: |
| 90 | Whether the input task belongs to this generation. |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 91 | """ |
| 92 | |
Yuheng Long | a5712a2 | 2013-07-22 13:51:17 -0700 | [diff] [blame] | 93 | # If there is a match, the input task belongs to this generation. |
| 94 | if task not in self._exe_pool: |
| 95 | return False |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 96 | |
Yuheng Long | a5712a2 | 2013-07-22 13:51:17 -0700 | [diff] [blame] | 97 | # Remove the place holder task in this generation and store the new input |
| 98 | # task and its result. |
| 99 | self._exe_pool.remove(task) |
| 100 | self._exe_pool.add(task) |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 101 | |
Yuheng Long | a5712a2 | 2013-07-22 13:51:17 -0700 | [diff] [blame] | 102 | # The current generation will have one less task to wait on. |
| 103 | self._pending -= 1 |
| 104 | |
| 105 | assert self._pending >= 0 |
| 106 | |
| 107 | return True |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 108 | |
| 109 | def Improve(self): |
Yuheng Long | ccfaf2f | 2013-08-02 14:27:45 -0700 | [diff] [blame] | 110 | """True if this generation has improvement upon its parent generation. |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 111 | |
| 112 | Raises: |
| 113 | NoneOverridingError: The subclass should override this method. |
| 114 | """ |
| 115 | raise NoneOverridingError('Must be implemented by child class') |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 116 | |
Yuheng Long | ccfaf2f | 2013-08-02 14:27:45 -0700 | [diff] [blame] | 117 | def Next(self, _): |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 118 | """Calculate the next generation. |
| 119 | |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 120 | This is the core of the framework implementation. It must be overridden by |
| 121 | the concrete subclass to implement algorithm specific generations. |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 122 | |
Yuheng Long | ccfaf2f | 2013-08-02 14:27:45 -0700 | [diff] [blame] | 123 | Args: |
| 124 | _: A set of tasks that have been generated before. The overridden method |
| 125 | in the subclasses can use this so as not to generate task that has been |
| 126 | generated before. |
| 127 | |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 128 | Returns: |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 129 | A set of new generations. |
| 130 | |
| 131 | Raises: |
| 132 | NoneOverridingError: The subclass should override this method. |
Yuheng Long | f20cffa | 2013-06-03 18:46:00 -0700 | [diff] [blame] | 133 | """ |
| 134 | |
Yuheng Long | 8b9c0f1 | 2013-07-16 09:38:16 -0700 | [diff] [blame] | 135 | raise NoneOverridingError('Must be implemented by child class') |