/* * Copyright 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.google.gwt.benchmarks.viewer.client; import com.google.gwt.core.client.EntryPoint; import com.google.gwt.core.client.GWT; import com.google.gwt.http.client.URL; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.Element; import com.google.gwt.user.client.History; import com.google.gwt.user.client.HistoryListener; import com.google.gwt.user.client.rpc.AsyncCallback; import com.google.gwt.user.client.ui.Button; import com.google.gwt.user.client.ui.CellPanel; import com.google.gwt.user.client.ui.ClickListener; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.HasHorizontalAlignment; import com.google.gwt.user.client.ui.HasVerticalAlignment; import com.google.gwt.user.client.ui.HorizontalPanel; import com.google.gwt.user.client.ui.Hyperlink; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.SourcesTableEvents; import com.google.gwt.user.client.ui.TableListener; import com.google.gwt.user.client.ui.VerticalPanel; import com.google.gwt.user.client.ui.Widget; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; /** * The application for viewing benchmark reports. In order for the ReportViewer * to operate correctly, you must have both the {@link ReportServer} RPC and * {@link com.google.gwt.junit.viewer.server.ReportImageServer} servlets up and * running within a servlet container. * * <code>ReportViewer's</code> GWT XML module is configured to start these * servlets by default. Just start <code>ReportViewer</code> in hosted mode, and * GWT will run them within its own embedded servlet engine. For example, * * <pre>java -cp <classpath> com.google.gwt.dev.GWTShell -out * ReportViewerShell/www * com.google.gwt.junit.viewer.ReportViewer/ReportViewer.html</pre> * * You can configure the location where ReportServer reads the benchmark reports * from by setting the system property named in * {@link com.google.gwt.benchmarks.client.Benchmark#REPORT_PATH}. */ @SuppressWarnings("deprecation") public class ReportViewer implements EntryPoint, HistoryListener { private static class MutableBool { boolean value; MutableBool(boolean value) { this.value = value; } } private class SummariesTableListener implements TableListener { public void onCellClicked(SourcesTableEvents sender, int row, int col) { if (row > 0) { ReportSummary summary = summaries.get(row - 1); String token = summary.getId(); // Short circuit the history loop. selectReport(row, token); History.newItem(token); } } } private static final String imageServer = GWT.getModuleBaseURL() + "test_images/"; HTML detailsLabel; Report report; VerticalPanel reportPanel; ReportServerAsync reportServer; FlexTable reportTable; HTML statusLabel; List<ReportSummary> summaries; VerticalPanel summariesPanel; FlexTable summariesTable; CellPanel topPanel; private int currentSelectedRow; private String currentToken; public void onHistoryChanged(String token) { assert (summaries != null); int row = 1; for (ReportSummary summary : summaries) { if (summary.getId().equals(token)) { selectReport(row, token); return; } ++row; } selectReport(0, token); } public void onModuleLoad() { init(); // Asynchronously load the summaries reportServer = (ReportServerAsync) GWT.create(ReportServer.class); reportServer.getReportSummaries(new AsyncCallback<List<ReportSummary>>() { public void onFailure(Throwable caught) { String msg = "<p>" + caught.toString() + "</p>" + "<p>Is your path to the reports correct?</p>"; statusLabel.setHTML(msg); } public void onSuccess(List<ReportSummary> result) { summaries = result; if (summaries != null) { if (summaries.size() == 0) { statusLabel.setText("There are no benchmark reports available in this folder."); } Collections.sort(summaries, new Comparator<ReportSummary>() { public int compare(ReportSummary r1, ReportSummary r2) { return r2.getDate().compareTo(r1.getDate()); // most recent first } }); displaySummaries(); // If there's an initial URL, browse to it. onHistoryChanged(History.getToken()); History.addHistoryListener(ReportViewer.this); } } }); } protected void selectReport(int row, String token) { if (row == currentSelectedRow && token.equals(currentToken)) { return; } if (currentSelectedRow != -1) { summariesTable.getRowFormatter().removeStyleName(currentSelectedRow, "viewer-SelectedRow"); } currentToken = token; currentSelectedRow = row; if (row < 1) { clearReport(); } else { fetchReport(row, token); } } private void clearReport() { statusLabel.setText("Select a report."); detailsLabel.setHTML("<h3>Report Details</h3>"); reportPanel.remove(reportTable); } private FlexTable createReportTable() { FlexTable topTable = new FlexTable(); FlexTable tempReportTable = new FlexTable(); tempReportTable.setBorderWidth(1); tempReportTable.setCellPadding(5); tempReportTable.setWidget(0, 0, new Label("Date Created")); tempReportTable.setWidget(0, 1, new Label("GWT Version")); if (report == null) { tempReportTable.setWidget(1, 0, new Label("No currently selected report.")); tempReportTable.getFlexCellFormatter().setColSpan(1, 0, 3); return tempReportTable; } detailsLabel.setHTML("<h3>" + report.getId() + " details </h3>"); tempReportTable.setWidget(1, 0, new Label(report.getDateString())); tempReportTable.setWidget(1, 1, new Label(report.getGwtVersion())); // topTable.setWidget( 0, 0, tempReportTable ); int currentRow = 1; Collections.sort(report.getCategories(), new Comparator<Category>() { public int compare(Category c1, Category c2) { return c1.getName().compareTo(c2.getName()); } }); // Should be done once in the RPC for (int i = 0; i < report.getCategories().size(); ++i) { Category c = report.getCategories().get(i); if (!c.getName().equals("")) { FlexTable categoryTable = new FlexTable(); categoryTable.setBorderWidth(0); categoryTable.setCellPadding(5); categoryTable.setText(0, 0, c.getName()); categoryTable.getFlexCellFormatter().setStyleName(0, 0, "benchmark-category"); categoryTable.setWidget(0, 1, new Label("Description")); categoryTable.setWidget(1, 0, new Label(c.getName())); categoryTable.setWidget(1, 1, new Label(c.getDescription())); topTable.setWidget(currentRow++, 0, categoryTable); } Collections.sort(c.getBenchmarks(), new Comparator<Benchmark>() { public int compare(Benchmark b1, Benchmark b2) { return b1.getName().compareTo(b2.getName()); } }); // Should be done once in the RPC for (int j = 0; j < c.getBenchmarks().size(); ++j) { Benchmark benchmark = c.getBenchmarks().get(j); FlexTable benchmarkTable = new FlexTable(); benchmarkTable.setBorderWidth(0); benchmarkTable.setCellPadding(5); benchmarkTable.setText(0, 0, benchmark.getName()); // benchmarkTable.setText(0, 1, benchmark.getDescription()); String codeHtml; String sourceText = benchmark.getSourceCode(); if (sourceText != null) { Element tempElem = DOM.createDiv(); DOM.setInnerText(tempElem, sourceText); String escapedCodeHtml = DOM.getInnerHTML(tempElem); codeHtml = "<pre>" + escapedCodeHtml + "</pre>"; } else { codeHtml = "<i>(source not available)</i>"; } benchmarkTable.setWidget(1, 0, new HTML(codeHtml)); benchmarkTable.getFlexCellFormatter().setStyleName(0, 0, "benchmark-name"); // benchmarkTable.getFlexCellFormatter().setStyleName( 0, 1, // "benchmark-description" ); benchmarkTable.getFlexCellFormatter().setStyleName(1, 0, "benchmark-code"); // TODO(tobyr) Provide detailed benchmark information. // Following bits of commented code are steps in that direction. /* * benchmarkTable.setWidget( 0, 1, new Label( "Description")); * benchmarkTable.setWidget( 0, 2, new Label( "Class Name")); * benchmarkTable.setWidget( 0, 3, new Label( "Source Code")); * benchmarkTable.setWidget( 1, 0, new Label( benchmark.getName())); * benchmarkTable.setWidget( 1, 1, new Label( * benchmark.getDescription())); benchmarkTable.setWidget( 1, 2, new * Label( benchmark.getClassName())); benchmarkTable.setWidget( 1, 3, * new HTML( "<pre>" + benchmark.getSourceCode() + "</pre>")); */ topTable.setWidget(currentRow++, 0, benchmarkTable); FlexTable resultsTable = new FlexTable(); resultsTable.setBorderWidth(0); resultsTable.setCellPadding(5); FlexTable.FlexCellFormatter resultsFormatter = resultsTable.getFlexCellFormatter(); topTable.setWidget(currentRow++, 0, resultsTable); Collections.sort(benchmark.getResults(), new Comparator<Result>() { public int compare(Result r1, Result r2) { return r1.getAgent().compareTo(r2.getAgent()); } }); // Should be done once in the RPC final List<FlexTable> trialsTables = new ArrayList<FlexTable>(); int numVariables = 0; List<String> variableNames = null; if (benchmark.getResults().size() > 0) { Result sampleResult = benchmark.getResults().get(0); if (sampleResult.getTrials().size() > 0) { Trial sampleTrial = sampleResult.getTrials().get(0); numVariables = sampleTrial.getVariables().size(); Map<String, String> variables = sampleTrial.getVariables(); variableNames = new ArrayList<String>(variables.keySet()); Collections.sort(variableNames); } } final MutableBool isVisible = new MutableBool(numVariables > 2); String buttonName = isVisible.value ? "Hide Data" : "Show Data"; Button visibilityButton = new Button(buttonName, new ClickListener() { public void onClick(Widget sender) { isVisible.value = !isVisible.value; for (int i = 0; i < trialsTables.size(); ++i) { Widget w = trialsTables.get(i); w.setVisible(isVisible.value); } String name = isVisible.value ? "Hide Data" : "Show Data"; ((Button) sender).setText(name); } }); for (int k = 0; k < benchmark.getResults().size(); ++k) { Result result = benchmark.getResults().get(k); // Currently only support graphs for results of 2 variables or less if (numVariables <= 2) { resultsTable.setWidget(0, k, new Image(getImageUrl(report.getId(), c.getName(), benchmark.getClassName(), benchmark.getName(), result.getAgent()))); } else { if (k == 0) { resultsTable.setHTML(0, k, "<b>" + BrowserInfo.getBrowser(result.getAgent()) + "</b><br><font size=\"-1\">(Graphs are not yet available " + "for benchmarks with more than two parameters)</font>"); } } /* * FlexTable allTrialsTable = new FlexTable(); * allTrialsTable.setBorderWidth(1); allTrialsTable.setCellPadding(5); * FlexTable.CellFormatter allTrialsFormatter = allTrialsTable * .getFlexCellFormatter(); topTable.setWidget(currentRow++, 0, * allTrialsTable); allTrialsTable.setWidget(0, k, trialsTable); * allTrialsFormatter .setAlignment(0, k, * HasHorizontalAlignment.ALIGN_CENTER, * HasVerticalAlignment.ALIGN_TOP); */ resultsFormatter.setAlignment(2, k, HasHorizontalAlignment.ALIGN_LEFT, HasVerticalAlignment.ALIGN_TOP); // A table of straight data for all trials for an agent FlexTable trialsTable = new FlexTable(); trialsTable.setVisible(isVisible.value); trialsTables.add(trialsTable); trialsTable.setBorderWidth(1); trialsTable.setCellPadding(5); if (k == 0) { resultsTable.setWidget(1, k, visibilityButton); resultsFormatter.setColSpan(1, k, benchmark.getResults().size()); resultsFormatter.setAlignment(1, k, HasHorizontalAlignment.ALIGN_LEFT, HasVerticalAlignment.ALIGN_MIDDLE); } resultsTable.setWidget(2, k, trialsTable); // Write out the variable column headers for (int varIndex = 0; varIndex < numVariables; ++varIndex) { String varName = variableNames.get(varIndex); trialsTable.setHTML(0, varIndex, varName); } // Timing header trialsTable.setHTML(0, numVariables, "Timing (ms)"); // Write out all the trial data int l = 0; for (Trial trial : result.getTrials()) { // Write the variable values for (int varIndex = 0; varIndex < numVariables; ++varIndex) { String varName = variableNames.get(varIndex); String varValue = trial.getVariables().get(varName); trialsTable.setHTML(l + 1, varIndex, varValue); } // Write out the timing data String data = trial.getRunTimeMillis() + ""; trialsTable.setHTML(l + 1, numVariables, data); ++l; } if (result.getException() != null) { trialsTable.setHTML(l + 1, numVariables, result.getException()); } } } } return topTable; } private FlexTable createSummariesTable() { FlexTable tempSummariesTable = new FlexTable(); tempSummariesTable.addStyleName("viewer-List"); tempSummariesTable.setCellPadding(5); tempSummariesTable.setBorderWidth(1); tempSummariesTable.setCellSpacing(0); tempSummariesTable.setWidget(0, 0, new Label("Report")); tempSummariesTable.setWidget(0, 1, new Label("Date Created")); tempSummariesTable.setWidget(0, 2, new Label("Tests")); tempSummariesTable.getRowFormatter().addStyleName(0, "viewer-ListHeader"); if (summaries == null) { tempSummariesTable.setWidget(1, 0, new Label("Fetching reports...")); tempSummariesTable.getFlexCellFormatter().setColSpan(1, 0, 4); return tempSummariesTable; } for (int i = 0; i < summaries.size(); ++i) { ReportSummary summary = summaries.get(i); int index = i + 1; tempSummariesTable.setWidget(index, 0, new Hyperlink(summary.getId(), summary.getId())); tempSummariesTable.setWidget(index, 1, new Label(summary.getDateString())); tempSummariesTable.setWidget(index, 2, new Label(String.valueOf(summary.getNumTests()))); } tempSummariesTable.addTableListener(new SummariesTableListener()); return tempSummariesTable; } private void displayReport() { FlexTable table = createReportTable(); reportPanel.remove(reportTable); reportTable = table; reportPanel.insert(reportTable, 1); } private void displaySummaries() { FlexTable table = createSummariesTable(); summariesPanel.remove(summariesTable); summariesTable = table; summariesPanel.insert(summariesTable, 1); } private String encode(String str) { if (str.equals("")) { return str; } return URL.encodeComponent(str); } private void fetchReport(int row, String token) { summariesTable.getRowFormatter().addStyleName(row, "viewer-SelectedRow"); statusLabel.setText("Retrieving the report..."); reportServer.getReport(token, new AsyncCallback<Report>() { public void onFailure(Throwable caught) { statusLabel.setText(caught.toString()); } public void onSuccess(Report result) { report = result; statusLabel.setText("Finished fetching report details."); displayReport(); } }); } private String getImageUrl(String report, String category, String testClass, String testMethod, String agent) { return imageServer + encode(report) + "/" + encode(category) + "/" + encode(testClass) + "/" + encode(testMethod) + "/" + encode(agent); } private void init() { topPanel = new VerticalPanel(); summariesPanel = new VerticalPanel(); summariesPanel.add(new HTML("<h3>Benchmark Reports</h3>")); summariesTable = createSummariesTable(); summariesPanel.add(summariesTable); reportPanel = new VerticalPanel(); detailsLabel = new HTML(); reportPanel.add(detailsLabel); reportTable = createReportTable(); // reportPanel.add( reportTable ); topPanel.add(summariesPanel); CellPanel spacerPanel = new HorizontalPanel(); spacerPanel.setSpacing(10); spacerPanel.add(new Label()); topPanel.add(spacerPanel); topPanel.add(reportPanel); final RootPanel root = RootPanel.get(); root.add(topPanel); statusLabel = new HTML(); root.add(statusLabel); selectReport(0, ""); } }