From d08b27fa9701fecfdb69e1b0d1ac2459efc2129b Mon Sep 17 00:00:00 2001 From: Han-Wen Nienhuys Date: Wed, 25 Feb 2015 16:45:20 +0100 Subject: Update from Google. -- MOE_MIGRATED_REVID=85702957 --- .../build/lib/profiler/chart/HtmlChartVisitor.java | 368 +++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 src/main/java/com/google/devtools/build/lib/profiler/chart/HtmlChartVisitor.java (limited to 'src/main/java/com/google/devtools/build/lib/profiler/chart/HtmlChartVisitor.java') diff --git a/src/main/java/com/google/devtools/build/lib/profiler/chart/HtmlChartVisitor.java b/src/main/java/com/google/devtools/build/lib/profiler/chart/HtmlChartVisitor.java new file mode 100644 index 0000000000..8fa3d0e48b --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/profiler/chart/HtmlChartVisitor.java @@ -0,0 +1,368 @@ +// Copyright 2014 Google Inc. All rights reserved. +// +// 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.devtools.build.lib.profiler.chart; + +import com.google.devtools.build.lib.profiler.ProfilePhaseStatistics; + +import java.io.PrintStream; +import java.util.List; + +/** + * {@link ChartVisitor} that builds HTML from the visited chart and prints it + * out to the given {@link PrintStream}. + */ +public class HtmlChartVisitor implements ChartVisitor { + + /** The default width of a second in the chart. */ + private static final int DEFAULT_PIXEL_PER_SECOND = 50; + + /** The horizontal offset of second zero. */ + private static final int H_OFFSET = 40; + + /** The font size of the row labels. */ + private static final int ROW_LABEL_FONT_SIZE = 7; + + /** The height of a bar in pixels. */ + private static final int BAR_HEIGHT = 8; + + /** The space between twp bars in pixels. */ + private static final int BAR_SPACE = 2; + + /** The height of a row. */ + private static final int ROW_HEIGHT = BAR_HEIGHT + BAR_SPACE; + + /** The {@link PrintStream} to output the HTML to. */ + private final PrintStream out; + + /** The maxmimum stop time of any bar in the chart. */ + private long maxStop; + + /** The width of a second in the chart. */ + private final int pixelsPerSecond; + + /** + * Creates the visitor, with a default width of a second of 50 pixels. + * + * @param out the {@link PrintStream} to output the HTML to + */ + public HtmlChartVisitor(PrintStream out) { + this(out, DEFAULT_PIXEL_PER_SECOND); + } + + /** + * Creates the visitor. + * + * @param out the {@link PrintStream} to output the HTML to + * @param pixelsPerSecond The width of a second in the chart. (In pixels) + */ + public HtmlChartVisitor(PrintStream out, int pixelsPerSecond) { + this.out = out; + this.pixelsPerSecond = pixelsPerSecond; + } + + @Override + public void visit(Chart chart) { + maxStop = chart.getMaxStop(); + out.println(""); + out.printf("%s", chart.getTitle()); + out.println(""); + out.println(""); + out.println(""); + + heading(chart.getTitle(), 1); + + printContentBox(); + + heading("Tasks", 2); + out.println("

To get more information about a task point the mouse at one of the bars.

"); + + out.printf("
\n", + chart.getRowCount() * ROW_HEIGHT, H_OFFSET + 10); + } + + @Override + public void endVisit(Chart chart) { + printTimeAxis(chart); + out.println("
"); + + heading("Legend", 2); + printLegend(chart.getSortedTypes()); + + heading("Statistics", 2); + printStatistics(chart.getStatistics()); + + out.println(""); + out.println(""); +} + + @Override + public void visit(ChartColumn column) { + int width = scale(column.getWidth()); + if (width == 0) { + return; + } + int left = scale(column.getStart()); + int height = column.getRowCount() * ROW_HEIGHT; + String style = chartTypeNameAsCSSClass(column.getType().getName()); + box(left, 0, width, height, style, column.getLabel(), 10); + } + + + @Override + public void visit(ChartRow slot) { + String style = slot.getIndex() % 2 == 0 ? "shade-even" : "shade-odd"; + int top = slot.getIndex() * ROW_HEIGHT; + int width = scale(maxStop) + 1; + + label(-H_OFFSET, top, width + H_OFFSET, ROW_HEIGHT, ROW_LABEL_FONT_SIZE, slot.getId()); + box(0, top, width, ROW_HEIGHT, style, "", 0); + } + + @Override + public void visit(ChartBar bar) { + int width = scale(bar.getWidth()); + if (width == 0) { + return; + } + int left = scale(bar.getStart()); + int top = bar.getRow().getIndex() * ROW_HEIGHT; + String style = chartTypeNameAsCSSClass(bar.getType().getName()); + if (bar.getHighlight()) { + style += "-highlight"; + } + box(left, top + 2, width, BAR_HEIGHT, style, bar.getLabel(), 20); + } + + @Override + public void visit(ChartLine chartLine) { + int start = chartLine.getStartRow().getIndex() * ROW_HEIGHT; + int stop = chartLine.getStopRow().getIndex() * ROW_HEIGHT; + int time = scale(chartLine.getStartTime()); + + if (start < stop) { + verticalLine(time, start + 1, 1, (stop - start) + ROW_HEIGHT, Color.RED); + } else { + verticalLine(time, stop + 1, 1, (start - stop) + ROW_HEIGHT, Color.RED); + } + } + + /** + * Converts the given value from the bar of the chart to pixels. + */ + private int scale(long value) { + return (int) (value / (1000000000L / pixelsPerSecond)); + } + + /** + * Prints a box with links to the sections of the generated HTML document. + */ + private void printContentBox() { + out.println("

