Benchmark.java
001 /*
002  *  Benchmark.java
003  *
004  *  Copyright (c) 1995-2010, The University of Sheffield. See the file
005  *  COPYRIGHT.txt in the software or at http://gate.ac.uk/gate/COPYRIGHT.txt
006  *
007  *  This file is part of GATE (see http://gate.ac.uk/), and is free
008  *  software, licenced under the GNU Library General Public License,
009  *  Version 2, June 1991 (in the distribution as file licence.html,
010  *  and also available at http://gate.ac.uk/gate/licence.html).
011  */
012 
013 package gate.util;
014 
015 import gate.Executable;
016 import gate.creole.ExecutionException;
017 
018 import java.util.Date;
019 import java.util.HashMap;
020 import java.util.Map;
021 import org.apache.log4j.Logger;
022 
023 /**
024  * This class provides methods for making entries in the shared log
025  * maintained by the GATE system. User should use various methods
026  * provided by this class and as described in the following example.
027  
028  <p>
029  
030  * TODO: Provide example here.
031  
032  </p>
033  
034  @author niraj
035  */
036 public class Benchmark {
037 
038   /**
039    * variable that keeps track of if logging is ON or OFF.
040    */
041   protected static boolean benchmarkingEnabled = false;
042 
043   /**
044    * corpus name feature
045    */
046   public final static String CORPUS_NAME_FEATURE = "corpusName";
047 
048   /**
049    * application name feature
050    */
051   public final static String APPLICATION_NAME_FEATURE = "applicationName";
052 
053   /**
054    * document name feature
055    */
056   public final static String DOCUMENT_NAME_FEATURE = "documentName";
057 
058   /**
059    * processing resource name feature
060    */
061   public final static String PR_NAME_FEATURE = "prName";
062 
063   /**
064    * message feature
065    */
066   public final static String MESSAGE_FEATURE = "message";
067 
068   // various check point ids
069 
070   public final static String PR_PREFIX = "pr_";
071 
072   public final static String DOCUMENT_LOADED = "documentLoaded";
073 
074   public final static String DOCUMENT_SAVED = "documentSaved";
075 
076   public final static String WRITING_FVS_TO_DISK = "writingFVsToDisk";
077 
078   public final static String ANNOTS_TO_NLP_FEATURES = "annotsToNlpFeatures";
079 
080   public final static String NLP_FEATURES_TO_FVS = "nlpFeaturesToFVs";
081 
082   public final static String READING_LEARNING_INFO = "readingLearningInfo";
083 
084   public final static String MODEL_APPLICATION = "modelApplication";
085 
086   public final static String WRITING_NGRAM_MODEL = "writingNgramModel";
087 
088   public final static String TERM_DOC_STATS = "termDocStats";
089 
090   public final static String FILTERING = "filtering";
091 
092   public final static String MODEL_TRAINING = "modelTraining";
093 
094   public final static String EVALUATION = "evaluation";
095 
096   public final static String NLP_LABELS_TO_DATA_LABELS = "nlpLabelsToDataLabels";
097 
098   public final static String READING_NLP_FEATURES = "readingNlpFeatures";
099 
100   public final static String READING_FVS = "readingFVs";
101 
102   public final static String WEKA_MODEL_TRAINING = "wekaModelTraining";
103 
104   public final static String PAUM_MODEL_TRAINING = "paumModelTraining";
105 
106   public final static String READING_CHUNK_LEARNING_DATA = "readingChunkLearningData";
107 
108   public final static String WEKA_MODEL_APPLICATION = "wekaModelApplication";
109 
110   public final static String PAUM_MODEL_APPLICATION = "paumModelApplication";
111 
112   public final static String POST_PROCESSING = "postProcessing";
113 
114   /**
115    * Static shared logger used for logging.
116    */
117   public static Logger logger = Logger.getLogger(Benchmark.class);
118 
119   /**
120    * This returns the current system time.
121    
122    @return
123    */
124   public static long startPoint() {
125     return System.currentTimeMillis();
126   }
127 
128   /**
129    * Like {@link #startPoint()} but also logs a message with the
130    * starting time if benchmarking is enabled. This is intended to be
131    * used in conjuntion with the three-argument version of checkPoint.
132    
133    @param benchmarkID the identifier of the process that is just
134    *          starting.
135    @return the current time, as logged.
136    */
137   public static long startPoint(String benchmarkID) {
138     long time = startPoint();
139     if(benchmarkingEnabled) {
140       logger.info(time + " START " + benchmarkID);
141     }
142     return time;
143   }
144 
145   /**
146    * This method is responsible for making entries into the log.
147    
148    @param startTime - when did the actual process started. This value
149    *          should be the value obtained by Benchmark.startPoint()
150    *          method invoked at the begining of the process.
151    @param benchmarkID - a unique ID of the resource that should be
152    *          logged with this message.
153    @param objectInvokingThisCheckPoint - The benchmarkable object that
154    *          invokes this method.
155    @param features - any features (key-value pairs) that should be
156    *          reported in the log message. toString() method will be
157    *          invoked on the objects.
158    */
159   public static void checkPoint(long startTime, String benchmarkID,
160           Object objectInvokingThisCheckPoint, Map benchmarkingFeatures) {
161 
162     // check if logging is disabled
163     if(!benchmarkingEnabledreturn;
164 
165     // we calculate processEndTime here as we don't want to consider
166     // the time to convert featureMapToString
167     long processingTime = System.currentTimeMillis() - startTime;
168 
169     logCheckPoint(String.valueOf(processingTime), benchmarkID,
170             objectInvokingThisCheckPoint, benchmarkingFeatures);
171   }
172   
173   /**
174    * This method is responsible for making entries into the log.
175    
176    @param totalTime - Total time consumed by the process
177    @param benchmarkID - a unique ID of the resource that should be
178    *          logged with this message.
179    @param objectInvokingThisCheckPoint - The benchmarkable object that
180    *          invokes this method.
181    @param features - any features (key-value pairs) that should be
182    *          reported in the log message. toString() method will be
183    *          invoked on the objects.
184    */
185   public static void checkPointWithDuration(long totalTime, String benchmarkID,
186           Object objectInvokingThisCheckPoint, Map benchmarkingFeatures) {
187 
188     // check if logging is disabled
189     if(!benchmarkingEnabledreturn;
190 
191     logCheckPoint(String.valueOf(totalTime), benchmarkID,
192             objectInvokingThisCheckPoint, benchmarkingFeatures);
193   }
194 
195   /**
196    * Logs the end of a process. There must previously have been a call
197    * to {@link #startPoint(String)} with the same benchmark ID.
198    
199    @see #checkPoint(long, String, Object, Map)
200    */
201   public static void checkPoint(String benchmarkID,
202           Object objectInvokingThisCheckPoint, Map benchmarkingFeatures) {
203     if(!benchmarkingEnabledreturn;
204     logCheckPoint("END", benchmarkID, objectInvokingThisCheckPoint,
205             benchmarkingFeatures);
206   }
207 
208   /**
209    * Private method to create a line in the benchmark log.
210    
211    @param processingTimeOrFlag either the duration of the task in ms
212    *          or the string "END" if no start time was provided.
213    */
214   private static void logCheckPoint(String processingTimeOrFlag,
215           String benchmarkID, Object objectInvokingThisCheckPoint,
216           Map benchmarkingFeatures) {
217     // finally build the string to be logged
218     StringBuilder messageToLog = new StringBuilder();
219     messageToLog.append("" + System.currentTimeMillis() " ");
220     messageToLog.append(processingTimeOrFlag + " " + benchmarkID + " "
221             + objectInvokingThisCheckPoint.getClass().getName() " ");
222 
223     if(benchmarkingFeatures == null) {
224       messageToLog.append("{}");
225     }
226     else {
227       messageToLog.append(benchmarkingFeatures.toString().replaceAll("\n"""))
228             .append("\n");
229     }
230     logger.info(messageToLog.toString());
231   }
232 
233   /**
234    * Helper method to generate the benchmark ID.
235    
236    @param resourceName
237    @param parentBenchmarkID
238    @return
239    */
240   public static String createBenchmarkId(String resourceName,
241           String parentBenchmarkID) {
242     if(parentBenchmarkID != null) {
243       if(resourceName != null) {
244         return (parentBenchmarkID + "." + resourceName.replaceAll("\\.","_")).replaceAll("[ ]+""_");
245       }
246       else {
247         return (parentBenchmarkID + ".null").replaceAll("[ ]+""_");
248       }
249     }
250     else {
251       if(resourceName != null) {
252         return resourceName.replaceAll("[ .]+""_");
253       }
254       else {
255         return "null";
256       }
257     }
258 
259   }
260 
261   /**
262    * Returns if the logging is enabled.
263    
264    @return
265    */
266   public static boolean isBenchmarkingEnabled() {
267     return benchmarkingEnabled;
268   }
269 
270   /**
271    * Enables or disables the logging.
272    
273    @param benchmarkingEnabled
274    */
275   public static void setBenchmarkingEnabled(boolean benchmarkingEnabled) {
276     Benchmark.benchmarkingEnabled = benchmarkingEnabled;
277   }
278 
279   /**
280    * Executes the given {@link Executable}, logging its runtime under
281    * the given benchmark ID (which is propagated to the Executable if it
282    * is itself {@link Benchmarkable}).
283    
284    @param executable the object to execute
285    @param benchmarkID the benchmark ID, which must not contain spaces
286    *  as it is already used as a separator in the log, you can use
287    {@link #createBenchmarkId(String, String)} for it. 
288    @param objectInvokingThisCheckPoint the object invoking this method
289    *          (typically the caller would pass <code>this</code> here)
290    @param benchmarkingFeatures features to include in the check point
291    *          log
292    @throws ExecutionException any exceptions thrown by the underlying
293    *           Executable are propagated.
294    */
295   public static void executeWithBenchmarking(Executable executable,
296           String benchmarkID, Object objectInvokingThisCheckPoint,
297           Map benchmarkingFeaturesthrows ExecutionException {
298     if(!benchmarkingEnabled) {
299       executable.execute();
300     }
301     else {
302       long startTime = startPoint();
303       String savedBenchmarkID = null;
304       try {
305         if(executable instanceof Benchmarkable) {
306           savedBenchmarkID = ((Benchmarkable)executable).getBenchmarkId();
307           ((Benchmarkable)executable).setBenchmarkId(benchmarkID);
308         }
309 
310         executable.execute();
311       }
312       catch(Exception e) {
313         Map tempFeatures = new HashMap();
314         if(benchmarkingFeatures != null) {
315           tempFeatures.putAll(benchmarkingFeatures);
316         }
317         tempFeatures.put("exceptionThrown", e);
318         checkPoint(startTime, benchmarkID, objectInvokingThisCheckPoint,
319                 tempFeatures);
320         if(instanceof ExecutionException) {
321           throw (ExecutionException)e;
322         }
323         else {
324           throw (RuntimeException)e;
325         }
326       }
327       finally {
328         if(savedBenchmarkID != null) {
329           ((Benchmarkable)executable).setBenchmarkId(savedBenchmarkID);
330         }
331       }
332 
333       // succeeded, so log checkpoint with the original features
334       checkPoint(startTime, benchmarkID, objectInvokingThisCheckPoint,
335               benchmarkingFeatures);
336     }
337   }
338 }