xref: /aosp_15_r20/external/toolchain-utils/bestflags/testing_batch.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"""Hill climbing unitest.
5*760c253cSXin Li
6*760c253cSXin LiPart of the Chrome build flags optimization.
7*760c253cSXin Li
8*760c253cSXin LiTest the best branching hill climbing algorithms, genetic algorithm and
9*760c253cSXin Liiterative elimination algorithm.
10*760c253cSXin Li"""
11*760c253cSXin Li
12*760c253cSXin Li__author__ = "[email protected] (Yuheng Long)"
13*760c253cSXin Li
14*760c253cSXin Liimport multiprocessing
15*760c253cSXin Liimport random
16*760c253cSXin Liimport sys
17*760c253cSXin Liimport unittest
18*760c253cSXin Li
19*760c253cSXin Liimport flags
20*760c253cSXin Lifrom flags import Flag
21*760c253cSXin Lifrom flags import FlagSet
22*760c253cSXin Lifrom genetic_algorithm import GAGeneration
23*760c253cSXin Lifrom genetic_algorithm import GATask
24*760c253cSXin Lifrom hill_climb_best_neighbor import HillClimbingBestBranch
25*760c253cSXin Lifrom iterative_elimination import IterativeEliminationFirstGeneration
26*760c253cSXin Liimport pipeline_process
27*760c253cSXin Lifrom steering import Steering
28*760c253cSXin Lifrom task import BUILD_STAGE
29*760c253cSXin Lifrom task import Task
30*760c253cSXin Lifrom task import TEST_STAGE
31*760c253cSXin Li
32*760c253cSXin Li
33*760c253cSXin Li# The number of flags be tested.
34*760c253cSXin LiNUM_FLAGS = 5
35*760c253cSXin Li
36*760c253cSXin Li# The value range of the flags.
37*760c253cSXin LiFLAG_RANGES = 10
38*760c253cSXin Li
39*760c253cSXin Li# The following variables are meta data for the Genetic Algorithm.
40*760c253cSXin LiSTOP_THRESHOLD = 20
41*760c253cSXin LiNUM_CHROMOSOMES = 10
42*760c253cSXin LiNUM_TRIALS = 20
43*760c253cSXin LiMUTATION_RATE = 0.03
44*760c253cSXin Li
45*760c253cSXin Li
46*760c253cSXin Lidef _GenerateRandomRasks(specs):
47*760c253cSXin Li    """Generate a task that has random values.
48*760c253cSXin Li
49*760c253cSXin Li    Args:
50*760c253cSXin Li      specs: A list of spec from which the flag set is created.
51*760c253cSXin Li
52*760c253cSXin Li    Returns:
53*760c253cSXin Li      A set containing a task that has random values.
54*760c253cSXin Li    """
55*760c253cSXin Li
56*760c253cSXin Li    flag_set = []
57*760c253cSXin Li
58*760c253cSXin Li    for spec in specs:
59*760c253cSXin Li        numeric_flag_match = flags.Search(spec)
60*760c253cSXin Li        if numeric_flag_match:
61*760c253cSXin Li            # Numeric flags.
62*760c253cSXin Li            start = int(numeric_flag_match.group("start"))
63*760c253cSXin Li            end = int(numeric_flag_match.group("end"))
64*760c253cSXin Li
65*760c253cSXin Li            value = random.randint(start - 1, end - 1)
66*760c253cSXin Li            if value != start - 1:
67*760c253cSXin Li                # If the value falls in the range, this flag is enabled.
68*760c253cSXin Li                flag_set.append(Flag(spec, value))
69*760c253cSXin Li        else:
70*760c253cSXin Li            # Boolean flags.
71*760c253cSXin Li            if random.randint(0, 1):
72*760c253cSXin Li                flag_set.append(Flag(spec))
73*760c253cSXin Li
74*760c253cSXin Li    return set([Task(FlagSet(flag_set))])
75*760c253cSXin Li
76*760c253cSXin Li
77*760c253cSXin Lidef _GenerateAllFlagsTasks(specs):
78*760c253cSXin Li    """Generate a task that all the flags are enable.
79*760c253cSXin Li
80*760c253cSXin Li    All the boolean flags in the specs will be enabled and all the numeric flag
81*760c253cSXin Li    with have the largest legal value.
82*760c253cSXin Li
83*760c253cSXin Li    Args:
84*760c253cSXin Li      specs: A list of spec from which the flag set is created.
85*760c253cSXin Li
86*760c253cSXin Li    Returns:
87*760c253cSXin Li      A set containing a task that has all flags enabled.
88*760c253cSXin Li    """
89*760c253cSXin Li
90*760c253cSXin Li    flag_set = []
91*760c253cSXin Li
92*760c253cSXin Li    for spec in specs:
93*760c253cSXin Li        numeric_flag_match = flags.Search(spec)
94*760c253cSXin Li
95*760c253cSXin Li        if numeric_flag_match:
96*760c253cSXin Li            value = int(numeric_flag_match.group("end")) - 1
97*760c253cSXin Li        else:
98*760c253cSXin Li            value = -1
99*760c253cSXin Li        flag_set.append(Flag(spec, value))
100*760c253cSXin Li
101*760c253cSXin Li    return set([Task(FlagSet(flag_set))])
102*760c253cSXin Li
103*760c253cSXin Li
104*760c253cSXin Lidef _GenerateNoFlagTask():
105*760c253cSXin Li    return set([Task(FlagSet([]))])
106*760c253cSXin Li
107*760c253cSXin Li
108*760c253cSXin Lidef GenerateRandomGATasks(specs, num_tasks, num_trials):
109*760c253cSXin Li    """Generate a set of tasks for the Genetic Algorithm.
110*760c253cSXin Li
111*760c253cSXin Li    Args:
112*760c253cSXin Li      specs: A list of spec from which the flag set is created.
113*760c253cSXin Li      num_tasks: number of tasks that should be generated.
114*760c253cSXin Li      num_trials: the maximum number of tries should be attempted to generate the
115*760c253cSXin Li        set of tasks.
116*760c253cSXin Li
117*760c253cSXin Li    Returns:
118*760c253cSXin Li      A set of randomly generated tasks.
119*760c253cSXin Li    """
120*760c253cSXin Li
121*760c253cSXin Li    tasks = set([])
122*760c253cSXin Li
123*760c253cSXin Li    total_trials = 0
124*760c253cSXin Li    while len(tasks) < num_tasks and total_trials < num_trials:
125*760c253cSXin Li        new_flag = FlagSet(
126*760c253cSXin Li            [Flag(spec) for spec in specs if random.randint(0, 1)]
127*760c253cSXin Li        )
128*760c253cSXin Li        new_task = GATask(new_flag)
129*760c253cSXin Li
130*760c253cSXin Li        if new_task in tasks:
131*760c253cSXin Li            total_trials += 1
132*760c253cSXin Li        else:
133*760c253cSXin Li            tasks.add(new_task)
134*760c253cSXin Li            total_trials = 0
135*760c253cSXin Li
136*760c253cSXin Li    return tasks
137*760c253cSXin Li
138*760c253cSXin Li
139*760c253cSXin Lidef _GenerateInitialFlags(specs, spec):
140*760c253cSXin Li    """Generate the flag_set of a task in the flag elimination algorithm.
141*760c253cSXin Li
142*760c253cSXin Li    Set the value of all the flags to the largest value, except for the flag that
143*760c253cSXin Li    contains spec.
144*760c253cSXin Li
145*760c253cSXin Li    For example, if the specs are [-finline-limit=[1-1000], -fstrict-aliasing] and
146*760c253cSXin Li    the spec is -finline-limit=[1-1000], then the result is
147*760c253cSXin Li    [-finline-limit=[1-1000]:-finline-limit=998,
148*760c253cSXin Li     -fstrict-aliasing:-fstrict-aliasing]
149*760c253cSXin Li
150*760c253cSXin Li    Args:
151*760c253cSXin Li      specs: an array of specifications from which the result flag_set is created.
152*760c253cSXin Li        The flag_set contains one and only one flag that contain the specification
153*760c253cSXin Li        spec.
154*760c253cSXin Li      spec: The flag containing this spec should have a value that is smaller than
155*760c253cSXin Li        the highest value the flag can have.
156*760c253cSXin Li
157*760c253cSXin Li    Returns:
158*760c253cSXin Li      An array of flags, each of which contains one spec in specs. All the values
159*760c253cSXin Li      of the flags are the largest values in specs, expect the one that contains
160*760c253cSXin Li      spec.
161*760c253cSXin Li    """
162*760c253cSXin Li
163*760c253cSXin Li    flag_set = []
164*760c253cSXin Li    for other_spec in specs:
165*760c253cSXin Li        numeric_flag_match = flags.Search(other_spec)
166*760c253cSXin Li        # Found the spec in the array specs.
167*760c253cSXin Li        if other_spec == spec:
168*760c253cSXin Li            # Numeric flag will have a value that is smaller than the largest value
169*760c253cSXin Li            # and Boolean flag will be deleted.
170*760c253cSXin Li            if numeric_flag_match:
171*760c253cSXin Li                end = int(numeric_flag_match.group("end"))
172*760c253cSXin Li                flag_set.append(flags.Flag(other_spec, end - 2))
173*760c253cSXin Li
174*760c253cSXin Li            continue
175*760c253cSXin Li
176*760c253cSXin Li        # other_spec != spec
177*760c253cSXin Li        if numeric_flag_match:
178*760c253cSXin Li            # numeric flag
179*760c253cSXin Li            end = int(numeric_flag_match.group("end"))
180*760c253cSXin Li            flag_set.append(flags.Flag(other_spec, end - 1))
181*760c253cSXin Li            continue
182*760c253cSXin Li
183*760c253cSXin Li        # boolean flag
184*760c253cSXin Li        flag_set.append(flags.Flag(other_spec))
185*760c253cSXin Li
186*760c253cSXin Li    return flag_set
187*760c253cSXin Li
188*760c253cSXin Li
189*760c253cSXin Lidef _GenerateAllIterativeEliminationTasks(specs):
190*760c253cSXin Li    """Generate the initial tasks for the negative flag elimination algorithm.
191*760c253cSXin Li
192*760c253cSXin Li    Generate the base line task that turns on all the boolean flags and sets the
193*760c253cSXin Li    value to be the largest value for the numeric flag.
194*760c253cSXin Li
195*760c253cSXin Li    For example, if the specs are [-finline-limit=[1-1000], -fstrict-aliasing],
196*760c253cSXin Li    the base line is [-finline-limit=[1-1000]:-finline-limit=999,
197*760c253cSXin Li    -fstrict-aliasing:-fstrict-aliasing]
198*760c253cSXin Li
199*760c253cSXin Li    Generate a set of task, each turns off one of the flag or sets a value that is
200*760c253cSXin Li    smaller than the largest value for the flag.
201*760c253cSXin Li
202*760c253cSXin Li    Args:
203*760c253cSXin Li      specs: an array of specifications from which the result flag_set is created.
204*760c253cSXin Li
205*760c253cSXin Li    Returns:
206*760c253cSXin Li      An array containing one generation of the initial tasks for the negative
207*760c253cSXin Li      flag elimination algorithm.
208*760c253cSXin Li    """
209*760c253cSXin Li
210*760c253cSXin Li    # The set of tasks to be generated.
211*760c253cSXin Li    results = set([])
212*760c253cSXin Li    flag_set = []
213*760c253cSXin Li
214*760c253cSXin Li    for spec in specs:
215*760c253cSXin Li        numeric_flag_match = flags.Search(spec)
216*760c253cSXin Li        if numeric_flag_match:
217*760c253cSXin Li            # Numeric flag.
218*760c253cSXin Li            end_value = int(numeric_flag_match.group("end"))
219*760c253cSXin Li            flag_set.append(flags.Flag(spec, end_value - 1))
220*760c253cSXin Li            continue
221*760c253cSXin Li
222*760c253cSXin Li        # Boolean flag.
223*760c253cSXin Li        flag_set.append(flags.Flag(spec))
224*760c253cSXin Li
225*760c253cSXin Li    # The base line task that set all the flags to their largest values.
226*760c253cSXin Li    parent_task = Task(flags.FlagSet(flag_set))
227*760c253cSXin Li    results.add(parent_task)
228*760c253cSXin Li
229*760c253cSXin Li    for spec in specs:
230*760c253cSXin Li        results.add(Task(flags.FlagSet(_GenerateInitialFlags(specs, spec))))
231*760c253cSXin Li
232*760c253cSXin Li    return [IterativeEliminationFirstGeneration(results, parent_task)]
233*760c253cSXin Li
234*760c253cSXin Li
235*760c253cSXin Lidef _ComputeCost(cost_func, specs, flag_set):
236*760c253cSXin Li    """Compute the mock cost of the flag_set using the input cost function.
237*760c253cSXin Li
238*760c253cSXin Li    All the boolean flags in the specs will be enabled and all the numeric flag
239*760c253cSXin Li    with have the largest legal value.
240*760c253cSXin Li
241*760c253cSXin Li    Args:
242*760c253cSXin Li      cost_func: The cost function which is used to compute the mock cost of a
243*760c253cSXin Li        dictionary of flags.
244*760c253cSXin Li      specs: All the specs that are used in the algorithm. This is used to check
245*760c253cSXin Li        whether certain flag is disabled in the flag_set dictionary.
246*760c253cSXin Li      flag_set: a dictionary of the spec and flag pairs.
247*760c253cSXin Li
248*760c253cSXin Li    Returns:
249*760c253cSXin Li      The mock cost of the input dictionary of the flags.
250*760c253cSXin Li    """
251*760c253cSXin Li
252*760c253cSXin Li    values = []
253*760c253cSXin Li
254*760c253cSXin Li    for spec in specs:
255*760c253cSXin Li        # If a flag is enabled, its value is added. Otherwise a padding 0 is added.
256*760c253cSXin Li        values.append(flag_set[spec].GetValue() if spec in flag_set else 0)
257*760c253cSXin Li
258*760c253cSXin Li    # The cost function string can use the values array.
259*760c253cSXin Li    return eval(cost_func)
260*760c253cSXin Li
261*760c253cSXin Li
262*760c253cSXin Lidef _GenerateTestFlags(num_flags, upper_bound, file_name):
263*760c253cSXin Li    """Generate a set of mock flags and write it to a configuration file.
264*760c253cSXin Li
265*760c253cSXin Li    Generate a set of mock flags
266*760c253cSXin Li
267*760c253cSXin Li    Args:
268*760c253cSXin Li      num_flags: Number of numeric flags to be generated.
269*760c253cSXin Li      upper_bound: The value of the upper bound of the range.
270*760c253cSXin Li      file_name: The configuration file name into which the mock flags are put.
271*760c253cSXin Li    """
272*760c253cSXin Li
273*760c253cSXin Li    with open(file_name, "w") as output_file:
274*760c253cSXin Li        num_flags = int(num_flags)
275*760c253cSXin Li        upper_bound = int(upper_bound)
276*760c253cSXin Li        for i in range(num_flags):
277*760c253cSXin Li            output_file.write("%s=[1-%d]\n" % (i, upper_bound))
278*760c253cSXin Li
279*760c253cSXin Li
280*760c253cSXin Lidef _TestAlgorithm(cost_func, specs, generations, best_result):
281*760c253cSXin Li    """Test the best result the algorithm should return.
282*760c253cSXin Li
283*760c253cSXin Li    Set up the framework, run the input algorithm and verify the result.
284*760c253cSXin Li
285*760c253cSXin Li    Args:
286*760c253cSXin Li      cost_func: The cost function which is used to compute the mock cost of a
287*760c253cSXin Li        dictionary of flags.
288*760c253cSXin Li      specs: All the specs that are used in the algorithm. This is used to check
289*760c253cSXin Li        whether certain flag is disabled in the flag_set dictionary.
290*760c253cSXin Li      generations: The initial generations to be evaluated.
291*760c253cSXin Li      best_result: The expected best result of the algorithm. If best_result is
292*760c253cSXin Li        -1, the algorithm may or may not return the best value. Therefore, no
293*760c253cSXin Li        assertion will be inserted.
294*760c253cSXin Li    """
295*760c253cSXin Li
296*760c253cSXin Li    # Set up the utilities to test the framework.
297*760c253cSXin Li    manager = multiprocessing.Manager()
298*760c253cSXin Li    input_queue = manager.Queue()
299*760c253cSXin Li    output_queue = manager.Queue()
300*760c253cSXin Li    pp_steer = multiprocessing.Process(
301*760c253cSXin Li        target=Steering, args=(set(), generations, output_queue, input_queue)
302*760c253cSXin Li    )
303*760c253cSXin Li    pp_steer.start()
304*760c253cSXin Li
305*760c253cSXin Li    # The best result of the algorithm so far.
306*760c253cSXin Li    result = sys.maxint
307*760c253cSXin Li
308*760c253cSXin Li    while True:
309*760c253cSXin Li        task = input_queue.get()
310*760c253cSXin Li
311*760c253cSXin Li        # POISONPILL signal the ends of the algorithm.
312*760c253cSXin Li        if task == pipeline_process.POISONPILL:
313*760c253cSXin Li            break
314*760c253cSXin Li
315*760c253cSXin Li        task.SetResult(BUILD_STAGE, (0, 0, 0, 0, 0))
316*760c253cSXin Li
317*760c253cSXin Li        # Compute the mock cost for the task.
318*760c253cSXin Li        task_result = _ComputeCost(cost_func, specs, task.GetFlags())
319*760c253cSXin Li        task.SetResult(TEST_STAGE, task_result)
320*760c253cSXin Li
321*760c253cSXin Li        # If the mock result of the current task is the best so far, set this
322*760c253cSXin Li        # result to be the best result.
323*760c253cSXin Li        if task_result < result:
324*760c253cSXin Li            result = task_result
325*760c253cSXin Li
326*760c253cSXin Li        output_queue.put(task)
327*760c253cSXin Li
328*760c253cSXin Li    pp_steer.join()
329*760c253cSXin Li
330*760c253cSXin Li    # Only do this test when best_result is not -1.
331*760c253cSXin Li    if best_result != -1:
332*760c253cSXin Li        assert best_result == result
333*760c253cSXin Li
334*760c253cSXin Li
335*760c253cSXin Liclass MockAlgorithmsTest(unittest.TestCase):
336*760c253cSXin Li    """This class mock tests different steering algorithms.
337*760c253cSXin Li
338*760c253cSXin Li    The steering algorithms are responsible for generating the next set of tasks
339*760c253cSXin Li    to run in each iteration. This class does a functional testing on the
340*760c253cSXin Li    algorithms. It mocks out the computation of the fitness function from the
341*760c253cSXin Li    build and test phases by letting the user define the fitness function.
342*760c253cSXin Li    """
343*760c253cSXin Li
344*760c253cSXin Li    def _GenerateFlagSpecifications(self):
345*760c253cSXin Li        """Generate the testing specifications."""
346*760c253cSXin Li
347*760c253cSXin Li        mock_test_file = "scale_mock_test"
348*760c253cSXin Li        _GenerateTestFlags(NUM_FLAGS, FLAG_RANGES, mock_test_file)
349*760c253cSXin Li        return flags.ReadConf(mock_test_file)
350*760c253cSXin Li
351*760c253cSXin Li    def testBestHillClimb(self):
352*760c253cSXin Li        """Test the best hill climb algorithm.
353*760c253cSXin Li
354*760c253cSXin Li        Test whether it finds the best results as expected.
355*760c253cSXin Li        """
356*760c253cSXin Li
357*760c253cSXin Li        # Initiate the build/test command and the log directory.
358*760c253cSXin Li        Task.InitLogCommand(None, None, "output")
359*760c253cSXin Li
360*760c253cSXin Li        # Generate the testing specs.
361*760c253cSXin Li        specs = self._GenerateFlagSpecifications()
362*760c253cSXin Li
363*760c253cSXin Li        # Generate the initial generations for a test whose cost function is the
364*760c253cSXin Li        # summation of the values of all the flags.
365*760c253cSXin Li        generation_tasks = _GenerateAllFlagsTasks(specs)
366*760c253cSXin Li        generations = [HillClimbingBestBranch(generation_tasks, set([]), specs)]
367*760c253cSXin Li
368*760c253cSXin Li        # Test the algorithm. The cost function is the summation of all the values
369*760c253cSXin Li        # of all the flags. Therefore, the best value is supposed to be 0, i.e.,
370*760c253cSXin Li        # when all the flags are disabled.
371*760c253cSXin Li        _TestAlgorithm("sum(values[0:len(values)])", specs, generations, 0)
372*760c253cSXin Li
373*760c253cSXin Li        # This test uses a cost function that is the negative of the previous cost
374*760c253cSXin Li        # function. Therefore, the best result should be found in task with all the
375*760c253cSXin Li        # flags enabled.
376*760c253cSXin Li        cost_function = "sys.maxint - sum(values[0:len(values)])"
377*760c253cSXin Li        all_flags = list(generation_tasks)[0].GetFlags()
378*760c253cSXin Li        cost = _ComputeCost(cost_function, specs, all_flags)
379*760c253cSXin Li
380*760c253cSXin Li        # Generate the initial generations.
381*760c253cSXin Li        generation_tasks = _GenerateNoFlagTask()
382*760c253cSXin Li        generations = [HillClimbingBestBranch(generation_tasks, set([]), specs)]
383*760c253cSXin Li
384*760c253cSXin Li        # Test the algorithm. The cost function is negative of the summation of all
385*760c253cSXin Li        # the values of all the flags. Therefore, the best value is supposed to be
386*760c253cSXin Li        # 0, i.e., when all the flags are disabled.
387*760c253cSXin Li        _TestAlgorithm(cost_function, specs, generations, cost)
388*760c253cSXin Li
389*760c253cSXin Li    def testGeneticAlgorithm(self):
390*760c253cSXin Li        """Test the Genetic Algorithm.
391*760c253cSXin Li
392*760c253cSXin Li        Do a functional testing here and see how well it scales.
393*760c253cSXin Li        """
394*760c253cSXin Li
395*760c253cSXin Li        # Initiate the build/test command and the log directory.
396*760c253cSXin Li        Task.InitLogCommand(None, None, "output")
397*760c253cSXin Li
398*760c253cSXin Li        # Generate the testing specs.
399*760c253cSXin Li        specs = self._GenerateFlagSpecifications()
400*760c253cSXin Li        # Initiate the build/test command and the log directory.
401*760c253cSXin Li        GAGeneration.InitMetaData(
402*760c253cSXin Li            STOP_THRESHOLD, NUM_CHROMOSOMES, NUM_TRIALS, specs, MUTATION_RATE
403*760c253cSXin Li        )
404*760c253cSXin Li
405*760c253cSXin Li        # Generate the initial generations.
406*760c253cSXin Li        generation_tasks = GenerateRandomGATasks(
407*760c253cSXin Li            specs, NUM_CHROMOSOMES, NUM_TRIALS
408*760c253cSXin Li        )
409*760c253cSXin Li        generations = [GAGeneration(generation_tasks, set([]), 0)]
410*760c253cSXin Li
411*760c253cSXin Li        # Test the algorithm.
412*760c253cSXin Li        _TestAlgorithm("sum(values[0:len(values)])", specs, generations, -1)
413*760c253cSXin Li        cost_func = "sys.maxint - sum(values[0:len(values)])"
414*760c253cSXin Li        _TestAlgorithm(cost_func, specs, generations, -1)
415*760c253cSXin Li
416*760c253cSXin Li    def testIterativeElimination(self):
417*760c253cSXin Li        """Test the iterative elimination algorithm.
418*760c253cSXin Li
419*760c253cSXin Li        Test whether it finds the best results as expected.
420*760c253cSXin Li        """
421*760c253cSXin Li
422*760c253cSXin Li        # Initiate the build/test command and the log directory.
423*760c253cSXin Li        Task.InitLogCommand(None, None, "output")
424*760c253cSXin Li
425*760c253cSXin Li        # Generate the testing specs.
426*760c253cSXin Li        specs = self._GenerateFlagSpecifications()
427*760c253cSXin Li
428*760c253cSXin Li        # Generate the initial generations. The generation contains the base line
429*760c253cSXin Li        # task that turns on all the flags and tasks that each turn off one of the
430*760c253cSXin Li        # flags.
431*760c253cSXin Li        generations = _GenerateAllIterativeEliminationTasks(specs)
432*760c253cSXin Li
433*760c253cSXin Li        # Test the algorithm. The cost function is the summation of all the values
434*760c253cSXin Li        # of all the flags. Therefore, the best value is supposed to be 0, i.e.,
435*760c253cSXin Li        # when all the flags are disabled.
436*760c253cSXin Li        _TestAlgorithm("sum(values[0:len(values)])", specs, generations, 0)
437*760c253cSXin Li
438*760c253cSXin Li        # This test uses a cost function that is the negative of the previous cost
439*760c253cSXin Li        # function. Therefore, the best result should be found in task with all the
440*760c253cSXin Li        # flags enabled.
441*760c253cSXin Li        all_flags_tasks = _GenerateAllFlagsTasks(specs)
442*760c253cSXin Li        cost_function = "sys.maxint - sum(values[0:len(values)])"
443*760c253cSXin Li        # Compute the cost of the task that turns on all the flags.
444*760c253cSXin Li        all_flags = list(all_flags_tasks)[0].GetFlags()
445*760c253cSXin Li        cost = _ComputeCost(cost_function, specs, all_flags)
446*760c253cSXin Li
447*760c253cSXin Li        # Test the algorithm. The cost function is negative of the summation of all
448*760c253cSXin Li        # the values of all the flags. Therefore, the best value is supposed to be
449*760c253cSXin Li        # 0, i.e., when all the flags are disabled.
450*760c253cSXin Li        # The concrete type of the generation decides how the next generation will
451*760c253cSXin Li        # be generated.
452*760c253cSXin Li        _TestAlgorithm(cost_function, specs, generations, cost)
453*760c253cSXin Li
454*760c253cSXin Li
455*760c253cSXin Liif __name__ == "__main__":
456*760c253cSXin Li    unittest.main()
457