Content

"); + out.println("

" + + "Tasks

"); + out.println("

" + + "Legend

"); + out.println("

" + + "Statistics

"); + } + + /** + * Prints the time axis of the chart and vertical lines for every second. + */ + private void printTimeAxis(Chart chart) { + int location = 0; + int second = 0; + int end = scale(chart.getMaxStop()); + while (location < end) { + label(location + 4, -17, pixelsPerSecond, ROW_HEIGHT, 0, second + "s"); + verticalLine(location, -20, 1, chart.getRowCount() * ROW_HEIGHT + 20, Color.GRAY); + location += pixelsPerSecond; + second += 1; + } + } + + private void printCss(List types) { + out.println("body { font-family: Sans; }"); + out.printf("div.shade-even { position:absolute; border: 0px; background-color:#dddddd }\n"); + out.printf("div.shade-odd { position:absolute; border: 0px; background-color:#eeeeee }\n"); + for (ChartBarType type : types) { + String name = chartTypeNameAsCSSClass(type.getName()); + String color = formatColor(type.getColor()); + + out.printf( + "div.%s-border { position:absolute; border:1px solid grey; background-color:%s }\n", + name, color); + out.printf( + "div.%s-highlight { position:absolute; border:1px solid red; background-color:%s }\n", + name, color); + out.printf("div.%s { position:absolute; border:0px; margin:1px; background-color:%s }\n", + name, color); + } + } + + /** + * Prints the legend for the chart at the current position in the document. The + * legend is printed in columns of 10 rows each. + * + * @param types the list of {@link ChartBarType}s to print in the legend. + */ + private void printLegend(List types) { + final int boxHeight = 20; + final int lineHeight = 25; + final int entriesPerColumn = 10; + final int legendWidth = 350; + int legendHeight; + if (types.size() / entriesPerColumn >= 1) { + legendHeight = entriesPerColumn; + } else { + legendHeight = types.size() % entriesPerColumn; + } + + out.printf("
", + (legendHeight + 1) * lineHeight); + + int left = -legendWidth; + int top; + int i = 0; + for (ChartBarType type : types) { + if (i % entriesPerColumn == 0) { + left += legendWidth; + i = 0; + } + top = lineHeight * i; + String style = chartTypeNameAsCSSClass(type.getName()) + "-border"; + box(left, top, boxHeight, boxHeight, style, type.getName(), 0); + label(left + lineHeight + 10, top, legendWidth - 10, boxHeight, 0, type.getName()); + i++; + } + out.println("
"); + } + + private void printStatistics(List statistics) { + boolean first = true; + + out.println(""); + for (ProfilePhaseStatistics stat : statistics) { + if (!first) { + out.println(""); + } else { + first = false; + } + out.println(""); + } + out.println("
 
"); + String title = stat.getTitle(); + if (title != "") { + heading(title, 3); + } + out.println("
" + stat.getStatistics() + "
"); + } + + /** + * Prints a head-line at the current position in the document. + * + * @param text the text to print + * @param level the headline level + */ + private void heading(String text, int level) { + anchor(text); + out.printf("%s\n", level, text, level); + } + + /** + * Prints a box with the given location, size, background color and border. + * + * @param x the x location of the top left corner of the box + * @param y the y location of the top left corner of the box + * @param width the width location of the box + * @param height the height location of the box + * @param style the CSS style class to use for the box + * @param title the text displayed when the mouse hovers over the box + */ + private void box(int x, int y, int width, int height, String style, String title, int zIndex) { + out.printf("
\n", + style, title, x, y, width, height, zIndex); + } + + /** + * Prints a label with the given location, size, background color and border. + * + * @param x the x location of the top left corner of the box + * @param y the y location of the top left corner of the box + * @param width the width location of the box + * @param height the height location of the box + * @param fontSize the font size of text in the box, 0 for default + * @param text the text displayed in the box + */ + private void label(int x, int y, int width, int height, int fontSize, String text) { + if (fontSize > 0) { + out.printf("
%s
\n", + x, y, width, height, fontSize, text); + } else { + out.printf("
%s
\n", + x, y, width, height, text); + } + } + + /** + * Prints a vertical line of given width, height and color at the given + * location. + * + * @param x the x location of the start point of the line + * @param y the y location of the start point of the line + * @param width the width of the line + * @param length the length of the line + * @param color the color of the line + */ + private void verticalLine(int x, int y, int width, int length, Color color) { + out.printf("
\n", + x, y, width, length, width, formatColor(color)); + } + + /** + * Prints an HTML anchor with the given name, + */ + private void anchor(String name) { + out.println(""); + } + + /** + * Formats the given {@link Color} to a css style color string. + */ + private String formatColor(Color color) { + int r = color.getRed(); + int g = color.getGreen(); + int b = color.getBlue(); + int a = color.getAlpha(); + + return String.format("rgba(%d,%d,%d,%f)", r, g, b, (a / 255.0)); + } + + /** + * Transform the name into a form suitable as a css class. + */ + private String chartTypeNameAsCSSClass(String name) { + return name.replace(' ', '_'); + } +} -- cgit v1.2.3