pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / benchmark / src / java / org / apache / lucene / benchmark / byTask / utils / Config.java
1 package org.apache.lucene.benchmark.byTask.utils;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.BufferedReader;
21 import java.io.ByteArrayInputStream;
22 import java.io.IOException;
23 import java.io.Reader;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Properties;
29 import java.util.StringTokenizer;
30
31 /**
32  * Perf run configuration properties.
33  * <p/>
34  * Numeric property containing ":", e.g. "10:100:5" is interpreted
35  * as array of numeric values. It is extracted once, on first use, and
36  * maintain a round number to return the appropriate value.
37  * <p/>
38  * The config property "work.dir" tells where is the root of
39  * docs data dirs and indexes dirs. It is set to either of: <ul>
40  * <li>value supplied for it in the alg file;</li>
41  * <li>otherwise, value of System property "benchmark.work.dir";</li>
42  * <li>otherwise, "work".</li>
43  * </ul>
44  */
45 public class Config {
46
47   // For tests, if verbose is not turned on, don't print the props.
48   private static final String DEFAULT_PRINT_PROPS = System.getProperty("tests.verbose", "true");
49   private static final String NEW_LINE = System.getProperty("line.separator");
50
51   private int roundNumber = 0;
52   private Properties props;
53   private HashMap<String, Object> valByRound = new HashMap<String, Object>();
54   private HashMap<String, String> colForValByRound = new HashMap<String, String>();
55   private String algorithmText;
56
57   /**
58    * Read both algorithm and config properties.
59    *
60    * @param algReader from where to read algorithm and config properties.
61    * @throws IOException
62    */
63   public Config(Reader algReader) throws IOException {
64     // read alg file to array of lines
65     ArrayList<String> lines = new ArrayList<String>();
66     BufferedReader r = new BufferedReader(algReader);
67     int lastConfigLine = 0;
68     for (String line = r.readLine(); line != null; line = r.readLine()) {
69       lines.add(line);
70       if (line.indexOf('=') > 0) {
71         lastConfigLine = lines.size();
72       }
73     }
74     r.close();
75     // copy props lines to string
76     StringBuilder sb = new StringBuilder();
77     for (int i = 0; i < lastConfigLine; i++) {
78       sb.append(lines.get(i));
79       sb.append(NEW_LINE);
80     }
81     // read props from string
82     this.props = new Properties();
83     props.load(new ByteArrayInputStream(sb.toString().getBytes()));
84
85     // make sure work dir is set properly 
86     if (props.get("work.dir") == null) {
87       props.setProperty("work.dir", System.getProperty("benchmark.work.dir", "work"));
88     }
89
90     if (Boolean.valueOf(props.getProperty("print.props", DEFAULT_PRINT_PROPS)).booleanValue()) {
91       printProps();
92     }
93
94     // copy algorithm lines
95     sb = new StringBuilder();
96     for (int i = lastConfigLine; i < lines.size(); i++) {
97       sb.append(lines.get(i));
98       sb.append(NEW_LINE);
99     }
100     algorithmText = sb.toString();
101   }
102
103   /**
104    * Create config without algorithm - useful for a programmatic perf test.
105    * @param props - configuration properties.
106    */
107   public Config (Properties props) {
108     this.props = props;
109     if (Boolean.valueOf(props.getProperty("print.props",DEFAULT_PRINT_PROPS)).booleanValue()) {
110       printProps();
111     }
112   }
113
114   @SuppressWarnings({"unchecked", "rawtypes"})
115   private void printProps() {
116     System.out.println("------------> config properties:");
117     List<String> propKeys = new ArrayList(props.keySet());
118     Collections.sort(propKeys);
119     for (final String propName : propKeys) {
120       System.out.println(propName + " = " + props.getProperty(propName));
121     }
122     System.out.println("-------------------------------");
123   }
124
125   /**
126    * Return a string property.
127    *
128    * @param name name of property.
129    * @param dflt default value.
130    * @return a string property.
131    */
132   public String get(String name, String dflt) {
133     String vals[] = (String[]) valByRound.get(name);
134     if (vals != null) {
135       return vals[roundNumber % vals.length];
136     }
137     // done if not by round
138     String sval = props.getProperty(name, dflt);
139     if (sval == null) {
140       return null;
141     }
142     if (sval.indexOf(":") < 0) {
143       return sval;
144     } else if (sval.indexOf(":\\") >= 0 || sval.indexOf(":/") >= 0) {
145       // this previously messed up absolute path names on Windows. Assuming
146       // there is no real value that starts with \ or /
147       return sval;
148     }
149     // first time this prop is extracted by round
150     int k = sval.indexOf(":");
151     String colName = sval.substring(0, k);
152     sval = sval.substring(k + 1);
153     colForValByRound.put(name, colName);
154     vals = propToStringArray(sval);
155     valByRound.put(name, vals);
156     return vals[roundNumber % vals.length];
157   }
158
159   /**
160    * Set a property.
161    * Note: once a multiple values property is set, it can no longer be modified.
162    *
163    * @param name  name of property.
164    * @param value either single or multiple property value (multiple values are separated by ":")
165    * @throws Exception
166    */
167   public void set(String name, String value) throws Exception {
168     if (valByRound.get(name) != null) {
169       throw new Exception("Cannot modify a multi value property!");
170     }
171     props.setProperty(name, value);
172   }
173
174   /**
175    * Return an int property.
176    * If the property contain ":", e.g. "10:100:5", it is interpreted
177    * as array of ints. It is extracted once, on first call
178    * to get() it, and a by-round-value is returned.
179    *
180    * @param name name of property
181    * @param dflt default value
182    * @return a int property.
183    */
184   public int get(String name, int dflt) {
185     // use value by round if already parsed
186     int vals[] = (int[]) valByRound.get(name);
187     if (vals != null) {
188       return vals[roundNumber % vals.length];
189     }
190     // done if not by round 
191     String sval = props.getProperty(name, "" + dflt);
192     if (sval.indexOf(":") < 0) {
193       return Integer.parseInt(sval);
194     }
195     // first time this prop is extracted by round
196     int k = sval.indexOf(":");
197     String colName = sval.substring(0, k);
198     sval = sval.substring(k + 1);
199     colForValByRound.put(name, colName);
200     vals = propToIntArray(sval);
201     valByRound.put(name, vals);
202     return vals[roundNumber % vals.length];
203   }
204
205   /**
206    * Return a double property.
207    * If the property contain ":", e.g. "10:100:5", it is interpreted
208    * as array of doubles. It is extracted once, on first call
209    * to get() it, and a by-round-value is returned.
210    *
211    * @param name name of property
212    * @param dflt default value
213    * @return a double property.
214    */
215   public double get(String name, double dflt) {
216     // use value by round if already parsed
217     double vals[] = (double[]) valByRound.get(name);
218     if (vals != null) {
219       return vals[roundNumber % vals.length];
220     }
221     // done if not by round 
222     String sval = props.getProperty(name, "" + dflt);
223     if (sval.indexOf(":") < 0) {
224       return Double.parseDouble(sval);
225     }
226     // first time this prop is extracted by round
227     int k = sval.indexOf(":");
228     String colName = sval.substring(0, k);
229     sval = sval.substring(k + 1);
230     colForValByRound.put(name, colName);
231     vals = propToDoubleArray(sval);
232     valByRound.put(name, vals);
233     return vals[roundNumber % vals.length];
234   }
235
236   /**
237    * Return a boolean property.
238    * If the property contain ":", e.g. "true.true.false", it is interpreted
239    * as array of booleans. It is extracted once, on first call
240    * to get() it, and a by-round-value is returned.
241    *
242    * @param name name of property
243    * @param dflt default value
244    * @return a int property.
245    */
246   public boolean get(String name, boolean dflt) {
247     // use value by round if already parsed
248     boolean vals[] = (boolean[]) valByRound.get(name);
249     if (vals != null) {
250       return vals[roundNumber % vals.length];
251     }
252     // done if not by round 
253     String sval = props.getProperty(name, "" + dflt);
254     if (sval.indexOf(":") < 0) {
255       return Boolean.valueOf(sval).booleanValue();
256     }
257     // first time this prop is extracted by round 
258     int k = sval.indexOf(":");
259     String colName = sval.substring(0, k);
260     sval = sval.substring(k + 1);
261     colForValByRound.put(name, colName);
262     vals = propToBooleanArray(sval);
263     valByRound.put(name, vals);
264     return vals[roundNumber % vals.length];
265   }
266
267   /**
268    * Increment the round number, for config values that are extracted by round number.
269    *
270    * @return the new round number.
271    */
272   public int newRound() {
273     roundNumber++;
274
275     StringBuilder sb = new StringBuilder("--> Round ").append(roundNumber - 1).append("-->").append(roundNumber);
276
277     // log changes in values
278     if (valByRound.size() > 0) {
279       sb.append(": ");
280       for (final String name : valByRound.keySet()) {
281         Object a = valByRound.get(name);
282         if (a instanceof int[]) {
283           int ai[] = (int[]) a;
284           int n1 = (roundNumber - 1) % ai.length;
285           int n2 = roundNumber % ai.length;
286           sb.append("  ").append(name).append(":").append(ai[n1]).append("-->").append(ai[n2]);
287         } else if (a instanceof double[]) {
288           double ad[] = (double[]) a;
289           int n1 = (roundNumber - 1) % ad.length;
290           int n2 = roundNumber % ad.length;
291           sb.append("  ").append(name).append(":").append(ad[n1]).append("-->").append(ad[n2]);
292         } else if (a instanceof String[]) {
293           String ad[] = (String[]) a;
294           int n1 = (roundNumber - 1) % ad.length;
295           int n2 = roundNumber % ad.length;
296           sb.append("  ").append(name).append(":").append(ad[n1]).append("-->").append(ad[n2]);
297         } else {
298           boolean ab[] = (boolean[]) a;
299           int n1 = (roundNumber - 1) % ab.length;
300           int n2 = roundNumber % ab.length;
301           sb.append("  ").append(name).append(":").append(ab[n1]).append("-->").append(ab[n2]);
302         }
303       }
304     }
305
306     System.out.println();
307     System.out.println(sb.toString());
308     System.out.println();
309
310     return roundNumber;
311   }
312
313   private String[] propToStringArray(String s) {
314     if (s.indexOf(":") < 0) {
315       return new String[]{s};
316     }
317
318     ArrayList<String> a = new ArrayList<String>();
319     StringTokenizer st = new StringTokenizer(s, ":");
320     while (st.hasMoreTokens()) {
321       String t = st.nextToken();
322       a.add(t);
323     }
324     return a.toArray(new String[a.size()]);
325   }
326
327   // extract properties to array, e.g. for "10:100:5" return int[]{10,100,5}. 
328   private int[] propToIntArray(String s) {
329     if (s.indexOf(":") < 0) {
330       return new int[]{Integer.parseInt(s)};
331     }
332
333     ArrayList<Integer> a = new ArrayList<Integer>();
334     StringTokenizer st = new StringTokenizer(s, ":");
335     while (st.hasMoreTokens()) {
336       String t = st.nextToken();
337       a.add(Integer.valueOf(t));
338     }
339     int res[] = new int[a.size()];
340     for (int i = 0; i < a.size(); i++) {
341       res[i] = a.get(i).intValue();
342     }
343     return res;
344   }
345
346   // extract properties to array, e.g. for "10.7:100.4:-2.3" return int[]{10.7,100.4,-2.3}. 
347   private double[] propToDoubleArray(String s) {
348     if (s.indexOf(":") < 0) {
349       return new double[]{Double.parseDouble(s)};
350     }
351
352     ArrayList<Double> a = new ArrayList<Double>();
353     StringTokenizer st = new StringTokenizer(s, ":");
354     while (st.hasMoreTokens()) {
355       String t = st.nextToken();
356       a.add(Double.valueOf(t));
357     }
358     double res[] = new double[a.size()];
359     for (int i = 0; i < a.size(); i++) {
360       res[i] = a.get(i).doubleValue();
361     }
362     return res;
363   }
364
365   // extract properties to array, e.g. for "true:true:false" return boolean[]{true,false,false}. 
366   private boolean[] propToBooleanArray(String s) {
367     if (s.indexOf(":") < 0) {
368       return new boolean[]{Boolean.valueOf(s).booleanValue()};
369     }
370
371     ArrayList<Boolean> a = new ArrayList<Boolean>();
372     StringTokenizer st = new StringTokenizer(s, ":");
373     while (st.hasMoreTokens()) {
374       String t = st.nextToken();
375       a.add(new Boolean(t));
376     }
377     boolean res[] = new boolean[a.size()];
378     for (int i = 0; i < a.size(); i++) {
379       res[i] = a.get(i).booleanValue();
380     }
381     return res;
382   }
383
384   /**
385    * @return names of params set by round, for reports title
386    */
387   public String getColsNamesForValsByRound() {
388     if (colForValByRound.size() == 0) {
389       return "";
390     }
391     StringBuilder sb = new StringBuilder();
392     for (final String name : colForValByRound.keySet()) {
393       String colName = colForValByRound.get(name);
394       sb.append(" ").append(colName);
395     }
396     return sb.toString();
397   }
398
399   /**
400    * @return values of params set by round, for reports lines.
401    */
402   public String getColsValuesForValsByRound(int roundNum) {
403     if (colForValByRound.size() == 0) {
404       return "";
405     }
406     StringBuilder sb = new StringBuilder();
407     for (final String name : colForValByRound.keySet()) {
408       String colName = colForValByRound.get(name);
409       String template = " " + colName;
410       if (roundNum < 0) {
411         // just append blanks
412         sb.append(Format.formatPaddLeft("-", template));
413       } else {
414         // append actual values, for that round
415         Object a = valByRound.get(name);
416         if (a instanceof int[]) {
417           int ai[] = (int[]) a;
418           int n = roundNum % ai.length;
419           sb.append(Format.format(ai[n], template));
420         } else if (a instanceof double[]) {
421           double ad[] = (double[]) a;
422           int n = roundNum % ad.length;
423           sb.append(Format.format(2, ad[n], template));
424         } else if (a instanceof String[]) {
425           String ad[] = (String[]) a;
426           int n = roundNum % ad.length;
427           sb.append(ad[n]);
428         } else {
429           boolean ab[] = (boolean[]) a;
430           int n = roundNum % ab.length;
431           sb.append(Format.formatPaddLeft("" + ab[n], template));
432         }
433       }
434     }
435     return sb.toString();
436   }
437
438   /**
439    * @return the round number.
440    */
441   public int getRoundNumber() {
442     return roundNumber;
443   }
444
445   /**
446    * @return Returns the algorithmText.
447    */
448   public String getAlgorithmText() {
449     return algorithmText;
450   }
451
452 }