Home | History | Annotate | Download | only in cf
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.dx.dex.cf;
     18 
     19 import com.android.dx.rop.code.RopMethod;
     20 import com.android.dx.rop.code.TranslationAdvice;
     21 import com.android.dx.ssa.Optimizer;
     22 import java.io.BufferedReader;
     23 import java.io.FileReader;
     24 import java.io.IOException;
     25 import java.util.EnumSet;
     26 import java.util.HashSet;
     27 
     28 /**
     29  * Settings for optimization of code.
     30  */
     31 public class OptimizerOptions {
     32     /**
     33      * {@code null-ok;} hash set of class name + method names that
     34      * should be optimized. {@code null} if this constraint was not
     35      * specified on the command line
     36      */
     37     private static HashSet<String> optimizeList;
     38 
     39     /**
     40      * {@code null-ok;} hash set of class name + method names that should NOT
     41      * be optimized.  null if this constraint was not specified on the
     42      * command line
     43      */
     44     private static HashSet<String> dontOptimizeList;
     45 
     46     /** true if the above lists have been loaded */
     47     private static boolean optimizeListsLoaded;
     48 
     49     /**
     50      * This class is uninstantiable.
     51      */
     52     private OptimizerOptions() {
     53         // This space intentionally left blank.
     54     }
     55 
     56     /**
     57      * Loads the optimize/don't optimize lists from files.
     58      *
     59      * @param optimizeListFile Pathname
     60      * @param dontOptimizeListFile Pathname
     61      */
     62     public static void loadOptimizeLists(String optimizeListFile,
     63             String dontOptimizeListFile) {
     64         if (optimizeListsLoaded) {
     65             return;
     66         }
     67 
     68         if (optimizeListFile != null && dontOptimizeListFile != null) {
     69             /*
     70              * We shouldn't get this far. The condition should have
     71              * been caught in the arg processor.
     72              */
     73             throw new RuntimeException("optimize and don't optimize lists "
     74                     + " are mutually exclusive.");
     75         }
     76 
     77         if (optimizeListFile != null) {
     78             optimizeList = loadStringsFromFile(optimizeListFile);
     79         }
     80 
     81         if (dontOptimizeListFile != null) {
     82             dontOptimizeList = loadStringsFromFile(dontOptimizeListFile);
     83         }
     84 
     85         optimizeListsLoaded = true;
     86     }
     87 
     88     /**
     89      * Loads a list of newline-separated strings into a new HashSet and returns
     90      * the HashSet.
     91      *
     92      * @param filename filename to process
     93      * @return set of all unique lines in the file
     94      */
     95     private static HashSet<String> loadStringsFromFile(String filename) {
     96         HashSet<String> result = new HashSet<String>();
     97 
     98         try {
     99             FileReader fr = new FileReader(filename);
    100             BufferedReader bfr = new BufferedReader(fr);
    101 
    102             String line;
    103 
    104             while (null != (line = bfr.readLine())) {
    105                 result.add(line);
    106             }
    107 
    108             fr.close();
    109         } catch (IOException ex) {
    110             // Let the exception percolate up as a RuntimeException.
    111             throw new RuntimeException("Error with optimize list: " +
    112                     filename, ex);
    113         }
    114 
    115         return result;
    116     }
    117 
    118     /**
    119      * Compares the output of the optimizer run normally with a run skipping
    120      * some optional steps. Results are printed to stderr.
    121      *
    122      * @param nonOptRmeth {@code non-null;} origional rop method
    123      * @param paramSize {@code >= 0;} parameter size of method
    124      * @param isStatic true if this method has no 'this' pointer argument.
    125      * @param args {@code non-null;} translator arguments
    126      * @param advice {@code non-null;} translation advice
    127      * @param rmeth {@code non-null;} method with all optimization steps run.
    128      */
    129     public static void compareOptimizerStep(RopMethod nonOptRmeth,
    130             int paramSize, boolean isStatic, CfOptions args,
    131             TranslationAdvice advice, RopMethod rmeth) {
    132         EnumSet<Optimizer.OptionalStep> steps;
    133 
    134         steps = EnumSet.allOf(Optimizer.OptionalStep.class);
    135 
    136         // This is the step to skip.
    137         steps.remove(Optimizer.OptionalStep.CONST_COLLECTOR);
    138 
    139         RopMethod skipRopMethod
    140                 = Optimizer.optimize(nonOptRmeth,
    141                         paramSize, isStatic, args.localInfo, advice, steps);
    142 
    143         int normalInsns
    144                 = rmeth.getBlocks().getEffectiveInstructionCount();
    145         int skipInsns
    146                 = skipRopMethod.getBlocks().getEffectiveInstructionCount();
    147 
    148         System.err.printf(
    149                 "optimize step regs:(%d/%d/%.2f%%)"
    150                 + " insns:(%d/%d/%.2f%%)\n",
    151                 rmeth.getBlocks().getRegCount(),
    152                 skipRopMethod.getBlocks().getRegCount(),
    153                 100.0 * ((skipRopMethod.getBlocks().getRegCount()
    154                         - rmeth.getBlocks().getRegCount())
    155                         / (float) skipRopMethod.getBlocks().getRegCount()),
    156                 normalInsns, skipInsns,
    157                 100.0 * ((skipInsns - normalInsns) / (float) skipInsns));
    158     }
    159 
    160     /**
    161      * Checks whether the specified method should be optimized
    162      *
    163      * @param canonicalMethodName name of method being considered
    164      * @return true if it should be optimized
    165      */
    166     public static boolean shouldOptimize(String canonicalMethodName) {
    167         // Optimize only what's in the optimize list.
    168         if (optimizeList != null) {
    169             return optimizeList.contains(canonicalMethodName);
    170         }
    171 
    172         /*
    173          * Or don't optimize what's listed here. (The two lists are
    174          * mutually exclusive.
    175          */
    176 
    177         if (dontOptimizeList != null) {
    178             return !dontOptimizeList.contains(canonicalMethodName);
    179         }
    180 
    181         // If neither list has been specified, then optimize everything.
    182         return true;
    183     }
    184 }
    185