]> source.dussan.org Git - vaadin-framework.git/commitdiff
Add lightweight profiling (#10961)
authorLeif Åstrand <leif@vaadin.com>
Tue, 12 Feb 2013 10:20:29 +0000 (12:20 +0200)
committerLeif Åstrand <leif@vaadin.com>
Wed, 13 Feb 2013 08:02:16 +0000 (10:02 +0200)
Also remove most of the timing information that was previously logged

Change-Id: I8269036a12762eb63f7d4f93aefb6be307dd620a

13 files changed:
client/src/com/vaadin/Vaadin.gwt.xml
client/src/com/vaadin/client/ApplicationConnection.java
client/src/com/vaadin/client/ConnectorMap.java
client/src/com/vaadin/client/LayoutManager.java
client/src/com/vaadin/client/LayoutManagerIE8.java
client/src/com/vaadin/client/MeasuredSize.java
client/src/com/vaadin/client/Profiler.java [new file with mode: 0644]
client/src/com/vaadin/client/VDebugConsole.java
client/src/com/vaadin/client/WidgetSet.java
client/src/com/vaadin/client/communication/JsonDecoder.java
client/src/com/vaadin/client/ui/AbstractConnector.java
client/src/com/vaadin/client/ui/dd/VDragAndDropManager.java
client/src/com/vaadin/client/ui/orderedlayout/AbstractOrderedLayoutConnector.java

index f7d1cf8410b242cbaebae0ba147457b7f0f8ad9d..dcc5b0d29460ea127464098694c2fb92af1901bf 100644 (file)
         <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" />
index 0171d541ea92f2fa52d8c51fa3b09bbdade8907a..44c739765566183ca583dbb2d851f4bbb543980e 100644 (file)
@@ -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;
     }
 
index 50df65397f8548d0c6e34d6e33ba43a2feb8d960..5f6053dd32248d67a2f296c932d9c924d08cf720 100644 (file)
@@ -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)
index d3366e86f3c8aeb00a495651b292554429b5681b..14b155c92f5515b640a2365f44ed28575ca7f4de 100644 (file)
@@ -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) {
index b352e14dc6dd373254b686b8db1d4881028202f2..a692f126a263ebb9191ef5c1fdbcfa6413419e9e 100644 (file)
@@ -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");
     }
 }
index e0928a1702959820f4758114287f24ce16fd81d5..51da8570e6056cf4dcb00d72f11c5ee75290b0fd 100644 (file)
@@ -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);
     }
diff --git a/client/src/com/vaadin/client/Profiler.java b/client/src/com/vaadin/client/Profiler.java
new file mode 100644 (file)
index 0000000..a7b9019
--- /dev/null
@@ -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>&lt;set-property name="vaadin.profiler" value="true" /&gt;</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;
+    }
+
+}
index 2739273fce7de3594900c19efd257f51a2a44765..ee7505876d9f402bc0f6bdb8aab0a01e3497629a 100644 (file)
@@ -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) {
index 8efdd1dee4a5229ee3344c108bd280898c82f299..34e18a5e4eaf247590d097c4127b3ea9623d7519 100644 (file)
@@ -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
index d4d71b3bc45dd48cc0eafddab0fa8dc2123f7d4c..e1ee1fd7b740a1e2317b16b73dd12a04a8e8f499 100644 (file)
@@ -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);
             }
index f9c74cc5c9153776a61695ffe50a56b44b0cf601..898b8cc483fa49851a8aedc63a12033a474f800a 100644 (file)
@@ -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;
index 280e44a9b55d8c4bda4784046e175a97c6a418e8..ffc146ad04910781260264147aeae28007093a67 100644 (file)
@@ -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() {
index 77def89e9e85a7db2be0dd75e5fc3fddc6742b93..50de8e0936ad97f42e4b0c5069d2ced95c2ae143 100644 (file)
@@ -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");
     }
 
     /**