001/* An application that executes non-graphical 002 models specified on the command line and prints out statistics. 003 004 Copyright (c) 2001-2014 The Regents of the University of California. 005 All rights reserved. 006 Permission is hereby granted, without written agreement and without 007 license or royalty fees, to use, copy, modify, and distribute this 008 software and its documentation for any purpose, provided that the above 009 copyright notice and the following two paragraphs appear in all copies 010 of this software. 011 012 IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY 013 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 014 ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF 015 THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF 016 SUCH DAMAGE. 017 018 THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, 019 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 020 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE 021 PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF 022 CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, 023 ENHANCEMENTS, OR MODIFICATIONS. 024 025 PT_COPYRIGHT_VERSION_2 026 COPYRIGHTENDKEY 027 028 */ 029package ptolemy.actor.gui; 030 031import java.lang.reflect.Constructor; 032import java.net.URL; 033import java.util.Iterator; 034import java.util.LinkedList; 035import java.util.List; 036 037import ptolemy.actor.CompositeActor; 038import ptolemy.actor.Director; 039import ptolemy.actor.Manager; 040import ptolemy.data.expr.Variable; 041import ptolemy.kernel.attributes.VersionAttribute; 042import ptolemy.kernel.util.Attribute; 043import ptolemy.kernel.util.IllegalActionException; 044import ptolemy.kernel.util.Settable; 045import ptolemy.kernel.util.Workspace; 046import ptolemy.moml.MoMLParser; 047import ptolemy.moml.StreamErrorHandler; 048import ptolemy.moml.filter.BackwardCompatibility; 049import ptolemy.moml.filter.RemoveGraphicalClasses; 050import ptolemy.util.StringUtilities; 051 052/////////////////////////////////////////////////////////////////// 053//// MoMLSimpleStatisticalApplication 054 055/** A simple application that reads in a .xml file as a command 056 line argument, runs it and prints out time and memory statistics 057 058 <p>MoMLApplication sets the look and feel, which starts up Swing, 059 so we can't use MoMLApplication for non-graphical simulations. 060 061 <p>We implement the ChangeListener interface so that this 062 class will get exceptions thrown by failed change requests. 063 064 <p>Below is an example use of this class: 065 <pre> 066 java -classpath $PTII ptolemy.actor.gui.MoMLSimpleStatisticalApplication -iterations 2 ../../../ptolemy/domains/sdf/demo/OrthogonalCom/OrthogonalCom.xml 067 </pre> 068 069 @author Christopher Hylands 070 @version $Id$ 071 @since Ptolemy II 2.0 072 @Pt.ProposedRating Red (cxh) 073 @Pt.AcceptedRating Red (eal) 074 */ 075public class MoMLSimpleStatisticalApplication 076 extends ptolemy.moml.MoMLSimpleApplication { 077 /** Parse the xml file and run it. 078 * @param args The command line arguments 079 * @exception Exception If there was a problem parsing 080 * or running the model. 081 */ 082 public MoMLSimpleStatisticalApplication(String[] args) throws Exception { 083 _parser = new MoMLParser(); 084 085 MoMLParser.setErrorHandler(new StreamErrorHandler()); 086 087 // The test suite calls MoMLSimpleApplication multiple times, 088 // and the list of filters is static, so we reset it each time 089 // so as to avoid adding filters every time we run an auto test. 090 // We set the list of MoMLFilters to handle Backward Compatibility. 091 MoMLParser.setMoMLFilters(BackwardCompatibility.allFilters()); 092 093 // Filter out any graphical classes. 094 MoMLParser.addMoMLFilter(new RemoveGraphicalClasses()); 095 096 // First, we gc and then print the memory stats 097 // BTW to get more info about gc, 098 // use java -verbose:gc . . . 099 System.gc(); 100 Thread.sleep(1000); 101 102 long startTime = System.currentTimeMillis(); 103 104 _parseArgs(args); 105 106 // We use parse(URL, URL) here instead of parseFile(String) 107 // because parseFile() works best on relative pathnames and 108 // has problems finding resources like files specified in 109 // parameters if the xml file was specified as an absolute path. 110 //CompositeActor toplevel = (CompositeActor) parser.parse(null, 111 // new File(xmlFilename).toURL()); 112 Manager manager = new Manager(_toplevel.workspace(), 113 "MoMLSimpleStatisticalApplication"); 114 _toplevel.setManager(manager); 115 _toplevel.addChangeListener(this); 116 117 Runtime runtime = Runtime.getRuntime(); 118 119 // Get the memory stats before we get the model name 120 // just to be sure that getting the model name does 121 // not skew are data too much 122 long totalMemory1 = runtime.totalMemory() / 1024; 123 long freeMemory1 = runtime.freeMemory() / 1024; 124 125 String modelName = _toplevel.getName(); 126 127 System.out.println(modelName + ": Stats before execution: " 128 + Manager.timeAndMemory(startTime, totalMemory1, freeMemory1)); 129 130 // Second, we run and print memory stats. 131 Manager.minimumStatisticsTime = 0; 132 manager.execute(); 133 134 long totalMemory2 = runtime.totalMemory() / 1024; 135 long freeMemory2 = runtime.freeMemory() / 1024; 136 String standardStats = Manager.timeAndMemory(startTime, totalMemory2, 137 freeMemory2); 138 139 System.out.println( 140 modelName + ": Execution stats: " + standardStats); 141 142 // Third, we gc and print memory stats. 143 System.gc(); 144 Thread.sleep(1000); 145 146 long totalMemory3 = runtime.totalMemory() / 1024; 147 long freeMemory3 = runtime.freeMemory() / 1024; 148 System.out.println(modelName + ": After Garbage Collection: " 149 + Manager.timeAndMemory(startTime, totalMemory3, freeMemory3)); 150 System.out.println(modelName + ": construction size: " 151 + totalMemory1 + "K - " + freeMemory1 + "K = " 152 + (totalMemory1 - freeMemory1) + "K"); 153 System.out.println(modelName + ": model alloc. while exec. : " 154 + freeMemory1 + "K - " + freeMemory3 + "K = " 155 + (freeMemory1 - freeMemory3) + "K"); 156 System.out.println(modelName + ": model alloc. runtime data: " 157 + freeMemory3 + "K - " + freeMemory2 + "K = " 158 + (freeMemory3 - freeMemory2) + "K"); 159 160 // Print out the standard stats at the end 161 // so as not to break too many scripts 162 System.out.println( 163 standardStats + " Stat: " + (totalMemory1 - freeMemory1) 164 + "K StatRT: " + (freeMemory1 - freeMemory3) 165 + "K DynRT: " + (freeMemory3 - freeMemory2) + "K"); 166 } 167 168 /** Parse a command-line argument. 169 * @param arg The command-line argument to be parsed. 170 * @return True if the argument is understood, false otherwise. 171 * @exception Exception If something goes wrong. 172 */ 173 protected boolean _parseArg(String arg) throws Exception { 174 if (arg.equals("-class")) { 175 _expectingClass = true; 176 } else if (arg.equals("-help")) { 177 System.out.println(_usage()); 178 179 // NOTE: This means the test suites cannot test -help 180 StringUtilities.exit(0); 181 } else if (arg.equals("-test")) { 182 _test = true; 183 } else if (arg.equals("-version")) { 184 System.out.println("Version " + VersionAttribute.CURRENT_VERSION 185 + ", Build $Id$"); 186 187 // NOTE: This means the test suites cannot test -version 188 StringUtilities.exit(0); 189 } else if (arg.equals("")) { 190 // Ignore blank argument. 191 } else { 192 if (_expectingClass) { 193 _expectingClass = false; 194 195 // Create the class. 196 Class<?> newClass = Class.forName(arg); 197 198 // Instantiate the specified class in a new workspace. 199 Workspace workspace = new Workspace(); 200 201 // Get the constructor that takes a Workspace argument. 202 Class[] argTypes = new Class[1]; 203 argTypes[0] = workspace.getClass(); 204 205 Constructor<?> constructor = newClass.getConstructor(argTypes); 206 207 Object[] args = new Object[1]; 208 args[0] = workspace; 209 constructor.newInstance(args); 210 } else { 211 if (!arg.startsWith("-")) { 212 // Assume the argument is a file name or URL. 213 // Attempt to read it. 214 URL inURL = ConfigurationApplication.specToURL(arg); 215 216 // Strangely, the XmlParser does not want as base the 217 // directory containing the file, but rather the 218 // file itself. 219 URL base = inURL; 220 221 // Assume this is a MoML file, and open it. 222 _parser.reset(); 223 224 // Always print the open time 225 long startTime = System.currentTimeMillis(); 226 _toplevel = (CompositeActor) _parser.parse(base, inURL); 227 System.out.println("Opened \"" + base + "\": " 228 + Manager.timeAndMemory(startTime)); 229 long statisticsStartTime = System.currentTimeMillis(); 230 System.out.println(_toplevel.statistics(null)); 231 long statisticsEndTime = System.currentTimeMillis(); 232 System.out.println("Generating statistics took" 233 + (statisticsEndTime - statisticsStartTime) 234 + " ms. "); 235 } else { 236 // Argument not recognized. 237 return false; 238 } 239 } 240 } 241 242 return true; 243 } 244 245 /** Parse the command-line arguments. 246 * @param args The command-line arguments to be parsed. 247 * @exception Exception If an argument is not understood or triggers 248 * an error. 249 */ 250 protected void _parseArgs(String[] args) throws Exception { 251 for (int i = 0; i < args.length; i++) { 252 String arg = args[i]; 253 254 if (_parseArg(arg) == false) { 255 if (arg.trim().startsWith("-")) { 256 if (i >= args.length - 1) { 257 throw new IllegalActionException( 258 "Cannot set " + "parameter " + arg 259 + " when no value is " + "given."); 260 } 261 262 // Save in case this is a parameter name and value. 263 _parameterNames.add(arg.substring(1)); 264 _parameterValues.add(args[i + 1]); 265 i++; 266 } else { 267 // Unrecognized option. 268 throw new IllegalActionException( 269 "Unrecognized option: " + arg); 270 } 271 } 272 } 273 274 if (_expectingClass) { 275 throw new IllegalActionException("Missing classname."); 276 } 277 278 // Check saved options to see whether any is setting an attribute. 279 Iterator<String> names = _parameterNames.iterator(); 280 Iterator<String> values = _parameterValues.iterator(); 281 282 while (names.hasNext() && values.hasNext()) { 283 String name = names.next(); 284 String value = values.next(); 285 286 boolean match = false; 287 288 CompositeActor model = _toplevel; 289 System.out.println("model = " + model.getFullName()); 290 291 Attribute attribute = model.getAttribute(name); 292 293 if (attribute instanceof Settable) { 294 match = true; 295 ((Settable) attribute).setExpression(value); 296 297 if (attribute instanceof Variable) { 298 // Force evaluation so that listeners are notified. 299 ((Variable) attribute).getToken(); 300 } 301 } 302 303 Director director = model.getDirector(); 304 305 if (director != null) { 306 attribute = director.getAttribute(name); 307 308 if (attribute instanceof Settable) { 309 match = true; 310 ((Settable) attribute).setExpression(value); 311 312 if (attribute instanceof Variable) { 313 // Force evaluation so that listeners 314 // are notified. 315 ((Variable) attribute).getToken(); 316 } 317 } 318 } 319 320 if (!match) { 321 // Unrecognized option. 322 throw new IllegalActionException("Unrecognized option: " 323 + "No parameter exists with name " + name); 324 } 325 } 326 } 327 328 /** Create an instance of a single model and run it. 329 * @param args The command-line arguments naming the .xml file to run 330 */ 331 public static void main(String[] args) { 332 try { 333 new MoMLSimpleStatisticalApplication(args); 334 } catch (Exception ex) { 335 System.err.println("Command failed: " + ex); 336 ex.printStackTrace(); 337 } 338 } 339 340 /** Return a string summarizing the command-line arguments. 341 * @return A usage string. 342 */ 343 protected String _usage() { 344 StringBuffer result = new StringBuffer("Usage: " + _commandTemplate 345 + "\n\n" + "Options that take values:\n"); 346 347 int i; 348 349 for (i = 0; i < _commandOptions.length; i++) { 350 result.append(" " + _commandOptions[i][0] + " " 351 + _commandOptions[i][1] + "\n"); 352 } 353 354 result.append("\nBoolean flags:\n"); 355 356 for (i = 0; i < _commandFlags.length; i++) { 357 result.append(" " + _commandFlags[i]); 358 } 359 360 return result.toString(); 361 } 362 363 /////////////////////////////////////////////////////////////////// 364 //// protected variables //// 365 366 /** The command-line options that are either present or not. */ 367 protected String[] _commandFlags = { "-help", "-test", "-version", }; 368 369 /** The command-line options that take arguments. */ 370 protected String[][] _commandOptions = { { "-class", "<classname>" }, 371 { "-<parameter name>", "<parameter value>" }, }; 372 373 /** The form of the command line. */ 374 protected String _commandTemplate = "java -classpath $PTII ptolemy.actor.gui.MoMLSimpleStatisticalApplication [ options ] [file ...]"; 375 376 /** If true, then auto exit after a few seconds. */ 377 protected static boolean _test = false; 378 379 /////////////////////////////////////////////////////////////////// 380 //// private variables //// 381 // Flag indicating that the previous argument was -class. 382 private boolean _expectingClass = false; 383 384 // List of parameter names seen on the command line. 385 private List<String> _parameterNames = new LinkedList<String>(); 386 387 // List of parameter values seen on the command line. 388 private List<String> _parameterValues = new LinkedList<String>(); 389}