1 package org.apache.lucene.benchmark.byTask.utils;
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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.
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;
32 * Perf run configuration properties.
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.
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>
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");
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;
58 * Read both algorithm and config properties.
60 * @param algReader from where to read algorithm and config properties.
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()) {
70 if (line.indexOf('=') > 0) {
71 lastConfigLine = lines.size();
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));
81 // read props from string
82 this.props = new Properties();
83 props.load(new ByteArrayInputStream(sb.toString().getBytes()));
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"));
90 if (Boolean.valueOf(props.getProperty("print.props", DEFAULT_PRINT_PROPS)).booleanValue()) {
94 // copy algorithm lines
95 sb = new StringBuilder();
96 for (int i = lastConfigLine; i < lines.size(); i++) {
97 sb.append(lines.get(i));
100 algorithmText = sb.toString();
104 * Create config without algorithm - useful for a programmatic perf test.
105 * @param props - configuration properties.
107 public Config (Properties props) {
109 if (Boolean.valueOf(props.getProperty("print.props",DEFAULT_PRINT_PROPS)).booleanValue()) {
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));
122 System.out.println("-------------------------------");
126 * Return a string property.
128 * @param name name of property.
129 * @param dflt default value.
130 * @return a string property.
132 public String get(String name, String dflt) {
133 String vals[] = (String[]) valByRound.get(name);
135 return vals[roundNumber % vals.length];
137 // done if not by round
138 String sval = props.getProperty(name, dflt);
142 if (sval.indexOf(":") < 0) {
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 /
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];
161 * Note: once a multiple values property is set, it can no longer be modified.
163 * @param name name of property.
164 * @param value either single or multiple property value (multiple values are separated by ":")
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!");
171 props.setProperty(name, value);
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.
180 * @param name name of property
181 * @param dflt default value
182 * @return a int property.
184 public int get(String name, int dflt) {
185 // use value by round if already parsed
186 int vals[] = (int[]) valByRound.get(name);
188 return vals[roundNumber % vals.length];
190 // done if not by round
191 String sval = props.getProperty(name, "" + dflt);
192 if (sval.indexOf(":") < 0) {
193 return Integer.parseInt(sval);
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];
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.
211 * @param name name of property
212 * @param dflt default value
213 * @return a double property.
215 public double get(String name, double dflt) {
216 // use value by round if already parsed
217 double vals[] = (double[]) valByRound.get(name);
219 return vals[roundNumber % vals.length];
221 // done if not by round
222 String sval = props.getProperty(name, "" + dflt);
223 if (sval.indexOf(":") < 0) {
224 return Double.parseDouble(sval);
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];
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.
242 * @param name name of property
243 * @param dflt default value
244 * @return a int property.
246 public boolean get(String name, boolean dflt) {
247 // use value by round if already parsed
248 boolean vals[] = (boolean[]) valByRound.get(name);
250 return vals[roundNumber % vals.length];
252 // done if not by round
253 String sval = props.getProperty(name, "" + dflt);
254 if (sval.indexOf(":") < 0) {
255 return Boolean.valueOf(sval).booleanValue();
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];
268 * Increment the round number, for config values that are extracted by round number.
270 * @return the new round number.
272 public int newRound() {
275 StringBuilder sb = new StringBuilder("--> Round ").append(roundNumber - 1).append("-->").append(roundNumber);
277 // log changes in values
278 if (valByRound.size() > 0) {
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]);
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]);
306 System.out.println();
307 System.out.println(sb.toString());
308 System.out.println();
313 private String[] propToStringArray(String s) {
314 if (s.indexOf(":") < 0) {
315 return new String[]{s};
318 ArrayList<String> a = new ArrayList<String>();
319 StringTokenizer st = new StringTokenizer(s, ":");
320 while (st.hasMoreTokens()) {
321 String t = st.nextToken();
324 return a.toArray(new String[a.size()]);
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)};
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));
339 int res[] = new int[a.size()];
340 for (int i = 0; i < a.size(); i++) {
341 res[i] = a.get(i).intValue();
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)};
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));
358 double res[] = new double[a.size()];
359 for (int i = 0; i < a.size(); i++) {
360 res[i] = a.get(i).doubleValue();
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()};
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));
377 boolean res[] = new boolean[a.size()];
378 for (int i = 0; i < a.size(); i++) {
379 res[i] = a.get(i).booleanValue();
385 * @return names of params set by round, for reports title
387 public String getColsNamesForValsByRound() {
388 if (colForValByRound.size() == 0) {
391 StringBuilder sb = new StringBuilder();
392 for (final String name : colForValByRound.keySet()) {
393 String colName = colForValByRound.get(name);
394 sb.append(" ").append(colName);
396 return sb.toString();
400 * @return values of params set by round, for reports lines.
402 public String getColsValuesForValsByRound(int roundNum) {
403 if (colForValByRound.size() == 0) {
406 StringBuilder sb = new StringBuilder();
407 for (final String name : colForValByRound.keySet()) {
408 String colName = colForValByRound.get(name);
409 String template = " " + colName;
411 // just append blanks
412 sb.append(Format.formatPaddLeft("-", template));
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;
429 boolean ab[] = (boolean[]) a;
430 int n = roundNum % ab.length;
431 sb.append(Format.formatPaddLeft("" + ab[n], template));
435 return sb.toString();
439 * @return the round number.
441 public int getRoundNumber() {
446 * @return Returns the algorithmText.
448 public String getAlgorithmText() {
449 return algorithmText;