pylucene 3.5.0-3
[pylucene.git] / lucene-java-3.5.0 / lucene / contrib / benchmark / src / java / org / apache / lucene / benchmark / byTask / utils / Algorithm.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.StreamTokenizer;
21 import java.io.StringReader;
22 import java.lang.reflect.Constructor;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25
26 import org.apache.lucene.benchmark.byTask.PerfRunData;
27 import org.apache.lucene.benchmark.byTask.tasks.PerfTask;
28 import org.apache.lucene.benchmark.byTask.tasks.RepSumByPrefTask;
29 import org.apache.lucene.benchmark.byTask.tasks.TaskSequence;
30
31 /**
32  * Test algorithm, as read from file
33  */
34 public class Algorithm {
35   
36   private TaskSequence sequence;
37   private final String[] taskPackages;
38   
39   /**
40    * Read algorithm from file
41    * Property examined: alt.tasks.packages == comma separated list of 
42    * alternate package names where tasks would be searched for, when not found 
43    * in the default package (that of {@link PerfTask}{@link #getClass()}).
44    * If the same task class appears in more than one package, the package 
45    * indicated first in this list will be used.
46    * @param runData perf-run-data used at running the tasks.
47    * @throws Exception if errors while parsing the algorithm 
48    */
49   @SuppressWarnings("fallthrough")
50   public Algorithm (PerfRunData runData) throws Exception {
51     Config config = runData.getConfig();
52     taskPackages = initTasksPackages(config);
53     String algTxt = config.getAlgorithmText();
54     sequence = new TaskSequence(runData,null,null,false);
55     TaskSequence currSequence = sequence;
56     PerfTask prevTask = null;
57     StreamTokenizer stok = new StreamTokenizer(new StringReader(algTxt));
58     stok.commentChar('#');
59     stok.eolIsSignificant(false);
60     stok.ordinaryChar('"');
61     stok.ordinaryChar('/');
62     stok.ordinaryChar('(');
63     stok.ordinaryChar(')');
64     boolean colonOk = false; 
65     boolean isDisableCountNextTask = false; // only for primitive tasks
66     currSequence.setDepth(0);
67     
68     while (stok.nextToken() != StreamTokenizer.TT_EOF) { 
69       switch(stok.ttype) {
70   
71         case StreamTokenizer.TT_WORD:
72           String s = stok.sval;
73           Constructor<? extends PerfTask> cnstr = taskClass(config,s)
74             .asSubclass(PerfTask.class).getConstructor(PerfRunData.class);
75           PerfTask task = cnstr.newInstance(runData);
76           task.setDisableCounting(isDisableCountNextTask);
77           isDisableCountNextTask = false;
78           currSequence.addTask(task);
79           if (task instanceof RepSumByPrefTask) {
80             stok.nextToken();
81             String prefix = stok.sval;
82             if (prefix==null || prefix.length()==0) { 
83               throw new Exception("named report prefix problem - "+stok.toString()); 
84             }
85             ((RepSumByPrefTask) task).setPrefix(prefix);
86           }
87           // check for task param: '(' someParam ')'
88           stok.nextToken();
89           if (stok.ttype!='(') {
90             stok.pushBack();
91           } else {
92             // get params, for tasks that supports them, - anything until next ')'
93             StringBuilder params = new StringBuilder();
94             stok.nextToken();
95             while (stok.ttype!=')') { 
96               switch (stok.ttype) {
97                 case StreamTokenizer.TT_NUMBER:  
98                   params.append(stok.nval);
99                   break;
100                 case StreamTokenizer.TT_WORD:    
101                   params.append(stok.sval);             
102                   break;
103                 case StreamTokenizer.TT_EOF:     
104                   throw new Exception("unexpexted EOF: - "+stok.toString());
105                 default:
106                   params.append((char)stok.ttype);
107               }
108               stok.nextToken();
109             }
110             String prm = params.toString().trim();
111             if (prm.length()>0) {
112               task.setParams(prm);
113             }
114           }
115
116           // ---------------------------------------
117           colonOk = false; prevTask = task;
118           break;
119   
120         default:
121           char c = (char)stok.ttype;
122           
123           switch(c) {
124           
125             case ':' :
126               if (!colonOk) throw new Exception("colon unexpexted: - "+stok.toString());
127               colonOk = false;
128               // get repetitions number
129               stok.nextToken();
130               if ((char)stok.ttype == '*') {
131                 ((TaskSequence)prevTask).setRepetitions(TaskSequence.REPEAT_EXHAUST);
132               } else {
133                 if (stok.ttype!=StreamTokenizer.TT_NUMBER)  {
134                   throw new Exception("expected repetitions number or XXXs: - "+stok.toString());
135                 } else {
136                   double num = stok.nval;
137                   stok.nextToken();
138                   if (stok.ttype == StreamTokenizer.TT_WORD && stok.sval.equals("s")) {
139                     ((TaskSequence) prevTask).setRunTime(num);
140                   } else {
141                     stok.pushBack();
142                     ((TaskSequence) prevTask).setRepetitions((int) num);
143                   }
144                 }
145               }
146               // check for rate specification (ops/min)
147               stok.nextToken();
148               if (stok.ttype!=':') {
149                 stok.pushBack();
150               } else {
151                 // get rate number
152                 stok.nextToken();
153                 if (stok.ttype!=StreamTokenizer.TT_NUMBER) throw new Exception("expected rate number: - "+stok.toString());
154                 // check for unit - min or sec, sec is default
155                 stok.nextToken();
156                 if (stok.ttype!='/') {
157                   stok.pushBack();
158                   ((TaskSequence)prevTask).setRate((int)stok.nval,false); // set rate per sec
159                 } else {
160                   stok.nextToken();
161                   if (stok.ttype!=StreamTokenizer.TT_WORD) throw new Exception("expected rate unit: 'min' or 'sec' - "+stok.toString());
162                   String unit = stok.sval.toLowerCase();
163                   if ("min".equals(unit)) {
164                     ((TaskSequence)prevTask).setRate((int)stok.nval,true); // set rate per min
165                   } else if ("sec".equals(unit)) {
166                     ((TaskSequence)prevTask).setRate((int)stok.nval,false); // set rate per sec
167                   } else {
168                     throw new Exception("expected rate unit: 'min' or 'sec' - "+stok.toString());
169                   }
170                 }
171               }
172               colonOk = false;
173               break;
174     
175             case '{' : 
176             case '[' :  
177               // a sequence
178               // check for sequence name
179               String name = null;
180               stok.nextToken();
181               if (stok.ttype!='"') {
182                 stok.pushBack();
183               } else {
184                 stok.nextToken();
185                 name = stok.sval;
186                 stok.nextToken();
187                 if (stok.ttype!='"' || name==null || name.length()==0) { 
188                   throw new Exception("sequence name problem - "+stok.toString()); 
189                 }
190               }
191               // start the sequence
192               TaskSequence seq2 = new TaskSequence(runData, name, currSequence, c=='[');
193               currSequence.addTask(seq2);
194               currSequence = seq2;
195               colonOk = false;
196               break;
197
198             case '&' :
199               if (currSequence.isParallel()) {
200                 throw new Exception("Can only create background tasks within a serial task");
201               }
202               stok.nextToken();
203               final int deltaPri;
204               if (stok.ttype != StreamTokenizer.TT_NUMBER) {
205                 stok.pushBack();
206                 deltaPri = 0;
207               } else {
208                 // priority
209                 deltaPri = (int) stok.nval;
210               }
211
212               if (prevTask == null) {
213                 throw new Exception("& was unexpected");
214               } else if (prevTask.getRunInBackground()) {
215                 throw new Exception("double & was unexpected");
216               } else {
217                 prevTask.setRunInBackground(deltaPri);
218               }
219               break;
220     
221             case '>' :
222               currSequence.setNoChildReport(); /* intentional fallthrough */
223             case '}' : 
224             case ']' : 
225               // end sequence
226               colonOk = true; prevTask = currSequence;
227               currSequence = currSequence.getParent();
228               break;
229           
230             case '-' :
231               isDisableCountNextTask = true;
232               break;
233               
234           } //switch(c)
235           break;
236           
237       } //switch(stok.ttype)
238       
239     }
240     
241     if (sequence != currSequence) {
242       throw new Exception("Unmatched sequences");
243     }
244     
245     // remove redundant top level enclosing sequences
246     while (sequence.isCollapsable() && sequence.getRepetitions()==1 && sequence.getRate()==0) {
247       ArrayList<PerfTask> t = sequence.getTasks();
248       if (t!=null && t.size()==1) {
249         PerfTask p = t.get(0);
250         if (p instanceof TaskSequence) {
251           sequence = (TaskSequence) p;
252           continue;
253         }
254       }
255       break;
256     }
257   }
258
259   private String[] initTasksPackages(Config config) {
260     String alts = config.get("alt.tasks.packages", null);
261     String dfltPkg = PerfTask.class.getPackage().getName();
262     if (alts==null) {
263       return new String[]{ dfltPkg };
264     }
265     ArrayList<String> pkgs = new ArrayList<String>();
266     pkgs.add(dfltPkg);
267     for (String alt : alts.split(",")) {
268       pkgs.add(alt);
269     }
270     return pkgs.toArray(new String[0]);
271   }
272
273   private Class<?> taskClass(Config config, String taskName)
274       throws ClassNotFoundException {
275     for (String pkg : taskPackages) {
276       try {
277         return Class.forName(pkg+'.'+taskName+"Task");
278       } catch (ClassNotFoundException e) {
279         // failed in this package, might succeed in the next one... 
280       }
281     }
282     // can only get here if failed to instantiate
283     throw new ClassNotFoundException(taskName+" not found in packages "+Arrays.toString(taskPackages));
284   }
285
286   @Override
287   public String toString() {
288     String newline = System.getProperty("line.separator");
289     StringBuilder sb = new StringBuilder();
290     sb.append(sequence.toString());
291     sb.append(newline);
292     return sb.toString();
293   }
294
295   /**
296    * Execute this algorithm
297    * @throws Exception 
298    */
299   public void execute() throws Exception {
300     try {
301       sequence.runAndMaybeStats(true);
302     } finally {
303       sequence.close();
304     }
305   }
306
307   /**
308    * Expert: for test purposes, return all tasks participating in this algorithm.
309    * @return all tasks participating in this algorithm.
310    */
311   public ArrayList<PerfTask> extractTasks() {
312     ArrayList<PerfTask> res = new ArrayList<PerfTask>();
313     extractTasks(res, sequence);
314     return res;
315   }
316   private void extractTasks (ArrayList<PerfTask> extrct, TaskSequence seq) {
317     if (seq==null) 
318       return;
319     extrct.add(seq);
320     ArrayList<PerfTask> t = sequence.getTasks();
321     if (t==null) 
322       return;
323     for (final PerfTask p : t) {
324       if (p instanceof TaskSequence) {
325         extractTasks(extrct, (TaskSequence)p);
326       } else {
327         extrct.add(p);
328       }
329     }
330   }
331   
332 }
333