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