xref: /aosp_15_r20/external/toolchain-utils/bestflags/generation.py (revision 760c253c1ed00ce9abd48f8546f08516e57485fe)
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