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 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 HashSet<String> dontOptimizeList;
45 
46     /** true if the above lists have been loaded */
47     private boolean optimizeListsLoaded;
48 
49 
50     /**
51      * Loads the optimize/don't optimize lists from files.
52      *
53      * @param optimizeListFile Pathname
54      * @param dontOptimizeListFile Pathname
55      */
loadOptimizeLists(String optimizeListFile, String dontOptimizeListFile)56     public void loadOptimizeLists(String optimizeListFile,
57             String dontOptimizeListFile) {
58         if (optimizeListsLoaded) {
59             return;
60         }
61 
62         if (optimizeListFile != null && dontOptimizeListFile != null) {
63             /*
64              * We shouldn't get this far. The condition should have
65              * been caught in the arg processor.
66              */
67             throw new RuntimeException("optimize and don't optimize lists "
68                     + " are mutually exclusive.");
69         }
70 
71         if (optimizeListFile != null) {
72             optimizeList = loadStringsFromFile(optimizeListFile);
73         }
74 
75         if (dontOptimizeListFile != null) {
76             dontOptimizeList = loadStringsFromFile(dontOptimizeListFile);
77         }
78 
79         optimizeListsLoaded = true;
80     }
81 
82     /**
83      * Loads a list of newline-separated strings into a new HashSet and returns
84      * the HashSet.
85      *
86      * @param filename filename to process
87      * @return set of all unique lines in the file
88      */
loadStringsFromFile(String filename)89     private static HashSet<String> loadStringsFromFile(String filename) {
90         HashSet<String> result = new HashSet<String>();
91 
92         try {
93             FileReader fr = new FileReader(filename);
94             BufferedReader bfr = new BufferedReader(fr);
95 
96             String line;
97 
98             while (null != (line = bfr.readLine())) {
99                 result.add(line);
100             }
101 
102             fr.close();
103         } catch (IOException ex) {
104             // Let the exception percolate up as a RuntimeException.
105             throw new RuntimeException("Error with optimize list: " +
106                     filename, ex);
107         }
108 
109         return result;
110     }
111 
112     /**
113      * Compares the output of the optimizer run normally with a run skipping
114      * some optional steps. Results are printed to stderr.
115      *
116      * @param nonOptRmeth {@code non-null;} origional rop method
117      * @param paramSize {@code >= 0;} parameter size of method
118      * @param isStatic true if this method has no 'this' pointer argument.
119      * @param args {@code non-null;} translator arguments
120      * @param advice {@code non-null;} translation advice
121      * @param rmeth {@code non-null;} method with all optimization steps run.
122      */
compareOptimizerStep(RopMethod nonOptRmeth, int paramSize, boolean isStatic, CfOptions args, TranslationAdvice advice, RopMethod rmeth)123     public void compareOptimizerStep(RopMethod nonOptRmeth,
124             int paramSize, boolean isStatic, CfOptions args,
125             TranslationAdvice advice, RopMethod rmeth) {
126         EnumSet<Optimizer.OptionalStep> steps;
127 
128         steps = EnumSet.allOf(Optimizer.OptionalStep.class);
129 
130         // This is the step to skip.
131         steps.remove(Optimizer.OptionalStep.CONST_COLLECTOR);
132 
133         RopMethod skipRopMethod
134                 = Optimizer.optimize(nonOptRmeth,
135                         paramSize, isStatic, args.localInfo, advice, steps);
136 
137         int normalInsns
138                 = rmeth.getBlocks().getEffectiveInstructionCount();
139         int skipInsns
140                 = skipRopMethod.getBlocks().getEffectiveInstructionCount();
141 
142         System.err.printf(
143                 "optimize step regs:(%d/%d/%.2f%%)"
144                 + " insns:(%d/%d/%.2f%%)\n",
145                 rmeth.getBlocks().getRegCount(),
146                 skipRopMethod.getBlocks().getRegCount(),
147                 100.0 * ((skipRopMethod.getBlocks().getRegCount()
148                         - rmeth.getBlocks().getRegCount())
149                         / (float) skipRopMethod.getBlocks().getRegCount()),
150                 normalInsns, skipInsns,
151                 100.0 * ((skipInsns - normalInsns) / (float) skipInsns));
152     }
153 
154     /**
155      * Checks whether the specified method should be optimized
156      *
157      * @param canonicalMethodName name of method being considered
158      * @return true if it should be optimized
159      */
shouldOptimize(String canonicalMethodName)160     public boolean shouldOptimize(String canonicalMethodName) {
161         // Optimize only what's in the optimize list.
162         if (optimizeList != null) {
163             return optimizeList.contains(canonicalMethodName);
164         }
165 
166         /*
167          * Or don't optimize what's listed here. (The two lists are
168          * mutually exclusive.
169          */
170 
171         if (dontOptimizeList != null) {
172             return !dontOptimizeList.contains(canonicalMethodName);
173         }
174 
175         // If neither list has been specified, then optimize everything.
176         return true;
177     }
178 }
179