LinkedIn App

diff --git a/assets/vendor-glimmer.js b/assets/vendor-glimmer.js
index a3e7839..2e72ecb 100644
--- a/assets/vendor-glimmer.js
+++ b/assets/vendor-glimmer.js
@@ -1,18 +1,100 @@
 /* jshint ignore:start */
 
-
-
 window.perfs = {};
+window.counts = {};
+window.pending = {};
+window.startTimes = {};
+
 window.startPerfs = function(name) {
   window.perfs[name] = window.perfs[name] || 0;
-  return window.performance.now();
-}
+  window.counts[name] = (window.counts[name] || 0) + 1;
 
-window.endPerfs = function(name, start) {
-  var delta = window.performance.now() - start;
-  window.perfs[name] += delta;
-}
+  if (!window.pending[name]) {
+    window.pending[name] = 1;
+    window.startTimes[name] = window.performance.now();
+  }
+};
+
+window.endPerfs = function(name) {
+  if (--window.pending[name] === 0) {
+    var delta = window.performance.now() - window.startTimes[name];
+    window.perfs[name] += delta;
+    window.startTimes[name] = undefined;
+  }
+};
+
+window.reportPerfs = function() {
+  console.log("*****" + window.performance.now().toFixed(3) + "*****");
+  localStorage.perfs = localStorage.perfs || JSON.stringify([]);
+  var storedPerfs = JSON.parse(localStorage.perfs);
+  storedPerfs.push(perfs);
+  localStorage.perfs = JSON.stringify(storedPerfs);
+
+  storedPerfs = storedPerfs.map(function(p) {
+    var obj = {};
+    Object.keys(p).forEach(function(key) {
+      obj[key] = parseFloat(p[key].toFixed(3));
+    });
+    return obj;
+  });
+
+  var keys = ['render', 'initial.render', 'rerender.render', 'eval', 'app.eval', 'vendor.eval', 'compile', 'lookup.component', 'create.component', '@component', 'link-to.@component', 'fast-link-to.@component'];
+
+  var normalizedPerfs = {};
+  var normalizedCounts = {};
+  var componentKeys = [];
+  var moduleKeys = [];
+
+  Object.keys(perfs).forEach(function(key) {
+    var parts = key.split('.');
+    if (parts.length > 1) {
+      var last = parts[parts.length - 1];
+      normalizedPerfs[last] = normalizedPerfs[last] || 0;
+      normalizedPerfs[last] += perfs[key];
+      normalizedCounts[last] = normalizedCounts[last] || 0;
+      normalizedCounts[last] += counts[key];
+
+      if (last === '@component') {
+        componentKeys.push(key);
+      }
+
+      if (last === '@module') {
+        moduleKeys.push(key);
+      }
+    }
+
+    normalizedPerfs[key] = perfs[key];
+    normalizedCounts[key] = counts[key];
+  });
 
+  var reporting = keys.map(function(key) {
+    return "" + key.toUpperCase() + " (" + normalizedCounts[key] + ") " + normalizedPerfs[key].toFixed(3);
+  }).join("\n");
+
+  console.log(">>>>>" + reporting + "<<<<<");
+
+  var sortedComponents = componentKeys.sort(function(a,b) {
+    return perfs[b] - perfs[a];
+  });
+
+  var componentsReporting = sortedComponents.map(function(key) {
+    return "" + key.slice(0,-11) + " (" + counts[key] + ") " + perfs[key].toFixed(3) + " @ " + (perfs[key]/counts[key]).toFixed(3);
+  }).join("\n");
+
+  console.log("$$$$$" + componentsReporting + "$$$$$");
+
+  var sortedModules = moduleKeys.sort(function(a,b) {
+    return perfs[b] - perfs[a];
+  });
+
+  var modulesReporting = sortedModules.map(function(key) {
+    return "" + key.slice(0,-8) + " " + perfs[key].toFixed(3);
+  }).join("\n");
+
+  console.log("#####" + modulesReporting + "#####");
+};
+
+window.startPerfs('vendor.eval');
 
 window.EmberENV = {"FEATURES":{"ember-glimmer":true}};
 var runningTests = false;
@@ -10347,7 +10429,9 @@ var mainContext = this;
         }
       }
 
+      window.startPerfs(name + ".@module");
       callback.apply(this, reified);
+      window.endPerfs(name + ".@module");
 
       return exports;
     }
