1 16 package com.google.gwt.junit.benchmarks; 17 18 import com.google.gwt.core.ext.TreeLogger; 19 import com.google.gwt.core.ext.typeinfo.HasMetaData; 20 import com.google.gwt.core.ext.typeinfo.JClassType; 21 import com.google.gwt.core.ext.typeinfo.JMethod; 22 import com.google.gwt.core.ext.typeinfo.TypeOracle; 23 import com.google.gwt.dev.util.Util; 24 import com.google.gwt.junit.client.TestResults; 25 import com.google.gwt.junit.client.Trial; 26 import com.google.gwt.junit.rebind.BenchmarkGenerator; 27 import com.google.gwt.util.tools.Utility; 28 29 import junit.framework.TestCase; 30 31 import org.eclipse.jdt.internal.compiler.IProblemFactory; 32 import org.eclipse.jdt.internal.compiler.ISourceElementRequestor; 33 import org.eclipse.jdt.internal.compiler.SourceElementParser; 34 import org.eclipse.jdt.internal.compiler.SourceElementRequestorAdapter; 35 import org.eclipse.jdt.internal.compiler.batch.CompilationUnit; 36 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; 37 import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; 38 import org.w3c.dom.Document ; 39 import org.w3c.dom.Element ; 40 41 import java.io.BufferedReader ; 42 import java.io.File ; 43 import java.io.FileOutputStream ; 44 import java.io.FileReader ; 45 import java.io.IOException ; 46 import java.text.BreakIterator ; 47 import java.text.DateFormat ; 48 import java.util.ArrayList ; 49 import java.util.Date ; 50 import java.util.HashMap ; 51 import java.util.Iterator ; 52 import java.util.List ; 53 import java.util.Locale ; 54 import java.util.Map ; 55 import java.util.regex.Matcher ; 56 import java.util.regex.Pattern ; 57 58 import javax.xml.parsers.DocumentBuilder ; 59 import javax.xml.parsers.DocumentBuilderFactory ; 60 import javax.xml.parsers.ParserConfigurationException ; 61 62 69 public class BenchmarkReport { 70 71 74 private class BenchmarkXml { 75 76 private MetaData metaData; 77 78 private List results; 79 80 private TestCase test; 81 82 BenchmarkXml(TestCase test, 83 List results) { 84 this.test = test; 85 this.results = results; 86 Map methodMetaData = (Map ) testMetaData.get(test.getClass().toString()); 87 metaData = (MetaData) methodMetaData.get(test.getName()); 88 } 89 90 Element toElement(Document doc) { 91 Element benchmark = doc.createElement("benchmark"); 92 benchmark.setAttribute("class", test.getClass().getName()); 93 benchmark.setAttribute("name", metaData.getTestName()); 94 benchmark.setAttribute("description", metaData.getTestDescription()); 95 96 String sourceCode = metaData.getSourceCode(); 97 if (sourceCode != null) { 98 Element sourceCodeElement = doc.createElement("source_code"); 99 sourceCodeElement.appendChild(doc.createTextNode(sourceCode)); 100 benchmark.appendChild(sourceCodeElement); 101 } 102 103 105 for (Iterator it = results.iterator(); it.hasNext();) { 106 TestResults result = (TestResults) it.next(); 107 benchmark.appendChild(toElement(doc, result)); 108 } 109 110 return benchmark; 111 } 112 113 private Element toElement(Document doc, TestResults result) { 114 Element resultElement = doc.createElement("result"); 115 resultElement.setAttribute("host", result.getHost()); 116 resultElement.setAttribute("agent", result.getAgent()); 117 118 List trials = result.getTrials(); 119 120 for (Iterator it = trials.iterator(); it.hasNext();) { 121 Trial trial = (Trial) it.next(); 122 Element trialElement = toElement(doc, trial); 123 resultElement.appendChild(trialElement); 124 } 125 126 return resultElement; 127 } 128 129 private Element toElement(Document doc, Trial trial) { 130 Element trialElement = doc.createElement("trial"); 131 132 Map variables = trial.getVariables(); 133 134 for (Iterator it = variables.entrySet().iterator(); it.hasNext();) { 135 Map.Entry entry = (Map.Entry ) it.next(); 136 Object name = entry.getKey(); 137 Object value = entry.getValue(); 138 Element variableElement = doc.createElement("variable"); 139 variableElement.setAttribute("name", name.toString()); 140 variableElement.setAttribute("value", value.toString()); 141 trialElement.appendChild(variableElement); 142 } 143 144 trialElement.setAttribute("timing", 145 String.valueOf(trial.getRunTimeMillis())); 146 147 Throwable exception = trial.getException(); 148 149 if (exception != null) { 150 Element exceptionElement = doc.createElement("exception"); 151 exceptionElement.appendChild(doc.createTextNode(exception.toString())); 152 trialElement.appendChild(exceptionElement); 153 } 154 155 return trialElement; 156 } 157 } 158 159 170 private static class Parser { 171 172 static class MethodBody { 173 174 int declarationEnd; 176 int declarationStart; 178 String source; 179 } 180 181 private MethodBody currentMethod; 183 private Map methods = new HashMap (); 185 186 private char[] sourceContents; 188 189 Parser(JClassType klass) throws IOException { 190 191 Map settings = new HashMap (); 192 settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_4); 193 settings.put(CompilerOptions.OPTION_TargetPlatform, 194 CompilerOptions.VERSION_1_4); 195 settings.put(CompilerOptions.OPTION_DocCommentSupport, 196 CompilerOptions.ENABLED); 197 CompilerOptions options = new CompilerOptions(settings); 198 199 IProblemFactory problemFactory = new DefaultProblemFactory( 200 Locale.getDefault()); 201 202 ISourceElementRequestor requestor = new SourceElementRequestorAdapter() { 204 public void enterMethod(MethodInfo methodInfo) { 205 String name = new String (methodInfo.name); 206 if (name.startsWith("test")) { 207 currentMethod = new MethodBody(); 208 currentMethod.declarationStart = methodInfo.declarationStart; 209 methods.put(name, currentMethod); 210 } 211 } 212 213 public void exitMethod(int declarationEnd, int defaultValueStart, 214 int defaultValueEnd) { 215 if (currentMethod != null) { 216 currentMethod.declarationEnd = declarationEnd; 217 currentMethod = null; 218 } 219 } 220 }; 221 222 boolean reportLocalDeclarations = true; 223 boolean optimizeStringLiterals = true; 224 225 SourceElementParser parser = new SourceElementParser(requestor, 226 problemFactory, options, reportLocalDeclarations, 227 optimizeStringLiterals); 228 229 File sourceFile = findSourceFile(klass); 230 sourceContents = read(sourceFile); 231 CompilationUnit unit = new CompilationUnit(sourceContents, 232 sourceFile.getName(), null); 233 234 parser.parseCompilationUnit(unit, true); 235 } 236 237 242 public String getMethod(JMethod method) { 243 250 return new String (sourceContents, method.getDeclStart(), 251 method.getDeclEnd() - method.getDeclStart() + 1); 252 } 253 } 254 255 258 private class ReportXml { 259 260 private Map categoryElementMap = new HashMap (); 261 262 private Date date = new Date (); 263 264 private String version = "unknown"; 265 266 Element toElement(Document doc) { 267 Element report = doc.createElement("gwt_benchmark_report"); 268 String dateString = DateFormat.getDateTimeInstance().format(date); 269 report.setAttribute("date", dateString); 270 report.setAttribute("gwt_version", version); 271 272 for (Iterator entryIt = testResults.entrySet().iterator(); entryIt.hasNext();) { 275 Map.Entry entry = (Map.Entry ) entryIt.next(); 276 TestCase test = (TestCase) entry.getKey(); 277 List results = (List ) entry.getValue(); 278 BenchmarkXml xml = new BenchmarkXml(test, results); 279 Element categoryElement = getCategoryElement(doc, report, 280 xml.metaData.getCategory().getClassName()); 281 categoryElement.appendChild(xml.toElement(doc)); 282 } 283 284 return report; 285 } 286 287 293 private Element getCategoryElement(Document doc, Element report, String name) { 294 Element e = (Element ) categoryElementMap.get(name); 295 296 if (e != null) { 297 return e; 298 } 299 300 Element categoryElement = doc.createElement("category"); 301 categoryElementMap.put(name, categoryElement); 302 CategoryImpl category = (CategoryImpl) testCategories.get(name); 303 categoryElement.setAttribute("name", category.getName()); 304 categoryElement.setAttribute("description", category.getDescription()); 305 306 report.appendChild(categoryElement); 307 308 return categoryElement; 309 } 310 } 311 312 private static final String GWT_BENCHMARK_CATEGORY = "gwt.benchmark.category"; 313 314 private static final String GWT_BENCHMARK_DESCRIPTION = "gwt.benchmark.description"; 315 316 private static final String GWT_BENCHMARK_NAME = "gwt.benchmark.name"; 317 318 private static File findSourceFile(JClassType klass) { 319 final char separator = File.separator.charAt(0); 320 String filePath = klass.getPackage().getName().replace('.', separator) 321 + separator + klass.getSimpleSourceName() + ".java"; 322 String [] paths = getClassPath(); 323 324 for (int i = 0; i < paths.length; ++i) { 325 File maybeSourceFile = new File (paths[i] + separator + filePath); 326 327 if (maybeSourceFile.exists()) { 328 return maybeSourceFile; 329 } 330 } 331 332 return null; 333 } 334 335 private static String [] getClassPath() { 336 String path = System.getProperty("java.class.path"); 337 return path.split(File.pathSeparator); 338 } 339 340 private static String getSimpleMetaData(HasMetaData hasMetaData, String name) { 341 String [][] allValues = hasMetaData.getMetaData(name); 342 343 if (allValues == null) { 344 return null; 345 } 346 347 StringBuffer result = new StringBuffer (); 348 349 for (int i = 0; i < allValues.length; ++i) { 350 String [] values = allValues[i]; 351 for (int j = 0; j < values.length; ++j) { 352 result.append(values[j]); 353 result.append(" "); 354 } 355 } 356 357 String resultString = result.toString().trim(); 358 return resultString.equals("") ? null : resultString; 359 } 360 361 private static char[] read(File f) throws IOException { 362 365 BufferedReader reader = new BufferedReader (new FileReader (f)); 366 StringBuffer source = new StringBuffer ((int) f.length()); 367 368 while (true) { 369 String line = reader.readLine(); 370 if (line == null) { 371 break; 372 } 373 source.append(line); 374 source.append("\n"); 375 } 376 377 char[] buf = new char[source.length()]; 378 source.getChars(0, buf.length, buf, 0); 379 380 return buf; 381 } 382 383 private Map testCategories = new HashMap (); 384 385 private Map testMetaData = new HashMap (); 386 387 private Map testResults = new HashMap (); 388 389 private TypeOracle typeOracle; 390 391 private TreeLogger logger; 392 393 public BenchmarkReport(TreeLogger logger) { 394 this.logger = logger; 395 } 396 397 401 public void addBenchmark(JClassType benchmarkClass, TypeOracle typeOracle) { 402 403 this.typeOracle = typeOracle; 404 String categoryType = getSimpleMetaData(benchmarkClass, 405 GWT_BENCHMARK_CATEGORY); 406 407 Map zeroArgMethods = BenchmarkGenerator.getNotOverloadedTestMethods(benchmarkClass); 408 Map parameterizedMethods = BenchmarkGenerator.getParameterizedTestMethods( 409 benchmarkClass, TreeLogger.NULL); 410 List testMethods = new ArrayList ( 411 zeroArgMethods.size() + parameterizedMethods.size()); 412 testMethods.addAll(zeroArgMethods.values()); 413 testMethods.addAll(parameterizedMethods.values()); 414 415 Map metaDataMap = (Map ) testMetaData.get(benchmarkClass.toString()); 416 if (metaDataMap == null) { 417 metaDataMap = new HashMap (); 418 testMetaData.put(benchmarkClass.toString(), metaDataMap); 419 } 420 421 Parser parser = null; 422 423 try { 424 parser = new Parser(benchmarkClass); 425 } catch (IOException e) { 426 logger.log(TreeLogger.WARN, "Unable to parse the code for " 429 + benchmarkClass, e); 430 } 431 432 for (int i = 0; i < testMethods.size(); ++i) { 434 JMethod method = (JMethod) testMethods.get(i); 435 String methodName = method.getName(); 436 String methodCategoryType = getSimpleMetaData(method, 437 GWT_BENCHMARK_CATEGORY); 438 if (methodCategoryType == null) { 439 methodCategoryType = categoryType; 440 } 441 CategoryImpl methodCategory = getCategory(methodCategoryType); 442 StringBuffer sourceCode = parser == null ? null : new StringBuffer ( 443 parser.getMethod(method)); 444 StringBuffer summary = new StringBuffer (); 445 StringBuffer comment = new StringBuffer (); 446 getComment(sourceCode, summary, comment); 447 448 MetaData metaData = new MetaData(benchmarkClass.toString(), methodName, 449 sourceCode != null ? sourceCode.toString() : null, methodCategory, 450 methodName, summary.toString()); 451 metaDataMap.put(methodName, metaData); 452 } 453 } 454 455 public void addBenchmarkResults(TestCase test, TestResults results) { 456 List currentResults = (List ) testResults.get(test); 457 if (currentResults == null) { 458 currentResults = new ArrayList (); 459 testResults.put(test, currentResults); 460 } 461 currentResults.add(results); 462 } 463 464 473 public void generate(String outputPath) throws ParserConfigurationException , 474 IOException { 475 476 if (testResults.size() == 0) { 478 return; 479 } 480 481 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 482 DocumentBuilder builder = factory.newDocumentBuilder(); 483 Document doc = builder.newDocument(); 484 doc.appendChild(new ReportXml().toElement(doc)); 485 byte[] xmlBytes = Util.toXmlUtf8(doc); 486 FileOutputStream fos = null; 487 try { 488 fos = new FileOutputStream (outputPath); 489 fos.write(xmlBytes); 490 } finally { 491 Utility.close(fos); 492 } 493 494 496 } 512 513 private CategoryImpl getCategory(String name) { 514 CategoryImpl c = (CategoryImpl) testCategories.get(name); 515 516 if (c != null) { 517 return c; 518 } 519 520 String categoryName = ""; 521 String categoryDescription = ""; 522 523 if (name != null) { 524 JClassType categoryType = typeOracle.findType(name); 525 526 if (categoryType != null) { 527 categoryName = getSimpleMetaData(categoryType, GWT_BENCHMARK_NAME); 528 categoryDescription = getSimpleMetaData(categoryType, 529 GWT_BENCHMARK_DESCRIPTION); 530 } 531 } 532 533 c = new CategoryImpl(name, categoryName, categoryDescription); 534 testCategories.put(name, c); 535 return c; 536 } 537 538 543 private void getComment(StringBuffer sourceCode, StringBuffer summary, 544 StringBuffer comment) { 545 546 if (sourceCode == null) { 547 return; 548 } 549 550 summary.setLength(0); 551 comment.setLength(0); 552 553 String regex = "/\\*\\*(.(?!}-\\*/))*\\*/"; 554 555 Pattern p = Pattern.compile(regex, Pattern.DOTALL); 556 Matcher m = p.matcher(sourceCode); 557 558 if (!m.find()) { 560 return; 561 } 562 563 String commentStr = m.group(); 564 565 p = Pattern.compile("(/\\*\\*\\s*)" + "(((\\s*\\**\\s*)([^\n\r]*)[\n\r]+)*)" ); 568 569 m = p.matcher(commentStr); 570 571 if (!m.find()) { 572 return; 573 } 574 575 String stripped = m.group(2); 576 577 p = Pattern.compile("^\\p{Blank}*\\**\\p{Blank}*", Pattern.MULTILINE); 578 String bareComment = p.matcher(stripped).replaceAll(""); 579 580 BreakIterator iterator = BreakIterator.getSentenceInstance(); 581 iterator.setText(bareComment); 582 int firstSentenceEnd = iterator.next(); 583 if (firstSentenceEnd == BreakIterator.DONE) { 584 summary.append(bareComment); 585 } else { 586 summary.append(bareComment.substring(0, firstSentenceEnd)); 587 } 588 589 comment.append(bareComment); 590 591 p = Pattern.compile("[^\\r\\n]+[\\r\\n]+(\\s+)\\*", Pattern.MULTILINE); 594 m = p.matcher(sourceCode); 595 int indentLen = 0; 596 if (m.find()) { 597 String indent = m.group(1); 598 indentLen = indent.length() - 1; 599 } 600 StringBuffer leadingIndent = new StringBuffer (); 601 for (int i = 0; i < indentLen; ++i) { 602 leadingIndent.append(' '); 603 } 604 605 sourceCode.insert(0, leadingIndent); 610 } 611 } 612 | Popular Tags |