<when-type-assignable
class="com.vaadin.client.metadata.ConnectorBundleLoader" />
</generate-with>
+
+ <!-- Set vaadin.profiler to true to include profiling support in the module -->
+ <define-property name="vaadin.profiler" values="true,false" />
+ <set-property name="vaadin.profiler" value="false" />
+
+ <replace-with class="com.vaadin.client.Profiler.EnabledProfiler">
+ <when-type-is class="com.vaadin.client.Profiler" />
+ <when-property-is name="vaadin.profiler" value="true" />
+ </replace-with>
<!-- Use the new cross site linker to get a nocache.js without document.write -->
<add-linker name="xsiframe" />
return;
}
+ Profiler.reset();
+
VConsole.log("Handling message from server");
eventBus.fireEvent(new ResponseHandlingStartedEvent(this));
handleUIDLDuration.logDuration(" * Loading widgets completed",
10);
- MultiStepDuration updateDuration = new MultiStepDuration();
-
+ Profiler.enter("Handling locales");
if (json.containsKey("locales")) {
VConsole.log(" * Handling locales");
// Store locale data
.getJSValueMapArray("locales");
LocaleService.addLocales(valueMapArray);
}
+ Profiler.leave("Handling locales");
- updateDuration.logDuration(" * Handling locales completed", 10);
-
+ Profiler.enter("Handling meta information");
boolean repaintAll = false;
ValueMap meta = null;
if (json.containsKey("meta")) {
.getInt("interval");
}
}
-
- updateDuration.logDuration(
- " * Handling meta information completed", 10);
+ Profiler.leave("Handling meta information");
if (redirectTimer != null) {
redirectTimer.schedule(1000 * sessionExpirationInterval);
componentCaptionSizeChanges.clear();
- int startProcessing = updateDuration.elapsedMillis();
+ double processUidlStart = Duration.currentTimeMillis();
// Ensure that all connectors that we are about to update exist
Set<ServerConnector> createdConnectors = createConnectorsIfNeeded(json);
- updateDuration.logDuration(" * Creating connectors completed",
- 10);
-
// Update states, do not fire events
Collection<StateChangeEvent> pendingStateChangeEvents = updateConnectorState(
json, createdConnectors);
- updateDuration.logDuration(
- " * Update of connector states completed", 10);
-
// Update hierarchy, do not fire events
ConnectorHierarchyUpdateResult connectorHierarchyUpdateResult = updateConnectorHierarchy(json);
- updateDuration.logDuration(
- " * Update of connector hierarchy completed", 10);
-
// Fire hierarchy change events
sendHierarchyChangeEvents(connectorHierarchyUpdateResult.events);
- updateDuration.logDuration(
- " * Hierarchy state change event processing completed",
- 10);
-
updateCaptions(pendingStateChangeEvents,
connectorHierarchyUpdateResult.parentChanged);
// Fire state change events.
sendStateChangeEvents(pendingStateChangeEvents);
- updateDuration.logDuration(
- " * State change event processing completed", 10);
-
// Update of legacy (UIDL) style connectors
updateVaadin6StyleConnectors(json);
- updateDuration
- .logDuration(
- " * Vaadin 6 style connector updates (updateFromUidl) completed",
- 10);
-
// Handle any RPC invocations done on the server side
handleRpcInvocations(json);
- updateDuration.logDuration(
- " * Processing of RPC invocations completed", 10);
-
if (json.containsKey("dd")) {
// response contains data for drag and drop service
VDragAndDropManager.get().handleServerResponse(
json.getValueMap("dd"));
}
- updateDuration
- .logDuration(
- " * Processing of drag and drop server response completed",
- 10);
-
unregisterRemovedConnectors();
- updateDuration.logDuration(
- " * Unregistering of removed components completed", 10);
-
VConsole.log("handleUIDLMessage: "
- + (updateDuration.elapsedMillis() - startProcessing)
+ + (Duration.currentTimeMillis() - processUidlStart)
+ " ms");
+ Profiler.enter("Layout processing");
try {
LayoutManager layoutManager = getLayoutManager();
layoutManager.setEverythingNeedsMeasure();
} catch (final Throwable e) {
VConsole.error(e);
}
-
- updateDuration
- .logDuration(" * Layout processing completed", 10);
+ Profiler.leave("Layout processing");
if (ApplicationConfiguration.isDebugMode()) {
+ Profiler.enter("Dumping state changes to the console");
VConsole.log(" * Dumping state changes to the console");
VConsole.dirUIDL(json, ApplicationConnection.this);
-
- updateDuration
- .logDuration(
- " * Dumping state changes to the console completed",
- 10);
+ Profiler.leave("Dumping state changes to the console");
}
if (meta != null) {
+ Profiler.enter("Error handling");
if (meta.containsKey("appError")) {
ValueMap error = meta.getValueMap("appError");
validatingLayouts = false;
}
+ Profiler.leave("Error handling");
}
- updateDuration.logDuration(" * Error handling completed", 10);
-
// TODO build profiling for widget impl loading time
lastProcessingTime = (int) ((new Date().getTime()) - start
endRequest();
+ if (Profiler.isEnabled()) {
+ Profiler.logTimings();
+ Profiler.reset();
+ }
+
}
private void updateCaptions(
Collection<StateChangeEvent> pendingStateChangeEvents,
Collection<ServerConnector> parentChanged) {
+ Profiler.enter("updateCaptions");
+
/*
* Find all components that might need a caption update based on
* pending state and hierarchy changes
.delegateCaptionHandling()) {
ServerConnector parent = child.getParent();
if (parent instanceof HasComponentsConnector) {
+ Profiler.enter("HasComponentsConnector.updateCaption");
((HasComponentsConnector) parent)
.updateCaption((ComponentConnector) child);
+ Profiler.leave("HasComponentsConnector.updateCaption");
}
}
}
+
+ Profiler.leave("updateCaptions");
}
private void delegateToWidget(
Collection<StateChangeEvent> pendingStateChangeEvents) {
+ Profiler.enter("@DelegateToWidget");
+
VConsole.log(" * Running @DelegateToWidget");
for (StateChangeEvent sce : pendingStateChangeEvents) {
String method = property
.getDelegateToWidgetMethodName();
if (method != null) {
+ Profiler.enter("doDelegateToWidget");
doDelegateToWidget(component, property, method);
+ Profiler.leave("doDelegateToWidget");
}
}
}
}
+
+ Profiler.leave("@DelegateToWidget");
}
private void doDelegateToWidget(ComponentConnector component,
*/
private void sendStateChangeEvents(
Collection<StateChangeEvent> pendingStateChangeEvents) {
+ Profiler.enter("sendStateChangeEvents");
VConsole.log(" * Sending state change events");
for (StateChangeEvent sce : pendingStateChangeEvents) {
}
}
+ Profiler.leave("sendStateChangeEvents");
}
private void unregisterRemovedConnectors() {
+ Profiler.enter("unregisterRemovedConnectors");
+
int unregistered = 0;
JsArrayObject<ServerConnector> currentConnectors = connectorMap
.getConnectorsAsJsArray();
}
VConsole.log("* Unregistered " + unregistered + " connectors");
+ Profiler.leave("unregisterRemovedConnectors");
}
private Set<ServerConnector> createConnectorsIfNeeded(ValueMap json) {
return Collections.emptySet();
}
+ Profiler.enter("Creating connectors");
+
Set<ServerConnector> createdConnectors = new HashSet<ServerConnector>();
ValueMap types = json.getValueMap("types");
// Connector does not exist so we must create it
if (connectorClass != UIConnector.class) {
// create, initialize and register the paintable
+ Profiler.enter("ApplicationConnection.getConnector");
connector = getConnector(connectorId, connectorType);
+ Profiler.leave("ApplicationConnection.getConnector");
+
createdConnectors.add(connector);
} else {
// First UIConnector update. Before this the
VConsole.error(e);
}
}
+
+ Profiler.leave("Creating connectors");
+
return createdConnectors;
}
private void updateVaadin6StyleConnectors(ValueMap json) {
+ Profiler.enter("updateVaadin6StyleConnectors");
+
JsArray<ValueMap> changes = json.getJSValueMapArray("changes");
int length = changes.length();
final ComponentConnector legacyConnector = (ComponentConnector) connectorMap
.getConnector(connectorId);
if (legacyConnector instanceof Paintable) {
+ String key = null;
+ if (Profiler.isEnabled()) {
+ key = "updateFromUIDL for "
+ + Util.getSimpleName(legacyConnector);
+ Profiler.enter(key);
+ }
+
((Paintable) legacyConnector).updateFromUIDL(uidl,
ApplicationConnection.this);
+
+ if (Profiler.isEnabled()) {
+ Profiler.leave(key);
+ }
} else if (legacyConnector == null) {
VConsole.error("Received update for "
+ uidl.getTag()
VConsole.error(e);
}
}
+
+ Profiler.leave("updateVaadin6StyleConnectors");
}
private void sendHierarchyChangeEvents(
if (pendingHierarchyChangeEvents.isEmpty()) {
return;
}
+ Profiler.enter("sendHierarchyChangeEvents");
VConsole.log(" * Sending hierarchy change events");
for (ConnectorHierarchyChangeEvent event : pendingHierarchyChangeEvents) {
}
}
+ Profiler.leave("sendHierarchyChangeEvents");
}
private void logHierarchyChange(ConnectorHierarchyChangeEvent event) {
if (!json.containsKey("state")) {
return events;
}
+
+ Profiler.enter("updateConnectorState");
+
HashSet<ServerConnector> remainingNewConnectors = new HashSet<ServerConnector>(
newConnectors);
ServerConnector connector = connectorMap
.getConnector(connectorId);
if (null != connector) {
+ Profiler.enter("updateConnectorState inner loop");
+ if (Profiler.isEnabled()) {
+ Profiler.enter("Decode connector state "
+ + Util.getSimpleName(connector));
+ }
JSONObject stateJson = new JSONObject(
states.getJavaScriptObject(connectorId));
}
SharedState state = connector.getState();
+
+ Profiler.enter("updateConnectorState decodeValue");
JsonDecoder.decodeValue(new Type(state.getClass()
.getName(), null), stateJson, state,
ApplicationConnection.this);
+ Profiler.leave("updateConnectorState decodeValue");
+
+ if (Profiler.isEnabled()) {
+ Profiler.leave("Decode connector state "
+ + Util.getSimpleName(connector));
+ }
+ Profiler.enter("updateConnectorState create event");
FastStringSet changedProperties = FastStringSet
.create();
addJsonFields(stateJson, changedProperties, "");
connector, changedProperties);
events.add(event);
+ Profiler.leave("updateConnectorState create event");
+
+ Profiler.leave("updateConnectorState inner loop");
}
} catch (final Throwable e) {
VConsole.error(e);
}
+ Profiler.leave("updateConnectorState");
+
return events;
}
FastStringSet fields;
fields = allStateFieldsCache.get(type.getBaseTypeName());
if (fields == null) {
+ Profiler.enter("getAllStateFields create");
fields = FastStringSet.create();
addAllStateFields(type, fields, "");
allStateFieldsCache.put(type.getBaseTypeName(), fields);
+ Profiler.leave("getAllStateFields create");
}
return fields;
}
return result;
}
+ Profiler.enter("updateConnectorHierarchy");
+
FastStringSet maybeDetached = FastStringSet.create();
ValueMap hierarchies = json.getValueMap("hierarchy");
recursivelyDetach(removed, result.events);
}
+ Profiler.leave("updateConnectorHierarchy");
+
return result;
}
private void handleRpcInvocations(ValueMap json) {
if (json.containsKey("rpc")) {
+ Profiler.enter("handleRpcInvocations");
+
VConsole.log(" * Performing server to client RPC calls");
JSONArray rpcCalls = new JSONArray(
VConsole.error(e);
}
}
- }
+ Profiler.leave("handleRpcInvocations");
+ }
}
};
*/
private ServerConnector createAndRegisterConnector(String connectorId,
int connectorType) {
+ Profiler.enter("ApplicationConnection.createAndRegisterConnector");
+
// Create and register a new connector with the given type
ServerConnector p = widgetSet.createConnector(connectorType,
configuration);
connectorMap.registerConnector(connectorId, p);
p.doInit(connectorId, this);
+ Profiler.leave("ApplicationConnection.createAndRegisterConnector");
return p;
}
}
public void registerConnector(String id, ServerConnector connector) {
+ Profiler.enter("ConnectorMap.registerConnector");
ComponentDetail componentDetail = GWT.create(ComponentDetail.class);
idToComponentDetail.put(id, componentDetail);
componentDetail.setConnector(connector);
if (connector instanceof ComponentConnector) {
ComponentConnector pw = (ComponentConnector) connector;
+ Profiler.enter("ConnectorMap.setConnectorId");
setConnectorId(pw.getWidget().getElement(), id);
+ Profiler.leave("ConnectorMap.setConnectorId");
}
+ Profiler.leave("ConnectorMap.registerConnector");
}
private static native void setConnectorId(Element el, String id)
private void doLayout() {
VConsole.log("Starting layout phase");
+ Profiler.enter("LayoutManager phase init");
FastStringMap<Integer> layoutCounts = FastStringMap.create();
measureNonConnectors();
- VConsole.log("Layout init in " + totalDuration.elapsedMillis() + " ms");
+ Profiler.leave("LayoutManager phase init");
while (true) {
- Duration passDuration = new Duration();
+ Profiler.enter("Layout pass");
passes++;
performBrowserLayoutHacks();
+ Profiler.enter("Layout measure connectors");
int measuredConnectorCount = measureConnectors(
currentDependencyTree, everythingNeedsMeasure);
+ Profiler.leave("Layout measure connectors");
+
everythingNeedsMeasure = false;
if (measuredConnectorCount == 0) {
VConsole.log("No more changes in pass " + passes);
+ Profiler.leave("Layout pass");
break;
}
- int measureTime = passDuration.elapsedMillis();
- VConsole.log(" Measured " + measuredConnectorCount
- + " elements in " + measureTime + " ms");
-
+ int firedListeners = 0;
if (!listenersToFire.isEmpty()) {
+ firedListeners = listenersToFire.size();
+ Profiler.enter("Layout fire resize events");
for (Element element : listenersToFire) {
Collection<ElementResizeListener> listeners = elementResizeListeners
.get(element);
element);
for (ElementResizeListener listener : array) {
try {
+ String key = null;
+ if (Profiler.isEnabled()) {
+ key = "ElementReizeListener.onElementReize for "
+ + Util.getSimpleName(listener);
+ Profiler.enter(key);
+ }
+
listener.onElementResize(event);
+ if (Profiler.isEnabled()) {
+ Profiler.leave(key);
+ }
} catch (RuntimeException e) {
VConsole.error(e);
}
}
}
}
- int measureListenerTime = passDuration.elapsedMillis();
- VConsole.log(" Fired resize listeners for "
- + listenersToFire.size() + " elements in "
- + (measureListenerTime - measureTime) + " ms");
- measureTime = measuredConnectorCount;
listenersToFire.clear();
+
+ Profiler.leave("Layout fire resize events");
}
+ Profiler.enter("LayoutManager handle ManagedLayout");
+
FastStringSet updatedSet = FastStringSet.create();
+ int layoutCount = 0;
while (currentDependencyTree.hasHorizontalConnectorToLayout()
|| currentDependencyTree.hasVerticaConnectorToLayout()) {
.markAsHorizontallyLayouted(layout);
DirectionalManagedLayout cl = (DirectionalManagedLayout) layout;
try {
+ String key = null;
+ if (Profiler.isEnabled()) {
+ key = "layoutHorizontally() for "
+ + Util.getSimpleName(cl);
+ Profiler.enter(key);
+ }
+
cl.layoutHorizontally();
+ layoutCount++;
+
+ if (Profiler.isEnabled()) {
+ Profiler.leave(key);
+ }
} catch (RuntimeException e) {
VConsole.error(e);
}
currentDependencyTree.markAsVerticallyLayouted(layout);
SimpleManagedLayout rr = (SimpleManagedLayout) layout;
try {
+ String key = null;
+ if (Profiler.isEnabled()) {
+ key = "layout() for " + Util.getSimpleName(rr);
+ Profiler.enter(key);
+ }
+
rr.layout();
+ layoutCount++;
+
+ if (Profiler.isEnabled()) {
+ Profiler.leave(key);
+ }
} catch (RuntimeException e) {
VConsole.error(e);
}
currentDependencyTree.markAsVerticallyLayouted(layout);
DirectionalManagedLayout cl = (DirectionalManagedLayout) layout;
try {
+ String key = null;
+ if (Profiler.isEnabled()) {
+ key = "layoutHorizontally() for "
+ + Util.getSimpleName(cl);
+ Profiler.enter(key);
+ }
+
cl.layoutVertically();
+ layoutCount++;
+
+ if (Profiler.isEnabled()) {
+ Profiler.leave(key);
+ }
} catch (RuntimeException e) {
VConsole.error(e);
}
currentDependencyTree.markAsVerticallyLayouted(layout);
SimpleManagedLayout rr = (SimpleManagedLayout) layout;
try {
+ String key = null;
+ if (Profiler.isEnabled()) {
+ key = "layout() for " + Util.getSimpleName(rr);
+ Profiler.enter(key);
+ }
+
rr.layout();
+ layoutCount++;
+
+ if (Profiler.isEnabled()) {
+ Profiler.leave(key);
+ }
} catch (RuntimeException e) {
VConsole.error(e);
}
}
}
+ Profiler.leave("LayoutManager handle ManagedLayout");
+
if (debugLogging) {
JsArrayString changedCids = updatedSet.dump();
StringBuilder b = new StringBuilder(" ");
b.append(changedCids.length());
- b.append(" requestLayout invocations in ");
- b.append(passDuration.elapsedMillis() - measureTime);
- b.append(" ms");
+ b.append(" requestLayout invocations ");
if (changedCids.length() < 30) {
for (int i = 0; i < changedCids.length(); i++) {
if (i != 0) {
VConsole.log(b.toString());
}
- VConsole.log("Pass " + passes + " completed in "
- + passDuration.elapsedMillis() + " ms");
+ Profiler.leave("Layout pass");
+
+ VConsole.log("Pass " + passes + " measured "
+ + measuredConnectorCount + " elements, fired "
+ + firedListeners + " listeners and did " + layoutCount
+ + " layouts.");
if (passes > 100) {
VConsole.log(LOOP_ABORT_MESSAGE);
}
}
- int postLayoutStart = totalDuration.elapsedMillis();
+ Profiler.enter("layout PostLayoutListener");
JsArrayObject<ComponentConnector> componentConnectors = connectorMap
.getComponentConnectorsAsJsArray();
int size = componentConnectors.size();
for (int i = 0; i < size; i++) {
ComponentConnector connector = componentConnectors.get(i);
if (connector instanceof PostLayoutListener) {
+ String key = null;
+ if (Profiler.isEnabled()) {
+ key = "layout PostLayoutListener for "
+ + Util.getSimpleName(connector);
+ Profiler.enter(key);
+ }
+
((PostLayoutListener) connector).postLayout();
+
+ if (Profiler.isEnabled()) {
+ Profiler.leave(key);
+ }
}
}
- int postLayoutDone = totalDuration.elapsedMillis();
- VConsole.log("Invoke post layout listeners in "
- + (postLayoutDone - postLayoutStart) + " ms");
+ Profiler.leave("layout PostLayoutListener");
cleanMeasuredSizes();
- int cleaningTime = (totalDuration.elapsedMillis() - postLayoutDone);
- VConsole.log("Cleaned old measured sizes in " + cleaningTime + "ms");
VConsole.log("Total layout phase time: "
+ totalDuration.elapsedMillis() + "ms");
private int measureConnectors(LayoutDependencyTree layoutDependencyTree,
boolean measureAll) {
+ Profiler.enter("Layout overflow fix handling");
JsArrayString pendingOverflowConnectorsIds = pendingOverflowFixes
.dump();
int pendingOverflowCount = pendingOverflowConnectorsIds.length();
ConnectorMap connectorMap = ConnectorMap.get(connection);
if (pendingOverflowCount > 0) {
- Duration duration = new Duration();
-
HashMap<Element, String> originalOverflows = new HashMap<Element, String>();
FastStringSet delayedOverflowFixes = FastStringSet.create();
+ Util.getConnectorString(componentConnector
.getParent()));
}
+ Profiler.enter("Overflow fix apply");
Element parentElement = componentConnector.getWidget()
.getElement().getParentElement();
}
style.setOverflow(Overflow.HIDDEN);
+ Profiler.leave("Overflow fix apply");
}
pendingOverflowFixes.removeAll(delayedOverflowFixes);
JsArrayString remainingOverflowFixIds = pendingOverflowFixes.dump();
int remainingCount = remainingOverflowFixIds.length();
+ Profiler.enter("Overflow fix reflow");
// Then ensure all scrolling elements are reflowed by measuring
for (int i = 0; i < remainingCount; i++) {
ComponentConnector componentConnector = (ComponentConnector) connectorMap
componentConnector.getWidget().getElement().getParentElement()
.getOffsetHeight();
}
+ Profiler.leave("Overflow fix reflow");
+ Profiler.enter("Overflow fix restore");
// Finally restore old overflow value and update bookkeeping
for (int i = 0; i < remainingCount; i++) {
String connectorId = remainingOverflowFixIds.get(i);
layoutDependencyTree.setNeedsMeasure(connectorId, true);
}
+ Profiler.leave("Overflow fix restore");
+
if (!pendingOverflowFixes.isEmpty()) {
VConsole.log("Did overflow fix for " + remainingCount
- + " elements in " + duration.elapsedMillis() + " ms");
+ + " elements");
}
pendingOverflowFixes = delayedOverflowFixes;
}
+ Profiler.leave("Layout overflow fix handling");
int measureCount = 0;
if (measureAll) {
+ Profiler.enter("Layout measureAll");
JsArrayObject<ComponentConnector> allConnectors = connectorMap
.getComponentConnectorsAsJsArray();
int size = allConnectors.size();
.getConnectorId(), false);
}
measureCount += connectorCount;
+
+ Profiler.leave("Layout measureAll");
}
+ Profiler.enter("Layout measure from tree");
while (layoutDependencyTree.hasConnectorsToMeasure()) {
JsArrayString measureTargets = layoutDependencyTree
.getMeasureTargetsJsArray();
layoutDependencyTree.setNeedsMeasure(connectorId, false);
}
}
+ Profiler.leave("Layout measure from tree");
+
return measureCount;
}
private void measureConnector(ComponentConnector connector) {
+ Profiler.enter("LayoutManager.measureConnector");
Element element = connector.getWidget().getElement();
MeasuredSize measuredSize = getMeasuredSize(connector);
MeasureResult measureResult = measuredAndUpdate(element, measuredSize);
onConnectorChange(connector, measureResult.isWidthChanged(),
measureResult.isHeightChanged());
}
+ Profiler.leave("LayoutManager.measureConnector");
}
private void onConnectorChange(ComponentConnector connector,
boolean widthChanged, boolean heightChanged) {
+ Profiler.enter("LayoutManager.onConnectorChange");
setNeedsOverflowFix(connector);
if (heightChanged) {
currentDependencyTree.markHeightAsChanged(connector);
if (widthChanged) {
currentDependencyTree.markWidthAsChanged(connector);
}
+ Profiler.leave("LayoutManager.onConnectorChange");
}
private void setNeedsOverflowFix(ComponentConnector connector) {
}
private void measureNonConnectors() {
+ Profiler.enter("LayoutManager.measureNonConenctors");
for (Element element : measuredNonConnectorElements) {
measuredAndUpdate(element, getMeasuredSize(element, null));
}
+ Profiler.leave("LayoutManager.measureNonConenctors");
VConsole.log("Measured " + measuredNonConnectorElements.size()
+ " non connector elements");
}
boolean widthChanged, boolean heightChanged) {
assert widthChanged || heightChanged;
+ Profiler.enter("LayoutManager.notifyListenersAndDepdendents");
+
MeasuredSize measuredSize = getMeasuredSize(element, nullSize);
JsArrayString dependents = measuredSize.getDependents();
for (int i = 0; i < dependents.length(); i++) {
if (elementResizeListeners.containsKey(element)) {
listenersToFire.add(element);
}
+ Profiler.leave("LayoutManager.notifyListenersAndDepdendents");
}
private static boolean isManagedLayout(ComponentConnector connector) {
@Override
protected void cleanMeasuredSizes() {
+ Profiler.enter("LayoutManager.cleanMeasuredSizes");
Document document = RootPanel.get().getElement().getOwnerDocument();
Iterator<Element> i = measuredSizes.keySet().iterator();
i.remove();
}
}
+
+ Profiler.leave("LayoutManager.cleanMeasuredSizes");
}
@Override
protected void performBrowserLayoutHacks() {
+ Profiler.enter("LayoutManagerIE8.performBrowserLayoutHacks");
/*
* Fixes IE8 issues where IE8 sometimes forgets to update the size of
* the containing element. To force a reflow by modifying the magical
* zoom property.
*/
Util.forceIE8Redraw(RootPanel.get().getElement());
+ Profiler.leave("LayoutManagerIE8.performBrowserLayoutHacks");
}
}
}
public MeasureResult measure(Element element) {
+ Profiler.enter("MeasuredSize.measure");
boolean heightChanged = false;
boolean widthChanged = false;
+ Profiler.enter("new ComputedStyle");
ComputedStyle computedStyle = new ComputedStyle(element);
int[] paddings = computedStyle.getPadding();
+ // Some browsers do not reflow until accessing data from the computed
+ // style object
+ Profiler.leave("new ComputedStyle");
+
+ Profiler.enter("Measure paddings");
if (!heightChanged && hasHeightChanged(this.paddings, paddings)) {
debugSizeChange(element, "Height (padding)", this.paddings,
paddings);
widthChanged = true;
}
this.paddings = paddings;
+ Profiler.leave("Measure paddings");
+ Profiler.enter("Measure margins");
int[] margins = computedStyle.getMargin();
if (!heightChanged && hasHeightChanged(this.margins, margins)) {
debugSizeChange(element, "Height (margins)", this.margins, margins);
widthChanged = true;
}
this.margins = margins;
+ Profiler.leave("Measure margins");
+ Profiler.enter("Measure borders");
int[] borders = computedStyle.getBorder();
if (!heightChanged && hasHeightChanged(this.borders, borders)) {
debugSizeChange(element, "Height (borders)", this.borders, borders);
widthChanged = true;
}
this.borders = borders;
+ Profiler.leave("Measure borders");
+ Profiler.enter("Measure height");
int requiredHeight = Util.getRequiredHeight(element);
int marginHeight = sumHeights(margins);
int oldHeight = height;
debugSizeChange(element, "Height (outer)", oldHeight, height);
heightChanged = true;
}
+ Profiler.leave("Measure height");
+ Profiler.enter("Measure width");
int requiredWidth = Util.getRequiredWidth(element);
int marginWidth = sumWidths(margins);
if (setOuterWidth(requiredWidth + marginWidth)) {
debugSizeChange(element, "Width (outer)", oldWidth, width);
widthChanged = true;
}
+ Profiler.leave("Measure width");
+
+ Profiler.leave("MeasuredSize.measure");
return new MeasureResult(widthChanged, heightChanged);
}
--- /dev/null
+/*
+ * Copyright 2012 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;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+import com.google.gwt.core.client.Duration;
+import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsArray;
+import com.google.gwt.core.shared.GWT;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.Widget;
+
+/**
+ * Lightweight profiling tool that can be used to collect profiling data with
+ * zero overhead unless enabled. To enable profiling, add
+ * <code><set-property name="vaadin.profiler" value="true" /></code> to
+ * your .gwt.xml file.
+ *
+ * @author Vaadin Ltd
+ * @since 7.0.0
+ */
+public class Profiler {
+ /**
+ * Class to include using deferred binding to enable the profiling.
+ *
+ * @author Vaadin Ltd
+ * @since 7.0.0
+ */
+ public static class EnabledProfiler extends Profiler {
+ @Override
+ protected boolean isImplEnabled() {
+ return true;
+ }
+ }
+
+ private static JsArray<ProfilerEvent> events;
+
+ private static final class ProfilerEvent extends JavaScriptObject {
+ protected ProfilerEvent() {
+ // JSO constructor
+ }
+
+ public native String getName()
+ /*-{
+ return this.name;
+ }-*/;
+
+ private native double getRawTime()
+ /*-{
+ return this.time;
+ }-*/;
+
+ private boolean isStart() {
+ return getRawTime() <= 0;
+ }
+ }
+
+ private 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;
+
+ public Node(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Node addEvent(ProfilerEvent event) {
+ Node child = children.get(event.getName());
+ if (child == null) {
+ child = new Node(event.getName());
+ children.put(event.getName(), child);
+ }
+ child.time += event.getRawTime();
+ child.count++;
+ return child;
+ }
+
+ public void registerEnd(ProfilerEvent event) {
+ time += event.getRawTime();
+ }
+
+ public double getTimeSpent() {
+ return time;
+ }
+
+ public int getCount() {
+ return count;
+ }
+
+ public double getOwnTime() {
+ double time = getTimeSpent();
+ for (Node node : children.values()) {
+ time -= node.getTimeSpent();
+ }
+ return time;
+ }
+
+ public Widget buildTree() {
+ String message = getStringRepresentation("");
+
+ if (getName() == null || !children.isEmpty()) {
+ SimpleTree tree = new SimpleTree(message);
+ for (Node node : children.values()) {
+ Widget child = node.buildTree();
+ tree.add(child);
+ }
+ return tree;
+ } else {
+ return new Label(message);
+ }
+ }
+
+ public 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);
+ }
+ }
+
+ private 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).";
+ }
+ 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;
+ }
+
+ public 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();
+ }
+ for (Node node : children.values()) {
+ node.sumUpTotals(totals);
+ }
+ }
+ }
+
+ /**
+ * Checks whether the profiling gathering is enabled.
+ *
+ * @return <code>true</code> if the profiling is enabled, else
+ * <code>false</code>
+ */
+ public static boolean isEnabled() {
+ // This will be fully inlined by the compiler
+ Profiler create = GWT.create(Profiler.class);
+ return create.isImplEnabled();
+ }
+
+ /**
+ * Enters a named block. There should always be a matching invocation of
+ * {@link #leave(String)} when leaving the block. Calls to this method will
+ * be removed by the compiler unless profiling is enabled.
+ *
+ * @param name
+ * the name of the entered block
+ */
+ public static void enter(String name) {
+ if (isEnabled()) {
+ pushEvent(events, name, -Duration.currentTimeMillis());
+ }
+ }
+
+ /**
+ * Leaves a named block. There should always be a matching invocation of
+ * {@link #enter(String)} when entering the block. Calls to this method will
+ * be removed by the compiler unless profiling is enabled.
+ *
+ * @param name
+ * the name of the left block
+ */
+ public static void leave(String name) {
+ if (isEnabled()) {
+ pushEvent(events, name, Duration.currentTimeMillis());
+ }
+ }
+
+ private static native final void pushEvent(JsArray<ProfilerEvent> target,
+ String name, double time)
+ /*-{
+ target[target.length] = {name: name, time: time};
+ }-*/;
+
+ /**
+ * Resets the collected profiler data. Calls to this method will be removed
+ * by the compiler unless profiling is enabled.
+ */
+ public static void reset() {
+ if (isEnabled()) {
+ events = JavaScriptObject.createArray().cast();
+ }
+ }
+
+ /**
+ * Outputs the gathered profiling data to the debug console.
+ */
+ public static void logTimings() {
+ if (!isEnabled()) {
+ VConsole.log("Profiler is not enabled, no data has been collected.");
+ return;
+ }
+
+ LinkedList<Node> stack = new LinkedList<Node>();
+ Node rootNode = new Node(null);
+ stack.add(rootNode);
+ for (int i = 0; i < events.length(); i++) {
+ ProfilerEvent event = events.get(i);
+ if (event.isStart()) {
+ Node stackTop = stack.getLast().addEvent(event);
+ stack.add(stackTop);
+ } else {
+ Node stackTop = stack.removeLast();
+ if (stackTop == null) {
+ VConsole.error("Leaving " + event.getName()
+ + " that was never entered.");
+ return;
+ }
+ if (!stackTop.getName().equals(event.getName())) {
+ VConsole.error("Invalid profiling event order, leaving "
+ + event.getName() + " but " + stackTop.getName()
+ + " was expected");
+ return;
+ }
+ stackTop.registerEnd(event);
+ }
+ }
+
+ if (stack.size() != 1) {
+ VConsole.log("Not all nodes are left, the last node is "
+ + stack.getLast().getName());
+ return;
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ rootNode.buildRecursiveString(stringBuilder, "");
+ Console implementation = VConsole.getImplementation();
+ if (implementation instanceof VDebugConsole) {
+ VDebugConsole console = (VDebugConsole) implementation;
+
+ SimpleTree tree = (SimpleTree) stack.getFirst().buildTree();
+ tree.setText("Profiler data");
+
+ console.showTree(tree, stringBuilder.toString());
+ } else {
+ VConsole.log(stringBuilder.toString());
+ }
+
+ Map<String, Node> totals = new HashMap<String, Node>();
+ rootNode.sumUpTotals(totals);
+
+ ArrayList<Node> totalList = new ArrayList<Node>(totals.values());
+ Collections.sort(totalList, new Comparator<Node>() {
+ @Override
+ public int compare(Node o1, Node o2) {
+ return (int) (o2.getTimeSpent() - o1.getTimeSpent());
+ }
+ });
+
+ double total = 0;
+ double top20total = 0;
+ for (int i = 0; i < totalList.size(); i++) {
+ Node node = totalList.get(i);
+ double timeSpent = node.getTimeSpent();
+ total += timeSpent;
+ if (i < 20) {
+ top20total += timeSpent;
+ }
+ }
+
+ VConsole.log("Largest individual contributors using " + top20total
+ + " ms out of " + total + " ms");
+ for (int i = 0; i < 20 && i < totalList.size(); i++) {
+ Node node = totalList.get(i);
+ double timeSpent = node.getTimeSpent();
+ total += timeSpent;
+ VConsole.log(" * " + node.getName() + ": " + timeSpent + " ms in "
+ + node.getCount() + " invokations.");
+ }
+
+ }
+
+ /**
+ * Overridden in {@link EnabledProfiler} to make {@link #isEnabled()} return
+ * true if GWT.create returns that class.
+ *
+ * @return <code>true</code> if the profiling is enabled, else
+ * <code>false</code>
+ */
+ protected boolean isImplEnabled() {
+ return false;
+ }
+
+}
// consoleLog(u.getChildrenAsXML());
}
+ /**
+ * Adds a {@link SimpleTree} to the console and prints a string
+ * representation of the tree structure to the text console.
+ *
+ * @param tree
+ * the simple tree to display in the console window
+ * @param stringRepresentation
+ * the string representation of the tree to output to the text
+ * console
+ */
+ public void showTree(SimpleTree tree, String stringRepresentation) {
+ if (panel.isAttached()) {
+ panel.add(tree);
+ }
+ consoleLog(stringRepresentation);
+ }
+
private static native void consoleDir(ValueMap u)
/*-{
if($wnd.console && $wnd.console.log) {
* some hacks. Extra instantiation code is needed if client side
* connector has no "native" counterpart on client side.
*/
+ Profiler.enter("WidgetSet.createConnector");
Class<? extends ServerConnector> classType = resolveInheritedConnectorType(
conf, tag);
UnknownComponentConnector c = GWT
.create(UnknownComponentConnector.class);
c.setServerSideClassName(serverSideName);
+ Profiler.leave("WidgetSet.createConnector");
return c;
} else {
/*
((HasJavaScriptConnectorHelper) connector)
.getJavascriptConnectorHelper().setTag(tag);
}
+ Profiler.leave("WidgetSet.createConnector");
return connector;
} catch (NoDataException e) {
+ Profiler.leave("WidgetSet.createConnector");
throw new IllegalStateException(
"There is no information about "
+ classType
import com.vaadin.client.ConnectorMap;
import com.vaadin.client.FastStringSet;
import com.vaadin.client.JsArrayObject;
+import com.vaadin.client.Profiler;
import com.vaadin.client.metadata.NoDataException;
import com.vaadin.client.metadata.Property;
import com.vaadin.client.metadata.Type;
private static Object decodeObject(Type type, JSONValue jsonValue,
Object target, ApplicationConnection connection) {
+ Profiler.enter("JsonDecoder.decodeObject");
JSONSerializer<Object> serializer = (JSONSerializer<Object>) type
.findSerializer();
if (serializer != null) {
if (target != null && serializer instanceof DiffJSONSerializer<?>) {
DiffJSONSerializer<Object> diffSerializer = (DiffJSONSerializer<Object>) serializer;
diffSerializer.update(target, type, jsonValue, connection);
+ Profiler.leave("JsonDecoder.decodeObject");
return target;
} else {
Object object = serializer.deserialize(type, jsonValue,
connection);
+ Profiler.leave("JsonDecoder.decodeObject");
return object;
}
} else {
try {
+ Profiler.enter("JsonDecoder.decodeObject meta data processing");
JsArrayObject<Property> properties = type
.getPropertiesAsArray();
if (target == null) {
propertyReference = null;
}
+ Profiler.leave("JsonDecoder.decodeObject meta data processing");
Object decodedValue = decodeValue(propertyType,
encodedPropertyValue, propertyReference, connection);
+ Profiler.enter("JsonDecoder.decodeObject meta data processing");
property.setValue(target, decodedValue);
}
+ Profiler.leave("JsonDecoder.decodeObject meta data processing");
+ Profiler.leave("JsonDecoder.decodeObject");
return target;
} catch (NoDataException e) {
+ Profiler.leave("JsonDecoder.decodeObject meta data processing");
+ Profiler.leave("JsonDecoder.decodeObject");
throw new RuntimeException("Can not deserialize "
+ type.getSignature(), e);
}
import com.google.web.bindery.event.shared.HandlerRegistration;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.FastStringMap;
+import com.vaadin.client.Profiler;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.Util;
import com.vaadin.client.VConsole;
@Override
public final void doInit(String connectorId,
ApplicationConnection connection) {
+ Profiler.enter("AbstractConnector.doInit");
this.connection = connection;
id = connectorId;
addStateChangeHandler(this);
+ if (Profiler.isEnabled()) {
+ Profiler.enter("AbstractConnector.init " + Util.getSimpleName(this));
+ }
init();
+ if (Profiler.isEnabled()) {
+ Profiler.leave("AbstractConnector.init " + Util.getSimpleName(this));
+ }
+ Profiler.leave("AbstractConnector.doInit");
}
/**
@Override
public void fireEvent(GwtEvent<?> event) {
+ String profilerKey = null;
+ if (Profiler.isEnabled()) {
+ profilerKey = "Fire " + Util.getSimpleName(event) + " for "
+ + Util.getSimpleName(this);
+ Profiler.enter(profilerKey);
+ }
if (handlerManager != null) {
handlerManager.fireEvent(event);
}
}
}
}
+ if (Profiler.isEnabled()) {
+ Profiler.leave(profilerKey);
+ }
+
}
protected HandlerManager ensureHandlerManager() {
@Override
public void onStateChanged(StateChangeEvent stateChangeEvent) {
+ Profiler.enter("AbstractConnector.onStateChanged");
if (debugLogging) {
VConsole.log("State change event for "
+ Util.getConnectorString(stateChangeEvent.getConnector())
}
updateEnabledState(isEnabled());
+ Profiler.leave("AbstractConnector.onStateChanged");
}
/*
@Override
public SharedState getState() {
if (state == null) {
+ Profiler.enter("AbstractConnector.createState()");
state = createState();
+ Profiler.leave("AbstractConnector.createState()");
}
return state;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.MouseEventDetailsBuilder;
+import com.vaadin.client.Profiler;
import com.vaadin.client.UIDL;
import com.vaadin.client.Util;
import com.vaadin.client.VConsole;
if (serverCallback == null) {
return;
}
+ Profiler.enter("VDragAndDropManager.handleServerResponse");
+
UIDL uidl = (UIDL) valueMap.cast();
int visitId = uidl.getIntAttribute("visitId");
serverCallback = null;
}
runDeferredCommands();
+
+ Profiler.leave("VDragAndDropManager.handleServerResponse");
}
private void runDeferredCommands() {
import com.vaadin.client.ComponentConnector;
import com.vaadin.client.ConnectorHierarchyChangeEvent;
import com.vaadin.client.LayoutManager;
+import com.vaadin.client.Profiler;
import com.vaadin.client.ServerConnector;
import com.vaadin.client.Util;
import com.vaadin.client.communication.StateChangeEvent;
*/
@Override
public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) {
+ Profiler.enter("AOLC.onConnectorHierarchyChange");
List<ComponentConnector> previousChildren = event.getOldChildren();
int currentIndex = 0;
layout.setSpacing(getState().spacing);
for (ComponentConnector child : getChildComponents()) {
+ Profiler.enter("AOLC.onConnectorHierarchyChange add children");
Slot slot = layout.getSlot(child.getWidget());
if (slot.getParent() != layout) {
+ Profiler.enter("AOLC.onConnectorHierarchyChange add state change handler");
child.addStateChangeHandler(childStateChangeHandler);
+ Profiler.leave("AOLC.onConnectorHierarchyChange add state change handler");
}
+ Profiler.enter("AOLC.onConnectorHierarchyChange addOrMoveSlot");
layout.addOrMoveSlot(slot, currentIndex++);
+ Profiler.leave("AOLC.onConnectorHierarchyChange addOrMoveSlot");
+
+ Profiler.leave("AOLC.onConnectorHierarchyChange add children");
}
for (ComponentConnector child : previousChildren) {
+ Profiler.enter("AOLC.onConnectorHierarchyChange remove children");
if (child.getParent() != this) {
Slot slot = layout.getSlot(child.getWidget());
slot.setWidgetResizeListener(null);
child.removeStateChangeHandler(childStateChangeHandler);
layout.removeWidget(child.getWidget());
}
+ Profiler.leave("AOL.onConnectorHierarchyChange remove children");
}
+ Profiler.leave("AOLC.onConnectorHierarchyChange");
updateInternalState();
}
if (processedResponseId == lastResponseId) {
return;
}
+ Profiler.enter("AOLC.updateInternalState");
// Remember that everything is updated for this response
processedResponseId = lastResponseId;
} else {
getWidget().clearExpand();
}
+
+ Profiler.leave("AOLC.updateInternalState");
}
/**