@@ -20413,6 +20497,7 @@ enifed('ember-glimmer/syntax/curly-component', ['exports', 'glimmer-runtime', 'e
     }
 
     CurlyComponentManager.prototype.create = function create(definition, args, dynamicScope, hasBlock) {
+      window.startPerfs('create.component');
       var parentView = dynamicScope.view;
 
       var klass = definition.ComponentClass;
@@ -20430,6 +20515,8 @@ enifed('ember-glimmer/syntax/curly-component', ['exports', 'glimmer-runtime', 'e
 
       var component = klass.create(props);
 
+      window.endPerfs('create.component');
+
       dynamicScope.view = component;
       parentView.appendChild(component);
 
@@ -21205,7 +21292,7 @@ enifed('ember-glimmer/utils/lookup-component', ['exports'], function (exports) {
   }
 
   function lookupComponent(owner, name, options) {
-    var start = window.startPerfs('lookupComponent');
+    window.startPerfs('lookup.component');
     var componentLookup = owner.lookup('component-lookup:main');
 
     var source = options && options.source;
@@ -21219,7 +21306,7 @@ enifed('ember-glimmer/utils/lookup-component', ['exports'], function (exports) {
     }
 
     var pair = lookupComponentPair(componentLookup, owner, name);
-    window.endPerfs('lookupComponent', start)
+    window.endPerfs('lookup.component');
     return pair;
   }
 });
@@ -64261,6 +64352,12 @@ enifed('glimmer-runtime/lib/compiled/opcodes/component', ['exports', 'glimmer-ru
             var layout = _glimmerRuntimeLibCompiler.layoutFor(definition, vm.env);
             var callerScope = vm.scope();
             var selfRef = manager.getSelf(component);
+
+            var componentName = selfRef.inner._debugContainerKey;
+            if (componentName) {
+              window.startPerfs(componentName.substr(10) + '.@component');
+            }
+
             vm.pushRootScope(selfRef, layout.symbols);
             vm.invokeLayout({ templates: templates, args: args, shadow: shadow, layout: layout, callerScope: callerScope });
             vm.env.didCreate(component, manager);
@@ -64421,6 +64518,12 @@ enifed('glimmer-runtime/lib/compiled/opcodes/component', ['exports', 'glimmer-ru
         }
 
         CloseComponentOpcode.prototype.evaluate = function evaluate(vm) {
+            var component = vm.getSelf().inner;
+            var componentName = component._debugContainerKey;
+            if (componentName) {
+              window.endPerfs(componentName.substr(10) + '.@component');
+            }
+
             vm.popScope();
             vm.popDynamicScope();
             vm.commitCacheGroup();
@@ -66433,10 +66536,7 @@ enifed('glimmer-runtime/lib/compiler', ['exports', 'glimmer-util', 'glimmer-runt
         }
 
         EntryPointCompiler.prototype.compile = function compile() {
-            window.perfs = window.perfs || {};
-            window.perfs["epc.compile"] = window.perfs["epc.compile"] || 0;
-
-            var start = window.performance.now();
+            window.startPerfs('epc.compile');
 
             var block = this.block;
             var ops = this.ops;
@@ -66449,8 +66549,7 @@ enifed('glimmer-runtime/lib/compiler', ['exports', 'glimmer-util', 'glimmer-runt
                 current = next;
             }
 
-            var delta = window.performance.now() - start;
-            window.perfs["epc.compile"] += delta;
+            window.endPerfs('epc.compile');
 
             return ops.toOpSeq();
         };
@@ -66487,9 +66586,8 @@ enifed('glimmer-runtime/lib/compiler', ['exports', 'glimmer-util', 'glimmer-runt
         }
 
         InlineBlockCompiler.prototype.compile = function compile() {
-            window.perfs = window.perfs || {};
-            window.perfs["ibc.compile"] = window.perfs["ibc.compile"] || 0;
-            var start = window.performance.now();
+            window.startPerfs('ibc.compile');
+
             var block = this.block;
             var ops = this.ops;
             var program = block.program;
@@ -66503,8 +66601,9 @@ enifed('glimmer-runtime/lib/compiler', ['exports', 'glimmer-util', 'glimmer-runt
                 this.compileStatement(current, ops);
                 current = next;
             }
-            var delta = window.performance.now() - start;
-            window.perfs["ibc.compile"] += delta;
+
+            window.endPerfs('ibc.compile');
+
             return ops;
         };
 
@@ -66541,14 +66640,11 @@ enifed('glimmer-runtime/lib/compiler', ['exports', 'glimmer-util', 'glimmer-runt
         };
 
         ComponentLayoutBuilder.prototype.compile = function compile() {
-            window.perfs = window.perfs || {};
-            window.perfs["clb.compile"] = window.perfs["clb.compile"] || 0;
-            var start = window.performance.now();
+            window.startPerfs('clb.compile');
 
             var inner = this.inner.compile();
 
-            var delta = window.performance.now() - start;
-            window.perfs["clb.compile"] += delta;
+            window.endPerfs('clb.compile');
 
             return inner;
         };
@@ -69621,6 +69717,7 @@ enifed('glimmer-runtime/lib/template', ['exports', 'glimmer-runtime/lib/builder'
         };
 
         Template.prototype.render = function render(self, env, _ref2) {
+            window.startPerfs('initial.render');
             var dynamicScope = _ref2.dynamicScope;
             var appendTo = _ref2.appendTo;
             var blockArguments = arguments.length <= 3 || arguments[3] === undefined ? null : arguments[3];
@@ -69628,7 +69725,9 @@ enifed('glimmer-runtime/lib/template', ['exports', 'glimmer-runtime/lib/builder'
             var elementStack = _glimmerRuntimeLibBuilder.ElementStack.forInitialRender({ dom: env.getDOM(), parentNode: appendTo, nextSibling: null });
             var compiled = this.raw.compile(env);
             var vm = _glimmerRuntimeLibVm.VM.initial(env, { self: self, dynamicScope: dynamicScope, elementStack: elementStack, size: compiled.symbols });
-            return vm.execute(compiled.ops);
+            var result = vm.execute(compiled.ops);
+            window.endPerfs('initial.render');
+            return result;
         };
 
         return Template;
@@ -70329,6 +70428,7 @@ enifed("glimmer-runtime/lib/vm/render-result", ["exports", "glimmer-runtime/lib/
         }
 
         RenderResult.prototype.rerender = function rerender() {
+            window.startPerfs('rerender.render');
             var env = this.env;
             var updating = this.updating;
 
@@ -70336,6 +70436,8 @@ enifed("glimmer-runtime/lib/vm/render-result", ["exports", "glimmer-runtime/lib/
             var vm = new _glimmerRuntimeLibVmUpdate.default(env);
             vm.execute(updating, this);
             env.commit();
+            window.endPerfs('rerender.render');
+            window.reportPerfs();
         };
 
         RenderResult.prototype.parentElement = function parentElement() {
@@ -113340,5 +113442,5 @@ if (typeof window !== 'undefined' && window && window.performance && window.perf
   }
 }
 
-
+window.endPerfs('vendor.eval');
 /* jshint ignore:end */
diff --git a/assets/vendor-htmlbars.js b/assets/vendor-htmlbars.js
index 24e7535..2bacdcb 100644
--- a/assets/vendor-htmlbars.js
+++ b/assets/vendor-htmlbars.js
@@ -1,18 +1,100 @@
 /* jshint ignore:start */
 
-
-
 window.perfs = {};
+window.counts = {};
+window.pending = {};
+window.startTimes = {};
+
 window.startPerfs = function(name) {
   window.perfs[name] = window.perfs[name] || 0;
-  return window.performance.now();
-}
+  window.counts[name] = (window.counts[name] || 0) + 1;
 
-window.endPerfs = function(name, start) {
-  var delta = window.performance.now() - start;
-  window.perfs[name] += delta;
-}
+  if (!window.pending[name]) {
+    window.pending[name] = 1;
+    window.startTimes[name] = window.performance.now();
+  }
+};
+
+window.endPerfs = function(name) {
+  if (--window.pending[name] === 0) {
+    var delta = window.performance.now() - window.startTimes[name];
+    window.perfs[name] += delta;
+    window.startTimes[name] = undefined;
+  }
+};
+
+window.reportPerfs = function() {
+  console.log("*****" + window.performance.now().toFixed(3) + "*****");
+  localStorage.perfs = localStorage.perfs || JSON.stringify([]);
+  var storedPerfs = JSON.parse(localStorage.perfs);
+  storedPerfs.push(perfs);
+  localStorage.perfs = JSON.stringify(storedPerfs);
 
+  storedPerfs = storedPerfs.map(function(p) {
+    var obj = {};
+    Object.keys(p).forEach(function(key) {
+      obj[key] = parseFloat(p[key].toFixed(3));
+    });
+    return obj;
+  });
+
+  var keys = ['render', 'initial.render', 'rerender.render', 'eval', 'app.eval', 'vendor.eval', 'lookup.component', 'create.component', '@component', 'link-to.@component', 'fast-link-to.@component'];
+
+  var normalizedPerfs = {};
+  var normalizedCounts = {};
+  var componentKeys = [];
+  var moduleKeys = [];
+
+  Object.keys(perfs).forEach(function(key) {
+    var parts = key.split('.');
+    if (parts.length > 1) {
+      var last = parts[parts.length - 1];
+      normalizedPerfs[last] = normalizedPerfs[last] || 0;
+      normalizedPerfs[last] += perfs[key];
+      normalizedCounts[last] = normalizedCounts[last] || 0;
+      normalizedCounts[last] += counts[key];
+
+      if (last === '@component') {
+        componentKeys.push(key);
+      }
+
+      if (last === '@module') {
+        moduleKeys.push(key);
+      }
+    }
+
+    normalizedPerfs[key] = perfs[key];
+    normalizedCounts[key] = counts[key];
+  });
+
+  var reporting = keys.map(function(key) {
+    return "" + key.toUpperCase() + " (" + normalizedCounts[key] + ") " + normalizedPerfs[key].toFixed(3);
+  }).join("\n");
+
+  console.log(">>>>>" + reporting + "<<<<<");
+
+  var sortedComponents = componentKeys.sort(function(a,b) {
+    return perfs[b] - perfs[a];
+  });
+
+  var componentsReporting = sortedComponents.map(function(key) {
+    return "" + key.slice(0,-11) + " (" + counts[key] + ") " + perfs[key].toFixed(3) + " @ " + (perfs[key]/counts[key]).toFixed(3);
+  }).join("\n");
+
+  console.log("$$$$$" + componentsReporting + "$$$$$");
+
+  var sortedModules = moduleKeys.sort(function(a,b) {
+    return perfs[b] - perfs[a];
+  });
+
+  var modulesReporting = sortedModules.map(function(key) {
+    return "" + key.slice(0,-8) + " " + perfs[key].toFixed(3);
+  }).join("\n");
+
+  console.log("#####" + modulesReporting + "#####");
+};
+
+window.startPerfs('vendor.eval');
 
 window.EmberENV = {"FEATURES":{}};
 var runningTests = false;
@@ -10267,7 +10349,9 @@ Em._eager = ["require","ember-metal/debug","ember-metal/core","ember-metal/assig
         }
       }
 
+      window.startPerfs(name + ".@module");
       mod.callback.apply(undefined, reified);
+      window.endPerfs(name + ".@module");
 
       return exports;
     }
@@ -36065,17 +36149,21 @@ Em.__loader._define("rsvp/platform", ["exports"], function (exports) {
   };
 
   Renderer.prototype.renderTopLevelView = function Renderer_renderTopLevelView(view, renderNode) {
+    window.startPerfs('initial.render');
     // Check to see if insertion has been canceled
     if (view._willInsert) {
       view._willInsert = false;
       this.prerenderTopLevelView(view, renderNode);
       this.dispatchLifecycleHooks(view.env);
     }
+
+    window.endPerfs('initial.render');
   };
 
   Renderer.prototype.revalidateTopLevelView = function Renderer_revalidateTopLevelView(view) {
     // This guard prevents revalidation on an already-destroyed view.
     if (view._renderNode.lastResult) {
+      window.startPerfs('rerender.render');
       view._renderNode.lastResult.revalidate(view.env);
       // supports createElement, which operates without moving the view into
       // the inDOM state.
@@ -36083,6 +36171,8 @@ Em.__loader._define("rsvp/platform", ["exports"], function (exports) {
         this.dispatchLifecycleHooks(view.env);
       }
       this.clearRenderedViews(view.env);
+      window.endPerfs('rerender.render');
+      window.reportPerfs();
     }
   };
 
@@ -53269,6 +53359,7 @@ Em.__loader._define("rsvp/platform", ["exports"], function (exports) {
   exports.default = ComponentNodeManager;
 
   ComponentNodeManager.create = function ComponentNodeManager_create(renderNode, env, options) {
+    window.startPerfs('create.component');
     var _createOptions;
 
     var tagName = options.tagName;
@@ -53318,6 +53409,8 @@ Em.__loader._define("rsvp/platform", ["exports"], function (exports) {
 
     var results = _emberViewsSystemBuildComponentTemplate.default({ layout: layout, component: component, isAngleBracket: isAngleBracket }, attrs, { templates: templates, scope: parentScope });
 
+    window.endPerfs('create.component');
+
     return new ComponentNodeManager(component, isAngleBracket, parentScope, renderNode, attrs, results.block, results.createdElement);
   };
 
@@ -53353,6 +53446,11 @@ Em.__loader._define("rsvp/platform", ["exports"], function (exports) {
       env.renderer.componentWillRender(component);
       env.renderedViews.push(component.elementId);
 
+      var componentName = component._debugContainerKey;
+      if (componentName) {
+        window.startPerfs(componentName.substr(10) + '.@component');
+      }
+
       if (this.block) {
         this.block.invoke(env, [], undefined, this.renderNode, this.scope, visitor);
       }
@@ -53373,6 +53471,10 @@ Em.__loader._define("rsvp/platform", ["exports"], function (exports) {
         }
       }
 
+      if (componentName) {
+        window.endPerfs(componentName.substr(10) + '.@component');
+      }
+
       // In environments like FastBoot, disable any hooks that would cause the component
       // to access the DOM directly.
       if (env.destinedForDOM) {
@@ -60451,14 +60553,14 @@ Em.__loader._define("rsvp/platform", ["exports"], function (exports) {
   exports.default = lookupComponent;
 
   function lookupComponent(container, tagName) {
-    var start = window.startPerfs('lookupComponent');
+    window.startPerfs('lookup.component');
     var componentLookup = container.lookup('component-lookup:main');
 
     var pair = {
       component: componentLookup.componentFor(tagName, container),
       layout: componentLookup.layoutFor(tagName, container)
     };
-    window.endPerfs('lookupComponent', start);
+    window.endPerfs('lookup.component');
     return pair;
   }
 })(Em._e[341]);
@@ -101419,4 +101521,5 @@ if (typeof window !== 'undefined' && window && window.performance && window.perf
 }
 
 
+window.endPerfs('vendor.eval', window.startEvalVendor);
 /* jshint ignore:end */
diff --git a/assets/voyager-web-glimmer.js b/assets/voyager-web-glimmer.js
index d7ec60f..335beae 100644
--- a/assets/voyager-web-glimmer.js
+++ b/assets/voyager-web-glimmer.js
@@ -2,6 +2,8 @@
 
 /* jshint ignore:start */
 
+window.startAppEval = window.startPerfs('app.eval');
+
 if (typeof window !== 'undefined' && window && window.performance && window.performance.mark) {
   window.performance.mark('mark_app_start');
 }
@@ -119172,5 +119174,6 @@ if (typeof window !== 'undefined' && window && window.performance && window.perf
   }
 }
 
+window.endPerfs('app.eval', startAppEval);
 
 /* jshint ignore:end */
diff --git a/assets/voyager-web-htmlbars.js b/assets/voyager-web-htmlbars.js
index 764b6fd..f4ec713 100644
--- a/assets/voyager-web-htmlbars.js
+++ b/assets/voyager-web-htmlbars.js
@@ -2,11 +2,12 @@
 
 /* jshint ignore:start */
 
+window.startAppEval = window.startPerfs('app.eval');
+
 if (typeof window !== 'undefined' && window && window.performance && window.performance.mark) {
   window.performance.mark('mark_app_start');
 }
 
-
 /* jshint ignore:end */
 
 define('voyager-web/adapters/application', ['exports', 'ember', 'ember-data', 'voyager-web/mixins/multiplexed-adapter', 'ember-cli-pemberly-rum-tracking/mixins/rum-tree', 'ember-restli/mixins/restli-encode-adapter', 'ember-cli-bpr/mixins/datawarm-adapter', 'ember-cli-pemberly-tracking/classes/page-instance', 'voyager-web/config/environment', 'voyager-web/utils/headers', 'voyager-web/utils/path-for-type-map', 'npm:@linkedin/pemberly-environment'], function (exports, _ember, _emberData, _voyagerWebMixinsMultiplexedAdapter, _emberCliPemberlyRumTrackingMixinsRumTree, _emberRestliMixinsRestliEncodeAdapter, _emberCliBprMixinsDatawarmAdapter, _emberCliPemberlyTrackingClassesPageInstance, _voyagerWebConfigEnvironment, _voyagerWebUtilsHeaders, _voyagerWebUtilsPathForTypeMap, _npmLinkedinPemberlyEnvironment) {
@@ -151454,5 +151455,6 @@ if (typeof window !== 'undefined' && window && window.performance && window.perf
   }
 }
 
+window.endPerfs('app.eval', startAppEval);
 
 /* jshint ignore:end */

Glimmer vs. Glimmer2

Quick Perf Analysis

Top-Line Results

  • Orthogonal optimizations
    • LI "eager module" optimization is 10-15%
    • LI "string module" optimization is about 5%
  • Glimmer 2 is ~25% faster than Glimmer 1
    • apples-to-apples
    • in terms of total time-to-first-byte

Performance Analysis

deck

By Yehuda Katz

Loading comments...

More from Yehuda Katz