You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
177 lines
6.2 KiB
177 lines
6.2 KiB
# 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. |
|
"""Iterative flags elimination. |
|
|
|
Part of the Chrome build flags optimization. |
|
|
|
This module implements the flag iterative elimination algorithm (IE) adopted |
|
from the paper |
|
Z. Pan et al. Fast and Effective Orchestration of Compiler Optimizations for |
|
Automatic Performance Tuning. |
|
|
|
IE begins with the base line that turns on all the optimizations flags and |
|
setting the numeric flags to their highest values. IE turns off the one boolean |
|
flag or lower the value of a numeric flag with the most negative effect from the |
|
baseline. This process repeats with all remaining flags, until none of them |
|
causes performance degradation. The complexity of IE is O(n^2). |
|
|
|
For example, -fstrict-aliasing and -ftree-vectorize. The base line is |
|
b=[-fstrict-aliasing, -ftree-vectorize]. The two tasks in the first iteration |
|
are t0=[-fstrict-aliasing] and t1=[-ftree-vectorize]. The algorithm compares b |
|
with t0 and t1, respectively, and see whether setting the numeric flag with a |
|
lower value or removing the boolean flag -fstrict-aliasing produce a better |
|
fitness value. |
|
""" |
|
|
|
__author__ = 'yuhenglong@google.com (Yuheng Long)' |
|
|
|
import flags |
|
from generation import Generation |
|
import task |
|
|
|
|
|
def _DecreaseFlag(flags_dict, spec): |
|
"""Decrease the value of the flag that has the specification spec. |
|
|
|
If the flag that contains the spec is a boolean flag, it is eliminated. |
|
Otherwise the flag is a numeric flag, its value will be reduced by one. |
|
|
|
Args: |
|
flags_dict: The dictionary containing the original flags whose neighbors are |
|
to be explored. |
|
spec: The spec in the flags_dict is to be changed. |
|
|
|
Returns: |
|
Dictionary of neighbor flag that is only different from the original |
|
dictionary by the spec. |
|
""" |
|
|
|
# The specification must be held by one of the flags. |
|
assert spec in flags_dict |
|
|
|
# The results this method returns. |
|
results = flags_dict.copy() |
|
|
|
# This method searches for a pattern [start-end] in the spec. If the spec |
|
# contains this pattern, it is a numeric flag. Otherwise it is a boolean flag. |
|
# For example, -finline-limit=[1-1000] is a numeric flag and -falign-jumps is |
|
# a boolean flag. |
|
numeric_flag_match = flags.Search(spec) |
|
|
|
if numeric_flag_match: |
|
# numeric flag |
|
val = results[spec].GetValue() |
|
|
|
# If the value of the flag is the lower boundary of the specification, this |
|
# flag will be turned off. Because it already contains the lowest value and |
|
# can not be decreased any more. |
|
if val == int(numeric_flag_match.group('start')): |
|
# Turn off the flag. A flag is turned off if it is not presented in the |
|
# flags_dict. |
|
del results[spec] |
|
else: |
|
results[spec] = flags.Flag(spec, val - 1) |
|
else: |
|
# Turn off the flag. A flag is turned off if it is not presented in the |
|
# flags_dict. |
|
del results[spec] |
|
|
|
return results |
|
|
|
|
|
class IterativeEliminationGeneration(Generation): |
|
"""The negative flag iterative elimination algorithm.""" |
|
|
|
def __init__(self, exe_set, parent_task): |
|
"""Set up the base line parent task. |
|
|
|
The parent task is the base line against which the new tasks are compared. |
|
The new tasks are only different from the base line from one flag f by |
|
either turning this flag f off, or lower the flag value by 1. |
|
If a new task is better than the base line, one flag is identified that |
|
gives degradation. The flag that give the worst degradation will be removed |
|
or lower the value by 1 in the base in each iteration. |
|
|
|
Args: |
|
exe_set: A set of tasks to be run. Each one only differs from the |
|
parent_task by one flag. |
|
parent_task: The base line task, against which the new tasks in exe_set |
|
are compared. |
|
""" |
|
|
|
Generation.__init__(self, exe_set, None) |
|
self._parent_task = parent_task |
|
|
|
def IsImproved(self): |
|
"""Whether any new task has improvement upon the parent task.""" |
|
|
|
parent = self._parent_task |
|
# Whether there is any new task that has improvement over the parent base |
|
# line task. |
|
for curr in [curr for curr in self.Pool() if curr != parent]: |
|
if curr.IsImproved(parent): |
|
return True |
|
|
|
return False |
|
|
|
def Next(self, cache): |
|
"""Find out the flag that gives the worst degradation. |
|
|
|
Found out the flag that gives the worst degradation. Turn that flag off from |
|
the base line and use the new base line for the new generation. |
|
|
|
Args: |
|
cache: A set of tasks that have been generated before. |
|
|
|
Returns: |
|
A set of new generations. |
|
""" |
|
parent_task = self._parent_task |
|
|
|
# Find out the task that gives the worst degradation. |
|
worst_task = parent_task |
|
|
|
for curr in [curr for curr in self.Pool() if curr != parent_task]: |
|
# The method IsImproved, which is supposed to be called before, ensures |
|
# that there is at least a task that improves upon the parent_task. |
|
if curr.IsImproved(worst_task): |
|
worst_task = curr |
|
|
|
assert worst_task != parent_task |
|
|
|
# The flags_set of the worst task. |
|
work_flags_set = worst_task.GetFlags().GetFlags() |
|
|
|
results = set([]) |
|
|
|
# If the flags_set contains no flag, i.e., all the flags have been |
|
# eliminated, the algorithm stops. |
|
if not work_flags_set: |
|
return [] |
|
|
|
# Turn of the remaining flags one by one for the next generation. |
|
for spec in work_flags_set: |
|
flag_set = flags.FlagSet(_DecreaseFlag(work_flags_set, spec).values()) |
|
new_task = task.Task(flag_set) |
|
if new_task not in cache: |
|
results.add(new_task) |
|
|
|
return [IterativeEliminationGeneration(results, worst_task)] |
|
|
|
|
|
class IterativeEliminationFirstGeneration(IterativeEliminationGeneration): |
|
"""The first iteration of the iterative elimination algorithm. |
|
|
|
The first iteration also evaluates the base line task. The base line tasks in |
|
the subsequent iterations have been evaluated. Therefore, |
|
IterativeEliminationGeneration does not include the base line task in the |
|
execution set. |
|
""" |
|
|
|
def IsImproved(self): |
|
# Find out the base line task in the execution set. |
|
parent = next(task for task in self.Pool() if task == self._parent_task) |
|
self._parent_task = parent |
|
|
|
return IterativeEliminationGeneration.IsImproved(self)
|
|
|