171 lines
5.4 KiB
Python
171 lines
5.4 KiB
Python
# 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.
|
|
"""Steering stage unittest.
|
|
|
|
Part of the Chrome build flags optimization.
|
|
"""
|
|
|
|
__author__ = 'yuhenglong@google.com (Yuheng Long)'
|
|
|
|
import multiprocessing
|
|
import unittest
|
|
|
|
from generation import Generation
|
|
from mock_task import IdentifierMockTask
|
|
import pipeline_process
|
|
import steering
|
|
|
|
# Pick an integer at random.
|
|
STEERING_TEST_STAGE = -8
|
|
|
|
# The number of generations to be used to do the testing.
|
|
NUMBER_OF_GENERATIONS = 20
|
|
|
|
# The number of tasks to be put in each generation to be tested.
|
|
NUMBER_OF_TASKS = 20
|
|
|
|
# The stride of permutation used to shuffle the input list of tasks. Should be
|
|
# relatively prime with NUMBER_OF_TASKS.
|
|
STRIDE = 7
|
|
|
|
|
|
class MockGeneration(Generation):
|
|
"""This class emulates an actual generation.
|
|
|
|
It will output the next_generations when the method Next is called. The
|
|
next_generations is initiated when the MockGeneration instance is constructed.
|
|
"""
|
|
|
|
def __init__(self, tasks, next_generations):
|
|
"""Set up the next generations for this task.
|
|
|
|
Args:
|
|
tasks: A set of tasks to be run.
|
|
next_generations: A list of generations as the next generation of the
|
|
current generation.
|
|
"""
|
|
Generation.__init__(self, tasks, None)
|
|
self._next_generations = next_generations
|
|
|
|
def Next(self, _):
|
|
return self._next_generations
|
|
|
|
def IsImproved(self):
|
|
if self._next_generations:
|
|
return True
|
|
return False
|
|
|
|
|
|
class SteeringTest(unittest.TestCase):
|
|
"""This class test the steering method.
|
|
|
|
The steering algorithm should return if there is no new task in the initial
|
|
generation. The steering algorithm should send all the tasks to the next stage
|
|
and should terminate once there is no pending generation. A generation is
|
|
pending if it contains pending task. A task is pending if its (test) result
|
|
is not ready.
|
|
"""
|
|
|
|
def testSteering(self):
|
|
"""Test that the steering algorithm processes all the tasks properly.
|
|
|
|
Test that the steering algorithm sends all the tasks to the next stage. Test
|
|
that the steering algorithm terminates once all the tasks have been
|
|
processed, i.e., the results for the tasks are all ready.
|
|
"""
|
|
|
|
# A list of generations used to test the steering stage.
|
|
generations = []
|
|
|
|
task_index = 0
|
|
previous_generations = None
|
|
|
|
# Generate a sequence of generations to be tested. Each generation will
|
|
# output the next generation in reverse order of the list when the "Next"
|
|
# method is called.
|
|
for _ in range(NUMBER_OF_GENERATIONS):
|
|
# Use a consecutive sequence of numbers as identifiers for the set of
|
|
# tasks put into a generation.
|
|
test_ranges = range(task_index, task_index + NUMBER_OF_TASKS)
|
|
tasks = [IdentifierMockTask(STEERING_TEST_STAGE, t) for t in test_ranges]
|
|
steering_tasks = set(tasks)
|
|
|
|
# Let the previous generation as the offspring generation of the current
|
|
# generation.
|
|
current_generation = MockGeneration(steering_tasks, previous_generations)
|
|
generations.insert(0, current_generation)
|
|
previous_generations = [current_generation]
|
|
|
|
task_index += NUMBER_OF_TASKS
|
|
|
|
# If there is no generation at all, the unittest returns right away.
|
|
if not current_generation:
|
|
return
|
|
|
|
# Set up the input and result queue for the steering method.
|
|
manager = multiprocessing.Manager()
|
|
input_queue = manager.Queue()
|
|
result_queue = manager.Queue()
|
|
|
|
steering_process = multiprocessing.Process(
|
|
target=steering.Steering,
|
|
args=(set(), [current_generation], input_queue, result_queue))
|
|
steering_process.start()
|
|
|
|
# Test that each generation is processed properly. I.e., the generations are
|
|
# processed in order.
|
|
while generations:
|
|
generation = generations.pop(0)
|
|
tasks = [task for task in generation.Pool()]
|
|
|
|
# Test that all the tasks are processed once and only once.
|
|
while tasks:
|
|
task = result_queue.get()
|
|
|
|
assert task in tasks
|
|
tasks.remove(task)
|
|
|
|
input_queue.put(task)
|
|
|
|
task = result_queue.get()
|
|
|
|
# Test that the steering algorithm returns properly after processing all
|
|
# the generations.
|
|
assert task == pipeline_process.POISONPILL
|
|
|
|
steering_process.join()
|
|
|
|
def testCache(self):
|
|
"""The steering algorithm returns immediately if there is no new tasks.
|
|
|
|
If all the new tasks have been cached before, the steering algorithm does
|
|
not have to execute these tasks again and thus can terminate right away.
|
|
"""
|
|
|
|
# Put a set of tasks in the cache and add this set to initial generation.
|
|
test_ranges = range(NUMBER_OF_TASKS)
|
|
tasks = [IdentifierMockTask(STEERING_TEST_STAGE, t) for t in test_ranges]
|
|
steering_tasks = set(tasks)
|
|
|
|
current_generation = MockGeneration(steering_tasks, None)
|
|
|
|
# Set up the input and result queue for the steering method.
|
|
manager = multiprocessing.Manager()
|
|
input_queue = manager.Queue()
|
|
result_queue = manager.Queue()
|
|
|
|
steering_process = multiprocessing.Process(
|
|
target=steering.Steering,
|
|
args=(steering_tasks, [current_generation], input_queue, result_queue))
|
|
|
|
steering_process.start()
|
|
|
|
# Test that the steering method returns right away.
|
|
assert result_queue.get() == pipeline_process.POISONPILL
|
|
steering_process.join()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
unittest.main()
|