Repository: GoogleChrome/lighthouse
Pull request #7728 (2019-03-27 03:48:32)

core(main-thread-tasks): handle last task not finishing
**Summary**
Treats `'B'` events without a corresponding `'E'` as if they ended at the time of trace end.

**Related Issues/PRs**
#7691 


Hoten: Looks good. I'll verify in Canary now.

Patch:
diff --git a/lighthouse-core/audits/main-thread-tasks.js b/lighthouse-core/audits/main-thread-tasks.js
index 437b0bbef..1399e6248 100644
--- a/lighthouse-core/audits/main-thread-tasks.js
+++ b/lighthouse-core/audits/main-thread-tasks.js
@@ -32,10 +32,10 @@ class MainThreadTasks extends Audit {
     const tasks = await MainThreadTasksComputed.request(trace, context);
 
     const results = tasks
-      .filter(task => task.duration > 5 && task.parent)
+      // Filter to just the sizable toplevel tasks; toplevel tasks are tasks without a parent.
+      .filter(task => task.duration > 5 && !task.parent)
       .map(task => {
         return {
-          type: task.group.id,
           duration: task.duration,
           startTime: task.startTime,
         };
@@ -43,7 +43,6 @@ class MainThreadTasks extends Audit {
 
     /** @type {LH.Audit.Details.Table['headings']} */
     const headings = [
-      {key: 'type', itemType: 'text', text: 'Task Type'},
       {key: 'startTime', itemType: 'ms', granularity: 1, text: 'Start Time'},
       {key: 'duration', itemType: 'ms', granularity: 1, text: 'End Time'},
     ];
diff --git a/lighthouse-core/computed/main-thread-tasks.js b/lighthouse-core/computed/main-thread-tasks.js
index e66eab62c..af38bd441 100644
--- a/lighthouse-core/computed/main-thread-tasks.js
+++ b/lighthouse-core/computed/main-thread-tasks.js
@@ -74,9 +74,10 @@ class MainThreadTasks {
   /**
    * @param {LH.TraceEvent[]} mainThreadEvents
    * @param {PriorTaskData} priorTaskData
+   * @param {number} traceEndTs
    * @return {TaskNode[]}
    */
-  static _createTasksFromEvents(mainThreadEvents, priorTaskData) {
+  static _createTasksFromEvents(mainThreadEvents, priorTaskData, traceEndTs) {
     /** @type {TaskNode[]} */
     const tasks = [];
     /** @type {TaskNode|undefined} */
@@ -133,6 +134,14 @@ class MainThreadTasks {
       }
     }
 
+    // Starting from the last and bottom-most task, we finish any tasks that didn't end yet.
+    while (currentTask && !Number.isFinite(currentTask.endTime)) {
+      // The last event didn't finish before tracing stopped, use traceEnd timestamp instead.
+      currentTask.endTime = traceEndTs;
+      currentTask = currentTask.parent;
+    }
+
+    // At this point we expect all tasks to have a finite startTime and endTime.
     return tasks;
   }
 
@@ -215,12 +224,13 @@ class MainThreadTasks {
 
   /**
    * @param {LH.TraceEvent[]} traceEvents
+   * @param {number} traceEndTs
    * @return {TaskNode[]}
    */
-  static getMainThreadTasks(traceEvents) {
+  static getMainThreadTasks(traceEvents, traceEndTs) {
     const timers = new Map();
     const priorTaskData = {timers};
-    const tasks = MainThreadTasks._createTasksFromEvents(traceEvents, priorTaskData);
+    const tasks = MainThreadTasks._createTasksFromEvents(traceEvents, priorTaskData, traceEndTs);
 
     // Compute the recursive properties we couldn't compute earlier, starting at the toplevel tasks
     for (const task of tasks) {
@@ -254,8 +264,8 @@ class MainThreadTasks {
    * @return {Promise<Array<TaskNode>>} networkRecords
    */
   static async compute_(trace, context) {
-    const {mainThreadEvents} = await TraceOfTab.request(trace, context);
-    return MainThreadTasks.getMainThreadTasks(mainThreadEvents);
+    const {mainThreadEvents, timestamps} = await TraceOfTab.request(trace, context);
+    return MainThreadTasks.getMainThreadTasks(mainThreadEvents, timestamps.traceEnd);
   }
 }
 
diff --git a/proto/sample_v2_round_trip.json b/proto/sample_v2_round_trip.json
index 3bc2761a1..ed7cd2fe6 100644
--- a/proto/sample_v2_round_trip.json
+++ b/proto/sample_v2_round_trip.json
@@ -1248,11 +1248,6 @@
             "description": "Lists the toplevel main thread tasks that executed during page load.", 
             "details": {
                 "headings": [
-                    {
-                        "itemType": "text", 
-                        "key": "type", 
-                        "text": "Task Type"
-                    }, 
                     {
                         "granularity": 1.0, 
                         "itemType": "ms", 
@@ -1268,199 +1263,68 @@
                 ], 
                 "items": [
                     {
-                        "duration": 26.823, 
-                        "startTime": 604.125, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 23.175, 
-                        "startTime": 606.246, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 5.89, 
-                        "startTime": 631.458, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 18.85, 
-                        "startTime": 638.562, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 16.58, 
-                        "startTime": 638.577, 
-                        "type": "parseHTML"
-                    }, 
-                    {
-                        "duration": 12.522, 
-                        "startTime": 638.586, 
-                        "type": "parseHTML"
-                    }, 
-                    {
-                        "duration": 5.897, 
-                        "startTime": 668.051, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 5.046, 
-                        "startTime": 668.09, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 5.516, 
-                        "startTime": 2643.396, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 979.165, 
-                        "startTime": 2857.942, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 5.803, 
-                        "startTime": 2858.62, 
-                        "type": "scriptEvaluation"
-                    }, 
-                    {
-                        "duration": 970.698, 
-                        "startTime": 2865.033, 
-                        "type": "parseHTML"
-                    }, 
-                    {
-                        "duration": 19.463, 
-                        "startTime": 2866.527, 
-                        "type": "parseHTML"
-                    }, 
-                    {
-                        "duration": 19.21, 
-                        "startTime": 2866.571, 
-                        "type": "scriptEvaluation"
-                    }, 
-                    {
-                        "duration": 945.898, 
-                        "startTime": 2889.816, 
-                        "type": "parseHTML"
-                    }, 
-                    {
-                        "duration": 944.888, 
-                        "startTime": 2890.118, 
-                        "type": "scriptEvaluation"
-                    }, 
-                    {
-                        "duration": 9.047, 
-                        "startTime": 3023.783, 
-                        "type": "scriptEvaluation"
-                    }, 
-                    {
-                        "duration": 5.97, 
-                        "startTime": 3023.842, 
-                        "type": "garbageCollection"
-                    }, 
-                    {
-                        "duration": 706.85, 
-                        "startTime": 3070.433, 
-                        "type": "scriptEvaluation"
-                    }, 
-                    {
-                        "duration": 123.208, 
-                        "startTime": 3840.307, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 123.116, 
-                        "startTime": 3840.313, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 30.142, 
-                        "startTime": 3840.667, 
-                        "type": "styleLayout"
-                    }, 
-                    {
-                        "duration": 87.039, 
-                        "startTime": 3870.824, 
-                        "type": "other"
-                    }, 
-                    {
-                        "duration": 86.959, 
-                        "startTime": 3870.844, 
-                        "type": "styleLayout"
+                        "duration": 5.272, 
+                        "startTime": 598.738
                     }, 
                     {
-                        "duration": 85.493, 
-                        "startTime": 3871.238, 
-                        "type": "styleLayout"
+                        "duration": 26.926, 
+                        "startTime": 604.035
                     }, 
                     {
-                        "duration": 94.261, 
-                        "startTime": 3996.555, 
-                        "type": "other"
+                        "duration": 6.681, 
+                        "startTime": 630.994
                     }, 
                     {
-                        "duration": 90.663, 
-                        "startTime": 3997.797, 
-                        "type": "scriptEvaluation"
+                        "duration": 19.718, 
+                        "startTime": 637.706
                     }, 
                     {
-                        "duration": 5.709, 
-                        "startTime": 4019.279, 
-                        "type": "garbageCollection"
+                        "duration": 7.812, 
+                        "startTime": 666.147
                     }, 
                     {
-                        "duration": 5.151, 
-                        "startTime": 4098.541, 
-                        "type": "other"
+                        "duration": 10.087, 
+                        "startTime": 2639.59
                     }, 
                     {
-                        "duration": 122.537, 
-                        "startTime": 4808.624, 
-                        "type": "other"
+                        "duration": 983.081, 
+                        "startTime": 2854.095
                     }, 
                     {
-                        "duration": 82.741, 
-                        "startTime": 4810.0, 
-                        "type": "scriptEvaluation"
+                        "duration": 123.752, 
+                        "startTime": 3839.839
                     }, 
                     {
-                        "duration": 36.919, 
-                        "startTime": 4893.397, 
-                        "type": "parseHTML"
+                        "duration": 5.338, 
+                        "startTime": 3980.383
                     }, 
                     {
-                        "duration": 36.866, 
-                        "startTime": 4893.44, 
-                        "type": "parseHTML"
+                        "duration": 6.574, 
+                        "startTime": 3986.1
                     }, 
                     {
-                        "duration": 10.58, 
-                        "startTime": 4894.119, 
-                        "type": "scriptEvaluation"
+                        "duration": 96.198, 
+                        "startTime": 3996.134
                     }, 
                     {
-                        "duration": 9.353, 
-                        "startTime": 4894.151, 
-                        "type": "scriptEvaluation"
+                        "duration": 9.23, 
+                        "startTime": 4098.379
                     }, 
                     {
-                        "duration": 22.297, 
-                        "startTime": 4905.447, 
-                        "type": "parseHTML"
+                        "duration": 5.463, 
+                        "startTime": 4784.783
                     }, 
                     {
-                        "duration": 6.849, 
-                        "startTime": 8603.435, 
-                        "type": "other"
+                        "duration": 127.282, 
+                        "startTime": 4808.602
                     }, 
                     {
-                        "duration": 7.076, 
-                        "startTime": 10219.463, 
-                        "type": "other"
+                        "duration": 6.885, 
+                        "startTime": 8603.411
                     }, 
                     {
-                        "duration": 6.983, 
-                        "startTime": 10219.523, 
-                        "type": "scriptEvaluation"
+                        "duration": 7.258, 
+                        "startTime": 10219.292
                     }
                 ], 
                 "type": "table"


Test patch:
diff --git a/lighthouse-core/test/audits/main-thread-tasks-test.js b/lighthouse-core/test/audits/main-thread-tasks-test.js
index fe34b94f2..9840afe62 100644
--- a/lighthouse-core/test/audits/main-thread-tasks-test.js
+++ b/lighthouse-core/test/audits/main-thread-tasks-test.js
@@ -15,7 +15,7 @@ describe('Main thread tasks audit', () => {
   it('should work', async () => {
     const artifacts = {traces: {defaultPass: acceptableTrace}};
     const result = await MainThreadTasks.audit(artifacts, {computedCache: new Map()});
-    expect(result.details.items).toHaveLength(76);
+    expect(result.details.items).toHaveLength(39);
 
     for (const item of result.details.items) {
       expect(Number.isFinite(item.startTime)).toBeTruthy();
diff --git a/lighthouse-core/test/computed/main-thread-tasks-test.js b/lighthouse-core/test/computed/main-thread-tasks-test.js
index e3babd95e..7dbca9dd7 100644
--- a/lighthouse-core/test/computed/main-thread-tasks-test.js
+++ b/lighthouse-core/test/computed/main-thread-tasks-test.js
@@ -143,4 +143,56 @@ describe('MainResource computed artifact', () => {
     assert.deepStrictEqual(taskC.attributableURLs, ['urlB.1', 'urlB.2', 'urlC']);
     assert.deepStrictEqual(taskD.attributableURLs, ['urlB.1', 'urlB.2', 'urlC', 'urlD']);
   });
+
+  it('should handle the last trace event not ending', async () => {
+    /*
+    An artistic rendering of the below trace:
+    █████████████████████████████TaskA████████████|
+          ████████████████TaskB███████████████████|
+                                            █TaskC|
+                                                  ^ trace abruptly ended
+    */
+    const traceEvents = [
+      ...boilerplateTrace,
+      // These events would normally be accompanied by an 'E' event
+      {ph: 'B', name: 'TaskA', pid, tid, ts: baseTs, args},
+      {ph: 'B', name: 'TaskB', pid, tid, ts: baseTs + 5e3, args},
+      {ph: 'B', name: 'TaskC', pid, tid, ts: baseTs + 100e3, args},
+    ];
+
+    traceEvents.forEach(evt => Object.assign(evt, {cat: 'devtools.timeline'}));
+
+    const context = {computedCache: new Map()};
+    const tasks = await MainThreadTasks.request({traceEvents}, context);
+    expect(tasks).toHaveLength(3);
+
+    const taskA = tasks.find(task => task.event.name === 'TaskA');
+    const taskB = tasks.find(task => task.event.name === 'TaskB');
+    const taskC = tasks.find(task => task.event.name === 'TaskC');
+    expect(taskA).toEqual({
+      parent: undefined,
+      attributableURLs: [],
+
+      children: [taskB],
+      event: traceEvents[3],
+      startTime: 0,
+      endTime: 100,
+      duration: 100,
+      selfTime: 5,
+      group: taskGroups.other,
+    });
+
+    expect(taskB).toEqual({
+      parent: taskA,
+      attributableURLs: [],
+
+      children: [taskC],
+      event: traceEvents[4],
+      startTime: 5,
+      endTime: 100,
+      duration: 95,
+      selfTime: 95,
+      group: taskGroups.other,
+    });
+  });
 });
diff --git a/lighthouse-core/test/results/sample_v2.json b/lighthouse-core/test/results/sample_v2.json
index 746d3435c..7f803ce0e 100644
--- a/lighthouse-core/test/results/sample_v2.json
+++ b/lighthouse-core/test/results/sample_v2.json
@@ -1150,15 +1150,10 @@
       "description": "Lists the toplevel main thread tasks that executed during page load.",
       "score": null,
       "scoreDisplayMode": "informative",
-      "rawValue": 39,
+      "rawValue": 16,
       "details": {
         "type": "table",
         "headings": [
-          {
-            "key": "type",
-            "itemType": "text",
-            "text": "Task Type"
-          },
           {
             "key": "startTime",
             "itemType": "ms",
@@ -1174,199 +1169,68 @@
         ],
         "items": [
           {
-            "type": "other",
-            "duration": 26.823,
-            "startTime": 604.125
-          },
-          {
-            "type": "other",
-            "duration": 23.175,
-            "startTime": 606.246
-          },
-          {
-            "type": "other",
-            "duration": 5.89,
-            "startTime": 631.458
-          },
-          {
-            "type": "other",
-            "duration": 18.85,
-            "startTime": 638.562
-          },
-          {
-            "type": "parseHTML",
-            "duration": 16.58,
-            "startTime": 638.577
-          },
-          {
-            "type": "parseHTML",
-            "duration": 12.522,
-            "startTime": 638.586
-          },
-          {
-            "type": "other",
-            "duration": 5.897,
-            "startTime": 668.051
-          },
-          {
-            "type": "other",
-            "duration": 5.046,
-            "startTime": 668.09
-          },
-          {
-            "type": "other",
-            "duration": 5.516,
-            "startTime": 2643.396
-          },
-          {
-            "type": "other",
-            "duration": 979.165,
-            "startTime": 2857.942
-          },
-          {
-            "type": "scriptEvaluation",
-            "duration": 5.803,
-            "startTime": 2858.62
-          },
-          {
-            "type": "parseHTML",
-            "duration": 970.698,
-            "startTime": 2865.033
-          },
-          {
-            "type": "parseHTML",
-            "duration": 19.463,
-            "startTime": 2866.527
-          },
-          {
-            "type": "scriptEvaluation",
-            "duration": 19.21,
-            "startTime": 2866.571
-          },
-          {
-            "type": "parseHTML",
-            "duration": 945.898,
-            "startTime": 2889.816
-          },
-          {
-            "type": "scriptEvaluation",
-            "duration": 944.888,
-            "startTime": 2890.118
-          },
-          {
-            "type": "scriptEvaluation",
-            "duration": 9.047,
-            "startTime": 3023.783
-          },
-          {
-            "type": "garbageCollection",
-            "duration": 5.97,
-            "startTime": 3023.842
-          },
-          {
-            "type": "scriptEvaluation",
-            "duration": 706.85,
-            "startTime": 3070.433
-          },
-          {
-            "type": "other",
-            "duration": 123.208,
-            "startTime": 3840.307
-          },
-          {
-            "type": "other",
-            "duration": 123.116,
-            "startTime": 3840.313
-          },
-          {
-            "type": "styleLayout",
-            "duration": 30.142,
-            "startTime": 3840.667
-          },
-          {
-            "type": "other",
-            "duration": 87.039,
-            "startTime": 3870.824
-          },
-          {
-            "type": "styleLayout",
-            "duration": 86.959,
-            "startTime": 3870.844
+            "duration": 5.272,
+            "startTime": 598.738
           },
           {
-            "type": "styleLayout",
-            "duration": 85.493,
-            "startTime": 3871.238
+            "duration": 26.926,
+            "startTime": 604.035
           },
           {
-            "type": "other",
-            "duration": 94.261,
-            "startTime": 3996.555
+            "duration": 6.681,
+            "startTime": 630.994
           },
           {
-            "type": "scriptEvaluation",
-            "duration": 90.663,
-            "startTime": 3997.797
+            "duration": 19.718,
+            "startTime": 637.706
           },
           {
-            "type": "garbageCollection",
-            "duration": 5.709,
-            "startTime": 4019.279
+            "duration": 7.812,
+            "startTime": 666.147
           },
           {
-            "type": "other",
-            "duration": 5.151,
-            "startTime": 4098.541
+            "duration": 10.087,
+            "startTime": 2639.59
           },
           {
-            "type": "other",
-            "duration": 122.537,
-            "startTime": 4808.624
+            "duration": 983.081,
+            "startTime": 2854.095
           },
           {
-            "type": "scriptEvaluation",
-            "duration": 82.741,
-            "startTime": 4810
+            "duration": 123.752,
+            "startTime": 3839.839
           },
           {
-            "type": "parseHTML",
-            "duration": 36.919,
-            "startTime": 4893.397
+            "duration": 5.338,
+            "startTime": 3980.383
           },
           {
-            "type": "parseHTML",
-            "duration": 36.866,
-            "startTime": 4893.44
+            "duration": 6.574,
+            "startTime": 3986.1
           },
           {
-            "type": "scriptEvaluation",
-            "duration": 10.58,
-            "startTime": 4894.119
+            "duration": 96.198,
+            "startTime": 3996.134
           },
           {
-            "type": "scriptEvaluation",
-            "duration": 9.353,
-            "startTime": 4894.151
+            "duration": 9.23,
+            "startTime": 4098.379
           },
           {
-            "type": "parseHTML",
-            "duration": 22.297,
-            "startTime": 4905.447
+            "duration": 5.463,
+            "startTime": 4784.783
           },
           {
-            "type": "other",
-            "duration": 6.849,
-            "startTime": 8603.435
+            "duration": 127.282,
+            "startTime": 4808.602
           },
           {
-            "type": "other",
-            "duration": 7.076,
-            "startTime": 10219.463
+            "duration": 6.885,
+            "startTime": 8603.411
           },
           {
-            "type": "scriptEvaluation",
-            "duration": 6.983,
-            "startTime": 10219.523
+            "duration": 7.258,
+            "startTime": 10219.292
           }
         ]
       }