001: package org.apache.lucene.benchmark.byTask.utils;
002:
003: /**
004: * Licensed to the Apache Software Foundation (ASF) under one or more
005: * contributor license agreements. See the NOTICE file distributed with
006: * this work for additional information regarding copyright ownership.
007: * The ASF licenses this file to You under the Apache License, Version 2.0
008: * (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: *
011: * http://www.apache.org/licenses/LICENSE-2.0
012: *
013: * Unless required by applicable law or agreed to in writing, software
014: * distributed under the License is distributed on an "AS IS" BASIS,
015: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016: * See the License for the specific language governing permissions and
017: * limitations under the License.
018: */
019:
020: import java.io.BufferedReader;
021: import java.io.ByteArrayInputStream;
022: import java.io.IOException;
023: import java.io.Reader;
024: import java.util.ArrayList;
025: import java.util.List;
026: import java.util.Collections;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.Properties;
030: import java.util.StringTokenizer;
031:
032: /**
033: * Perf run configuration properties.
034: * <p>
035: * Numeric peroperty containing ":", e.g. "10:100:5" is interpreted
036: * as array of numeric values. It is extracted once, on first use, and
037: * maintain a round number to return the appropriate value.
038: * <p>
039: * The config property "work.dir" tells where is the root of
040: * docs data dirs and indexes dirs. It is set to either of: <ul>
041: * <li>value supplied for it in the alg file;</li>
042: * <li>otherwise, value of System property "benchmark.work.dir";</li>
043: * <li>otherwise, "work".</li>
044: * </ul>
045: */
046: public class Config {
047:
048: private static final String NEW_LINE = System
049: .getProperty("line.separator");
050:
051: private int roundNumber = 0;
052: private Properties props;
053: private HashMap valByRound = new HashMap();
054: private HashMap colForValByRound = new HashMap();
055: private String algorithmText;
056:
057: /**
058: * Read both algorithm and config properties.
059: * @param algReader from where to read algorithm and config properties.
060: * @throws IOException
061: */
062: public Config(Reader algReader) throws IOException {
063: // read alg file to array of lines
064: ArrayList lines = new ArrayList();
065: BufferedReader r = new BufferedReader(algReader);
066: int lastConfigLine = 0;
067: for (String line = r.readLine(); line != null; line = r
068: .readLine()) {
069: lines.add(line);
070: if (line.indexOf('=') > 0) {
071: lastConfigLine = lines.size();
072: }
073: }
074: r.close();
075: // copy props lines to string
076: StringBuffer sb = new StringBuffer();
077: for (int i = 0; i < lastConfigLine; i++) {
078: sb.append(lines.get(i));
079: sb.append(NEW_LINE);
080: }
081: // read props from string
082: this .props = new Properties();
083: props.load(new ByteArrayInputStream(sb.toString().getBytes()));
084:
085: // make sure work dir is set properly
086: if (props.get("work.dir") == null) {
087: props.setProperty("work.dir", System.getProperty(
088: "benchmark.work.dir", "work"));
089: }
090:
091: if (Boolean.valueOf(props.getProperty("print.props", "true"))
092: .booleanValue()) {
093: printProps();
094: }
095:
096: // copy algorithm lines
097: sb = new StringBuffer();
098: for (int i = lastConfigLine; i < lines.size(); i++) {
099: sb.append(lines.get(i));
100: sb.append(NEW_LINE);
101: }
102: algorithmText = sb.toString();
103: }
104:
105: /**
106: * Create config without algorithm - usefull for a programmatic perf test.
107: * @param props - configuration properties.
108: * @throws IOException
109: */
110: public Config(Properties props) {
111: this .props = props;
112: if (Boolean.valueOf(props.getProperty("print.props", "true"))
113: .booleanValue()) {
114: printProps();
115: }
116: }
117:
118: private void printProps() {
119: System.out.println("------------> config properties:");
120: List propKeys = new ArrayList(props.keySet());
121: Collections.sort(propKeys);
122: for (Iterator it = propKeys.iterator(); it.hasNext();) {
123: String propName = (String) it.next();
124: System.out.println(propName + " = "
125: + props.getProperty(propName));
126: }
127: System.out.println("-------------------------------");
128: }
129:
130: /**
131: * Return a string property.
132: * @param name name of property.
133: * @param dflt default value.
134: * @return a string property.
135: */
136: public String get(String name, String dflt) {
137: return props.getProperty(name, dflt);
138: }
139:
140: /**
141: * Set a property.
142: * Note: once a multiple values property is set, it can no longer be modified.
143: * @param name name of property.
144: * @param value either single or multiple propery value (multple values are separated by ":")
145: * @throws Exception
146: */
147: public void set(String name, String value) throws Exception {
148: if (valByRound.get(name) != null) {
149: throw new Exception("Cannot modify a multi value property!");
150: }
151: props.setProperty(name, value);
152: }
153:
154: /**
155: * Return an int property.
156: * If the property contain ":", e.g. "10:100:5", it is interpreted
157: * as array of ints. It is extracted once, on first call
158: * to get() it, and a by-round-value is returned.
159: * @param name name of property
160: * @param dflt default value
161: * @return a int property.
162: */
163: public int get(String name, int dflt) {
164: // use value by round if already parsed
165: int vals[] = (int[]) valByRound.get(name);
166: if (vals != null) {
167: return vals[roundNumber % vals.length];
168: }
169: // done if not by round
170: String sval = props.getProperty(name, "" + dflt);
171: if (sval.indexOf(":") < 0) {
172: return Integer.parseInt(sval);
173: }
174: // first time this prop is extracted by round
175: int k = sval.indexOf(":");
176: String colName = sval.substring(0, k);
177: sval = sval.substring(k + 1);
178: colForValByRound.put(name, colName);
179: vals = propToIntArray(sval);
180: valByRound.put(name, vals);
181: return vals[roundNumber % vals.length];
182: }
183:
184: /**
185: * Return a double property.
186: * If the property contain ":", e.g. "10:100:5", it is interpreted
187: * as array of doubles. It is extracted once, on first call
188: * to get() it, and a by-round-value is returned.
189: * @param name name of property
190: * @param dflt default value
191: * @return a double property.
192: */
193: public double get(String name, double dflt) {
194: // use value by round if already parsed
195: double vals[] = (double[]) valByRound.get(name);
196: if (vals != null) {
197: return vals[roundNumber % vals.length];
198: }
199: // done if not by round
200: String sval = props.getProperty(name, "" + dflt);
201: if (sval.indexOf(":") < 0) {
202: return Double.parseDouble(sval);
203: }
204: // first time this prop is extracted by round
205: int k = sval.indexOf(":");
206: String colName = sval.substring(0, k);
207: sval = sval.substring(k + 1);
208: colForValByRound.put(name, colName);
209: vals = propToDoubleArray(sval);
210: valByRound.put(name, vals);
211: return vals[roundNumber % vals.length];
212: }
213:
214: /**
215: * Return a boolean property.
216: * If the property contain ":", e.g. "true.true.false", it is interpreted
217: * as array of boleans. It is extracted once, on first call
218: * to get() it, and a by-round-value is returned.
219: * @param name name of property
220: * @param dflt default value
221: * @return a int property.
222: */
223: public boolean get(String name, boolean dflt) {
224: // use value by round if already parsed
225: boolean vals[] = (boolean[]) valByRound.get(name);
226: if (vals != null) {
227: return vals[roundNumber % vals.length];
228: }
229: // done if not by round
230: String sval = props.getProperty(name, "" + dflt);
231: if (sval.indexOf(":") < 0) {
232: return Boolean.valueOf(sval).booleanValue();
233: }
234: // first time this prop is extracted by round
235: int k = sval.indexOf(":");
236: String colName = sval.substring(0, k);
237: sval = sval.substring(k + 1);
238: colForValByRound.put(name, colName);
239: vals = propToBooleanArray(sval);
240: valByRound.put(name, vals);
241: return vals[roundNumber % vals.length];
242: }
243:
244: /**
245: * Increment the round number, for config values that are extracted by round number.
246: * @return the new round number.
247: */
248: public int newRound() {
249: roundNumber++;
250:
251: StringBuffer sb = new StringBuffer("--> Round ").append(
252: roundNumber - 1).append("-->").append(roundNumber);
253:
254: // log changes in values
255: if (valByRound.size() > 0) {
256: sb.append(": ");
257: for (Iterator iter = valByRound.keySet().iterator(); iter
258: .hasNext();) {
259: String name = (String) iter.next();
260: Object a = valByRound.get(name);
261: if (a instanceof int[]) {
262: int ai[] = (int[]) a;
263: int n1 = (roundNumber - 1) % ai.length;
264: int n2 = roundNumber % ai.length;
265: sb.append(" ").append(name).append(":").append(
266: ai[n1]).append("-->").append(ai[n2]);
267: } else if (a instanceof double[]) {
268: double ad[] = (double[]) a;
269: int n1 = (roundNumber - 1) % ad.length;
270: int n2 = roundNumber % ad.length;
271: sb.append(" ").append(name).append(":").append(
272: ad[n1]).append("-->").append(ad[n2]);
273: } else {
274: boolean ab[] = (boolean[]) a;
275: int n1 = (roundNumber - 1) % ab.length;
276: int n2 = roundNumber % ab.length;
277: sb.append(" ").append(name).append(":").append(
278: ab[n1]).append("-->").append(ab[n2]);
279: }
280: }
281: }
282:
283: System.out.println();
284: System.out.println(sb.toString());
285: System.out.println();
286:
287: return roundNumber;
288: }
289:
290: // extract properties to array, e.g. for "10:100:5" return int[]{10,100,5}.
291: private int[] propToIntArray(String s) {
292: if (s.indexOf(":") < 0) {
293: return new int[] { Integer.parseInt(s) };
294: }
295:
296: ArrayList a = new ArrayList();
297: StringTokenizer st = new StringTokenizer(s, ":");
298: while (st.hasMoreTokens()) {
299: String t = st.nextToken();
300: a.add(new Integer(t));
301: }
302: int res[] = new int[a.size()];
303: for (int i = 0; i < a.size(); i++) {
304: res[i] = ((Integer) a.get(i)).intValue();
305: }
306: return res;
307: }
308:
309: // extract properties to array, e.g. for "10.7:100.4:-2.3" return int[]{10.7,100.4,-2.3}.
310: private double[] propToDoubleArray(String s) {
311: if (s.indexOf(":") < 0) {
312: return new double[] { Double.parseDouble(s) };
313: }
314:
315: ArrayList a = new ArrayList();
316: StringTokenizer st = new StringTokenizer(s, ":");
317: while (st.hasMoreTokens()) {
318: String t = st.nextToken();
319: a.add(new Double(t));
320: }
321: double res[] = new double[a.size()];
322: for (int i = 0; i < a.size(); i++) {
323: res[i] = ((Double) a.get(i)).doubleValue();
324: }
325: return res;
326: }
327:
328: // extract properties to array, e.g. for "true:true:false" return boolean[]{true,false,false}.
329: private boolean[] propToBooleanArray(String s) {
330: if (s.indexOf(":") < 0) {
331: return new boolean[] { Boolean.valueOf(s).booleanValue() };
332: }
333:
334: ArrayList a = new ArrayList();
335: StringTokenizer st = new StringTokenizer(s, ":");
336: while (st.hasMoreTokens()) {
337: String t = st.nextToken();
338: a.add(new Boolean(t));
339: }
340: boolean res[] = new boolean[a.size()];
341: for (int i = 0; i < a.size(); i++) {
342: res[i] = ((Boolean) a.get(i)).booleanValue();
343: }
344: return res;
345: }
346:
347: /**
348: * @return names of params set by round, for reports title
349: */
350: public String getColsNamesForValsByRound() {
351: if (colForValByRound.size() == 0) {
352: return "";
353: }
354: StringBuffer sb = new StringBuffer();
355: for (Iterator it = colForValByRound.keySet().iterator(); it
356: .hasNext();) {
357: String name = (String) it.next();
358: String colName = (String) colForValByRound.get(name);
359: sb.append(" ").append(colName);
360: }
361: return sb.toString();
362: }
363:
364: /**
365: * @return values of params set by round, for reports lines.
366: */
367: public String getColsValuesForValsByRound(int roundNum) {
368: if (colForValByRound.size() == 0) {
369: return "";
370: }
371: StringBuffer sb = new StringBuffer();
372: for (Iterator it = colForValByRound.keySet().iterator(); it
373: .hasNext();) {
374: String name = (String) it.next();
375: String colName = (String) colForValByRound.get(name);
376: String template = " " + colName;
377: if (roundNum < 0) {
378: // just append blanks
379: sb.append(Format.formatPaddLeft("-", template));
380: } else {
381: // append actual values, for that round
382: Object a = valByRound.get(name);
383: if (a instanceof int[]) {
384: int ai[] = (int[]) a;
385: int n = roundNum % ai.length;
386: sb.append(Format.format(ai[n], template));
387: } else if (a instanceof double[]) {
388: double ad[] = (double[]) a;
389: int n = roundNum % ad.length;
390: sb.append(Format.format(2, ad[n], template));
391: } else {
392: boolean ab[] = (boolean[]) a;
393: int n = roundNum % ab.length;
394: sb.append(Format.formatPaddLeft("" + ab[n],
395: template));
396: }
397: }
398: }
399: return sb.toString();
400: }
401:
402: /**
403: * @return the round number.
404: */
405: public int getRoundNumber() {
406: return roundNumber;
407: }
408:
409: /**
410: * @return Returns the algorithmText.
411: */
412: public String getAlgorithmText() {
413: return algorithmText;
414: }
415:
416: }
|