123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- /*
- * Copyright 2000-2014 Vaadin Ltd.
- *
- * 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.vaadin.client.debug.internal;
-
- import java.util.Collection;
- import java.util.Collections;
- import java.util.LinkedHashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.Set;
-
- import com.google.gwt.user.client.ui.FlowPanel;
- import com.google.gwt.user.client.ui.HorizontalPanel;
- import com.google.gwt.user.client.ui.Label;
- import com.google.gwt.user.client.ui.Widget;
- import com.vaadin.client.ApplicationConnection;
- import com.vaadin.client.Profiler;
- import com.vaadin.client.SimpleTree;
- import com.vaadin.client.ValueMap;
-
- /**
- * Debug window section for investigating {@link Profiler} data. This section is
- * only visible if the profiler is enabled ({@link Profiler#isEnabled()}).
- *
- * @since 7.1
- * @author Vaadin Ltd
- *
- * @see Profiler
- */
- public class ProfilerSection implements Section {
- /**
- * Interface for getting data from the {@link Profiler}.
- * <p>
- * <b>Warning!</b> This interface is most likely to change in the future and
- * is therefore defined in this class in an internal package instead of
- * Profiler where it might seem more logical.
- *
- * @since 7.1
- * @author Vaadin Ltd
- */
- public interface ProfilerResultConsumer {
- public void addProfilerData(Node rootNode, List<Node> totals);
-
- public void addBootstrapData(LinkedHashMap<String, Double> timings);
- }
-
- /**
- * A hierarchical representation of the time spent running a named block of
- * code.
- * <p>
- * <b>Warning!</b> This class is most likely to change in the future and is
- * therefore defined in this class in an internal package instead of
- * Profiler where it might seem more logical.
- */
- public static class Node {
- private final String name;
- private final LinkedHashMap<String, Node> children = new LinkedHashMap<String, Node>();
- private double time = 0;
- private int count = 0;
- private double enterTime = 0;
- private double minTime = 1000000000;
- private double maxTime = 0;
-
- /**
- * Create a new node with the given name.
- *
- * @param name
- */
- public Node(String name) {
- this.name = name;
- }
-
- /**
- * Gets the name of the node
- *
- * @return the name of the node
- */
- public String getName() {
- return name;
- }
-
- /**
- * Creates a new child node or retrieves and existing child and updates
- * its total time and hit count.
- *
- * @param name
- * the name of the child
- * @param timestamp
- * the timestamp for when the node is entered
- * @return the child node object
- */
- public Node enterChild(String name, double timestamp) {
- Node child = children.get(name);
- if (child == null) {
- child = new Node(name);
- children.put(name, child);
- }
- child.enterTime = timestamp;
- child.count++;
- return child;
- }
-
- /**
- * Gets the total time spent in this node, including time spent in sub
- * nodes
- *
- * @return the total time spent, in milliseconds
- */
- public double getTimeSpent() {
- return time;
- }
-
- /**
- * Gets the minimum time spent for one invocation of this node,
- * including time spent in sub nodes
- *
- * @return the time spent for the fastest invocation, in milliseconds
- */
- public double getMinTimeSpent() {
- return minTime;
- }
-
- /**
- * Gets the maximum time spent for one invocation of this node,
- * including time spent in sub nodes
- *
- * @return the time spent for the slowest invocation, in milliseconds
- */
- public double getMaxTimeSpent() {
- return maxTime;
- }
-
- /**
- * Gets the number of times this node has been entered
- *
- * @return the number of times the node has been entered
- */
- public int getCount() {
- return count;
- }
-
- /**
- * Gets the total time spent in this node, excluding time spent in sub
- * nodes
- *
- * @return the total time spent, in milliseconds
- */
- public double getOwnTime() {
- double time = getTimeSpent();
- for (Node node : children.values()) {
- time -= node.getTimeSpent();
- }
- return time;
- }
-
- /**
- * Gets the child nodes of this node
- *
- * @return a collection of child nodes
- */
- public Collection<Node> getChildren() {
- return Collections.unmodifiableCollection(children.values());
- }
-
- private void buildRecursiveString(StringBuilder builder, String prefix) {
- if (getName() != null) {
- String msg = getStringRepresentation(prefix);
- builder.append(msg + '\n');
- }
- String childPrefix = prefix + "*";
- for (Node node : children.values()) {
- node.buildRecursiveString(builder, childPrefix);
- }
- }
-
- @Override
- public String toString() {
- return getStringRepresentation("");
- }
-
- public String getStringRepresentation(String prefix) {
- if (getName() == null) {
- return "";
- }
- String msg = prefix + " " + getName() + " in " + getTimeSpent()
- + " ms.";
- if (getCount() > 1) {
- msg += " Invoked "
- + getCount()
- + " times ("
- + roundToSignificantFigures(getTimeSpent() / getCount())
- + " ms per time, min "
- + roundToSignificantFigures(getMinTimeSpent())
- + " ms, max "
- + roundToSignificantFigures(getMaxTimeSpent())
- + " ms).";
- }
- if (!children.isEmpty()) {
- double ownTime = getOwnTime();
- msg += " " + ownTime + " ms spent in own code";
- if (getCount() > 1) {
- msg += " ("
- + roundToSignificantFigures(ownTime / getCount())
- + " ms per time)";
- }
- msg += '.';
- }
- return msg;
- }
-
- private static double roundToSignificantFigures(double num) {
- // Number of significant digits
- int n = 3;
- if (num == 0) {
- return 0;
- }
-
- final double d = Math.ceil(Math.log10(num < 0 ? -num : num));
- final int power = n - (int) d;
-
- final double magnitude = Math.pow(10, power);
- final long shifted = Math.round(num * magnitude);
- return shifted / magnitude;
- }
-
- public void sumUpTotals(Map<String, Node> totals) {
- String name = getName();
- if (name != null) {
- Node totalNode = totals.get(name);
- if (totalNode == null) {
- totalNode = new Node(name);
- totals.put(name, totalNode);
- }
-
- totalNode.time += getOwnTime();
- totalNode.count += getCount();
- totalNode.minTime = Math.min(totalNode.minTime,
- getMinTimeSpent());
- totalNode.maxTime = Math.max(totalNode.maxTime,
- getMaxTimeSpent());
- }
- for (Node node : children.values()) {
- node.sumUpTotals(totals);
- }
- }
-
- /**
- * @param timestamp
- */
- public void leave(double timestamp) {
- double elapsed = (timestamp - enterTime);
- time += elapsed;
- enterTime = 0;
- if (elapsed < minTime) {
- minTime = elapsed;
- }
- if (elapsed > maxTime) {
- maxTime = elapsed;
- }
- }
- }
-
- private static final int MAX_ROWS = 10;
-
- private final DebugButton tabButton = new DebugButton(Icon.RESET_TIMER,
- "Profiler");
-
- private final HorizontalPanel controls = new HorizontalPanel();
- private final FlowPanel content = new FlowPanel();
-
- public ProfilerSection() {
- Profiler.setProfilerResultConsumer(new ProfilerResultConsumer() {
- @Override
- public void addProfilerData(Node rootNode, List<Node> totals) {
- double totalTime = 0;
- int eventCount = 0;
- for (Node node : totals) {
- totalTime += node.getTimeSpent();
- eventCount += node.getCount();
- }
-
- SimpleTree drillDownTree = (SimpleTree) buildTree(rootNode);
- drillDownTree.setText("Drill down");
-
- SimpleTree offendersTree = new SimpleTree("Longest events");
- for (int i = 0; i < totals.size() && i < 20; i++) {
- Node node = totals.get(i);
- offendersTree.add(new Label(node
- .getStringRepresentation("")));
- }
-
- SimpleTree root = new SimpleTree(eventCount
- + " profiler events using " + totalTime + " ms");
- root.add(drillDownTree);
- root.add(offendersTree);
- root.open(false);
-
- content.add(root);
- applyLimit();
- }
-
- @Override
- public void addBootstrapData(LinkedHashMap<String, Double> timings) {
- SimpleTree tree = new SimpleTree(
- "Time since window.performance.timing events");
- Set<Entry<String, Double>> entrySet = timings.entrySet();
- for (Entry<String, Double> entry : entrySet) {
- tree.add(new Label(entry.getValue() + " " + entry.getKey()));
- }
-
- tree.open(false);
- content.add(tree);
- applyLimit();
- }
- });
- }
-
- private Widget buildTree(Node node) {
- String message = node.getStringRepresentation("");
-
- Collection<Node> children = node.getChildren();
- if (node.getName() == null || !children.isEmpty()) {
- SimpleTree tree = new SimpleTree(message);
- for (Node childNode : children) {
- Widget child = buildTree(childNode);
- tree.add(child);
- }
- return tree;
- } else {
- return new Label(message);
- }
- }
-
- private void applyLimit() {
- while (content.getWidgetCount() > MAX_ROWS) {
- content.remove(0);
- }
- }
-
- @Override
- public DebugButton getTabButton() {
- return tabButton;
- }
-
- @Override
- public Widget getControls() {
- return controls;
- }
-
- @Override
- public Widget getContent() {
- return content;
- }
-
- @Override
- public void show() {
- // Nothing to do
- }
-
- @Override
- public void hide() {
- // Nothing to do
- }
-
- @Override
- public void meta(ApplicationConnection ac, ValueMap meta) {
- // Nothing to do
- }
-
- @Override
- public void uidl(ApplicationConnection ac, ValueMap uidl) {
- // Nothing to do
- }
-
- }
|