Also remove most of the timing information that was previously logged Change-Id: I8269036a12762eb63f7d4f93aefb6be307dd620atags/7.0.1
@@ -38,6 +38,15 @@ | |||
<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" /> |
@@ -1311,6 +1311,8 @@ public class ApplicationConnection { | |||
return; | |||
} | |||
Profiler.reset(); | |||
VConsole.log("Handling message from server"); | |||
eventBus.fireEvent(new ResponseHandlingStartedEvent(this)); | |||
@@ -1384,8 +1386,7 @@ public class ApplicationConnection { | |||
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 | |||
@@ -1393,9 +1394,9 @@ public class ApplicationConnection { | |||
.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")) { | |||
@@ -1422,9 +1423,7 @@ public class ApplicationConnection { | |||
.getInt("interval"); | |||
} | |||
} | |||
updateDuration.logDuration( | |||
" * Handling meta information completed", 10); | |||
Profiler.leave("Handling meta information"); | |||
if (redirectTimer != null) { | |||
redirectTimer.schedule(1000 * sessionExpirationInterval); | |||
@@ -1432,34 +1431,21 @@ public class ApplicationConnection { | |||
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); | |||
@@ -1468,43 +1454,25 @@ public class ApplicationConnection { | |||
// 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(); | |||
@@ -1512,21 +1480,17 @@ public class ApplicationConnection { | |||
} 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"); | |||
@@ -1547,10 +1511,9 @@ public class ApplicationConnection { | |||
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 | |||
@@ -1564,11 +1527,18 @@ public class ApplicationConnection { | |||
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 | |||
@@ -1589,15 +1559,21 @@ public class ApplicationConnection { | |||
.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) { | |||
@@ -1618,12 +1594,16 @@ public class ApplicationConnection { | |||
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, | |||
@@ -1661,6 +1641,7 @@ public class ApplicationConnection { | |||
*/ | |||
private void sendStateChangeEvents( | |||
Collection<StateChangeEvent> pendingStateChangeEvents) { | |||
Profiler.enter("sendStateChangeEvents"); | |||
VConsole.log(" * Sending state change events"); | |||
for (StateChangeEvent sce : pendingStateChangeEvents) { | |||
@@ -1671,9 +1652,12 @@ public class ApplicationConnection { | |||
} | |||
} | |||
Profiler.leave("sendStateChangeEvents"); | |||
} | |||
private void unregisterRemovedConnectors() { | |||
Profiler.enter("unregisterRemovedConnectors"); | |||
int unregistered = 0; | |||
JsArrayObject<ServerConnector> currentConnectors = connectorMap | |||
.getConnectorsAsJsArray(); | |||
@@ -1703,6 +1687,7 @@ public class ApplicationConnection { | |||
} | |||
VConsole.log("* Unregistered " + unregistered + " connectors"); | |||
Profiler.leave("unregisterRemovedConnectors"); | |||
} | |||
private Set<ServerConnector> createConnectorsIfNeeded(ValueMap json) { | |||
@@ -1712,6 +1697,8 @@ public class ApplicationConnection { | |||
return Collections.emptySet(); | |||
} | |||
Profiler.enter("Creating connectors"); | |||
Set<ServerConnector> createdConnectors = new HashSet<ServerConnector>(); | |||
ValueMap types = json.getValueMap("types"); | |||
@@ -1733,7 +1720,10 @@ public class ApplicationConnection { | |||
// 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 | |||
@@ -1750,10 +1740,15 @@ public class ApplicationConnection { | |||
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(); | |||
@@ -1768,8 +1763,19 @@ public class ApplicationConnection { | |||
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() | |||
@@ -1785,6 +1791,8 @@ public class ApplicationConnection { | |||
VConsole.error(e); | |||
} | |||
} | |||
Profiler.leave("updateVaadin6StyleConnectors"); | |||
} | |||
private void sendHierarchyChangeEvents( | |||
@@ -1792,6 +1800,7 @@ public class ApplicationConnection { | |||
if (pendingHierarchyChangeEvents.isEmpty()) { | |||
return; | |||
} | |||
Profiler.enter("sendHierarchyChangeEvents"); | |||
VConsole.log(" * Sending hierarchy change events"); | |||
for (ConnectorHierarchyChangeEvent event : pendingHierarchyChangeEvents) { | |||
@@ -1803,6 +1812,7 @@ public class ApplicationConnection { | |||
} | |||
} | |||
Profiler.leave("sendHierarchyChangeEvents"); | |||
} | |||
private void logHierarchyChange(ConnectorHierarchyChangeEvent event) { | |||
@@ -1835,6 +1845,9 @@ public class ApplicationConnection { | |||
if (!json.containsKey("state")) { | |||
return events; | |||
} | |||
Profiler.enter("updateConnectorState"); | |||
HashSet<ServerConnector> remainingNewConnectors = new HashSet<ServerConnector>( | |||
newConnectors); | |||
@@ -1847,6 +1860,11 @@ public class ApplicationConnection { | |||
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)); | |||
@@ -1859,10 +1877,19 @@ public class ApplicationConnection { | |||
} | |||
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, ""); | |||
@@ -1880,6 +1907,9 @@ public class ApplicationConnection { | |||
connector, changedProperties); | |||
events.add(event); | |||
Profiler.leave("updateConnectorState create event"); | |||
Profiler.leave("updateConnectorState inner loop"); | |||
} | |||
} catch (final Throwable e) { | |||
VConsole.error(e); | |||
@@ -1899,6 +1929,8 @@ public class ApplicationConnection { | |||
} | |||
Profiler.leave("updateConnectorState"); | |||
return events; | |||
} | |||
@@ -1906,9 +1938,11 @@ public class ApplicationConnection { | |||
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; | |||
} | |||
@@ -1994,6 +2028,8 @@ public class ApplicationConnection { | |||
return result; | |||
} | |||
Profiler.enter("updateConnectorHierarchy"); | |||
FastStringSet maybeDetached = FastStringSet.create(); | |||
ValueMap hierarchies = json.getValueMap("hierarchy"); | |||
@@ -2113,6 +2149,8 @@ public class ApplicationConnection { | |||
recursivelyDetach(removed, result.events); | |||
} | |||
Profiler.leave("updateConnectorHierarchy"); | |||
return result; | |||
} | |||
@@ -2200,6 +2238,8 @@ public class ApplicationConnection { | |||
private void handleRpcInvocations(ValueMap json) { | |||
if (json.containsKey("rpc")) { | |||
Profiler.enter("handleRpcInvocations"); | |||
VConsole.log(" * Performing server to client RPC calls"); | |||
JSONArray rpcCalls = new JSONArray( | |||
@@ -2215,8 +2255,9 @@ public class ApplicationConnection { | |||
VConsole.error(e); | |||
} | |||
} | |||
} | |||
Profiler.leave("handleRpcInvocations"); | |||
} | |||
} | |||
}; | |||
@@ -2864,12 +2905,15 @@ public class ApplicationConnection { | |||
*/ | |||
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; | |||
} | |||
@@ -120,13 +120,17 @@ public class ConnectorMap { | |||
} | |||
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) |
@@ -259,6 +259,7 @@ public class LayoutManager { | |||
private void doLayout() { | |||
VConsole.log("Starting layout phase"); | |||
Profiler.enter("LayoutManager phase init"); | |||
FastStringMap<Integer> layoutCounts = FastStringMap.create(); | |||
@@ -293,27 +294,30 @@ public class LayoutManager { | |||
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); | |||
@@ -325,23 +329,33 @@ public class LayoutManager { | |||
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()) { | |||
@@ -356,7 +370,19 @@ public class LayoutManager { | |||
.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); | |||
} | |||
@@ -367,7 +393,18 @@ public class LayoutManager { | |||
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); | |||
} | |||
@@ -388,7 +425,19 @@ public class LayoutManager { | |||
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); | |||
} | |||
@@ -399,7 +448,18 @@ public class LayoutManager { | |||
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); | |||
} | |||
@@ -411,14 +471,14 @@ public class LayoutManager { | |||
} | |||
} | |||
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) { | |||
@@ -439,8 +499,12 @@ public class LayoutManager { | |||
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); | |||
@@ -455,23 +519,30 @@ public class LayoutManager { | |||
} | |||
} | |||
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"); | |||
@@ -485,13 +556,12 @@ public class LayoutManager { | |||
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(); | |||
@@ -523,6 +593,7 @@ public class LayoutManager { | |||
+ Util.getConnectorString(componentConnector | |||
.getParent())); | |||
} | |||
Profiler.enter("Overflow fix apply"); | |||
Element parentElement = componentConnector.getWidget() | |||
.getElement().getParentElement(); | |||
@@ -537,6 +608,7 @@ public class LayoutManager { | |||
} | |||
style.setOverflow(Overflow.HIDDEN); | |||
Profiler.leave("Overflow fix apply"); | |||
} | |||
pendingOverflowFixes.removeAll(delayedOverflowFixes); | |||
@@ -544,6 +616,7 @@ public class LayoutManager { | |||
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 | |||
@@ -551,7 +624,9 @@ public class LayoutManager { | |||
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); | |||
@@ -564,15 +639,19 @@ public class LayoutManager { | |||
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(); | |||
@@ -596,8 +675,11 @@ public class LayoutManager { | |||
.getConnectorId(), false); | |||
} | |||
measureCount += connectorCount; | |||
Profiler.leave("Layout measureAll"); | |||
} | |||
Profiler.enter("Layout measure from tree"); | |||
while (layoutDependencyTree.hasConnectorsToMeasure()) { | |||
JsArrayString measureTargets = layoutDependencyTree | |||
.getMeasureTargetsJsArray(); | |||
@@ -613,10 +695,13 @@ public class LayoutManager { | |||
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); | |||
@@ -625,10 +710,12 @@ public class LayoutManager { | |||
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); | |||
@@ -636,6 +723,7 @@ public class LayoutManager { | |||
if (widthChanged) { | |||
currentDependencyTree.markWidthAsChanged(connector); | |||
} | |||
Profiler.leave("LayoutManager.onConnectorChange"); | |||
} | |||
private void setNeedsOverflowFix(ComponentConnector connector) { | |||
@@ -651,9 +739,11 @@ public class LayoutManager { | |||
} | |||
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"); | |||
} | |||
@@ -673,6 +763,8 @@ public class LayoutManager { | |||
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++) { | |||
@@ -689,6 +781,7 @@ public class LayoutManager { | |||
if (elementResizeListeners.containsKey(element)) { | |||
listenersToFire.add(element); | |||
} | |||
Profiler.leave("LayoutManager.notifyListenersAndDepdendents"); | |||
} | |||
private static boolean isManagedLayout(ComponentConnector connector) { |
@@ -61,6 +61,7 @@ public class LayoutManagerIE8 extends LayoutManager { | |||
@Override | |||
protected void cleanMeasuredSizes() { | |||
Profiler.enter("LayoutManager.cleanMeasuredSizes"); | |||
Document document = RootPanel.get().getElement().getOwnerDocument(); | |||
Iterator<Element> i = measuredSizes.keySet().iterator(); | |||
@@ -70,15 +71,19 @@ public class LayoutManagerIE8 extends LayoutManager { | |||
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"); | |||
} | |||
} |
@@ -185,11 +185,18 @@ public class MeasuredSize { | |||
} | |||
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); | |||
@@ -200,7 +207,9 @@ public class MeasuredSize { | |||
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); | |||
@@ -211,7 +220,9 @@ public class MeasuredSize { | |||
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); | |||
@@ -222,7 +233,9 @@ public class MeasuredSize { | |||
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; | |||
@@ -231,13 +244,18 @@ public class MeasuredSize { | |||
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); | |||
} |
@@ -0,0 +1,365 @@ | |||
/* | |||
* 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; | |||
} | |||
} |
@@ -513,6 +513,23 @@ public class VDebugConsole extends VOverlay implements Console { | |||
// 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) { |
@@ -47,6 +47,7 @@ public class WidgetSet { | |||
* 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); | |||
@@ -56,6 +57,7 @@ public class WidgetSet { | |||
UnknownComponentConnector c = GWT | |||
.create(UnknownComponentConnector.class); | |||
c.setServerSideClassName(serverSideName); | |||
Profiler.leave("WidgetSet.createConnector"); | |||
return c; | |||
} else { | |||
/* | |||
@@ -68,8 +70,10 @@ public class WidgetSet { | |||
((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 |
@@ -32,6 +32,7 @@ import com.vaadin.client.ApplicationConnection; | |||
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; | |||
@@ -128,20 +129,24 @@ public class JsonDecoder { | |||
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) { | |||
@@ -167,12 +172,18 @@ public class JsonDecoder { | |||
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); | |||
} |
@@ -29,6 +29,7 @@ import com.google.gwt.event.shared.HandlerManager; | |||
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; | |||
@@ -110,11 +111,19 @@ public abstract class AbstractConnector implements ServerConnector, | |||
@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"); | |||
} | |||
/** | |||
@@ -200,6 +209,12 @@ public abstract class AbstractConnector implements ServerConnector, | |||
@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); | |||
} | |||
@@ -214,6 +229,10 @@ public abstract class AbstractConnector implements ServerConnector, | |||
} | |||
} | |||
} | |||
if (Profiler.isEnabled()) { | |||
Profiler.leave(profilerKey); | |||
} | |||
} | |||
protected HandlerManager ensureHandlerManager() { | |||
@@ -263,6 +282,7 @@ public abstract class AbstractConnector implements ServerConnector, | |||
@Override | |||
public void onStateChanged(StateChangeEvent stateChangeEvent) { | |||
Profiler.enter("AbstractConnector.onStateChanged"); | |||
if (debugLogging) { | |||
VConsole.log("State change event for " | |||
+ Util.getConnectorString(stateChangeEvent.getConnector()) | |||
@@ -270,6 +290,7 @@ public abstract class AbstractConnector implements ServerConnector, | |||
} | |||
updateEnabledState(isEnabled()); | |||
Profiler.leave("AbstractConnector.onStateChanged"); | |||
} | |||
/* | |||
@@ -296,7 +317,9 @@ public abstract class AbstractConnector implements ServerConnector, | |||
@Override | |||
public SharedState getState() { | |||
if (state == null) { | |||
Profiler.enter("AbstractConnector.createState()"); | |||
state = createState(); | |||
Profiler.leave("AbstractConnector.createState()"); | |||
} | |||
return state; |
@@ -37,6 +37,7 @@ import com.google.gwt.user.client.ui.Widget; | |||
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; | |||
@@ -659,6 +660,8 @@ public class VDragAndDropManager { | |||
if (serverCallback == null) { | |||
return; | |||
} | |||
Profiler.enter("VDragAndDropManager.handleServerResponse"); | |||
UIDL uidl = (UIDL) valueMap.cast(); | |||
int visitId = uidl.getIntAttribute("visitId"); | |||
@@ -668,6 +671,8 @@ public class VDragAndDropManager { | |||
serverCallback = null; | |||
} | |||
runDeferredCommands(); | |||
Profiler.leave("VDragAndDropManager.handleServerResponse"); | |||
} | |||
private void runDeferredCommands() { |
@@ -23,6 +23,7 @@ import com.vaadin.client.ApplicationConnection; | |||
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; | |||
@@ -281,6 +282,7 @@ public abstract class AbstractOrderedLayoutConnector extends | |||
*/ | |||
@Override | |||
public void onConnectorHierarchyChange(ConnectorHierarchyChangeEvent event) { | |||
Profiler.enter("AOLC.onConnectorHierarchyChange"); | |||
List<ComponentConnector> previousChildren = event.getOldChildren(); | |||
int currentIndex = 0; | |||
@@ -289,14 +291,22 @@ public abstract class AbstractOrderedLayoutConnector extends | |||
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); | |||
@@ -309,7 +319,9 @@ public abstract class AbstractOrderedLayoutConnector extends | |||
child.removeStateChangeHandler(childStateChangeHandler); | |||
layout.removeWidget(child.getWidget()); | |||
} | |||
Profiler.leave("AOL.onConnectorHierarchyChange remove children"); | |||
} | |||
Profiler.leave("AOLC.onConnectorHierarchyChange"); | |||
updateInternalState(); | |||
} | |||
@@ -342,6 +354,7 @@ public abstract class AbstractOrderedLayoutConnector extends | |||
if (processedResponseId == lastResponseId) { | |||
return; | |||
} | |||
Profiler.enter("AOLC.updateInternalState"); | |||
// Remember that everything is updated for this response | |||
processedResponseId = lastResponseId; | |||
@@ -422,6 +435,8 @@ public abstract class AbstractOrderedLayoutConnector extends | |||
} else { | |||
getWidget().clearExpand(); | |||
} | |||
Profiler.leave("AOLC.updateInternalState"); | |||
} | |||
/** |