Merge "Add dur_ms to jank and frame_timeline metrics"
diff --git a/docs/contributing/build-instructions.md b/docs/contributing/build-instructions.md
index e037479..74eeecf 100644
--- a/docs/contributing/build-instructions.md
+++ b/docs/contributing/build-instructions.md
@@ -149,6 +149,21 @@
 ui/run-unittests
 ```
 
+This command will perform the build first; which is not necessary if you
+already have a development server running. In this case, to avoid interference
+with the rebuild done by development server and to get the results faster, you
+can use
+
+```bash
+ui/run-unittests --no-build
+```
+
+to skip the build steps.
+
+Script `ui/run-unittests` also supports `--watch` parameter, which would
+restart the testing when the underlying source files are changed. This can be
+used in conjunction with `--no-build`, and on its own as well.
+
 ## Build files
 
 The source of truth of our build file is in the BUILD.gn files, which are based
diff --git a/include/perfetto/base/compiler.h b/include/perfetto/base/compiler.h
index c67e315..bf1b823 100644
--- a/include/perfetto/base/compiler.h
+++ b/include/perfetto/base/compiler.h
@@ -25,6 +25,10 @@
 
 #if __cplusplus >= 201703
 #define PERFETTO_IS_AT_LEAST_CPP17() 1
+#elif defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
+// Without additional flags, MSVC is not standard compliant and keeps
+// __cplusplus stuck at an old value, even with C++17
+#define PERFETTO_IS_AT_LEAST_CPP17() 1
 #else
 #define PERFETTO_IS_AT_LEAST_CPP17() 0
 #endif
diff --git a/include/perfetto/tracing/data_source.h b/include/perfetto/tracing/data_source.h
index 7c78546..acf892c 100644
--- a/include/perfetto/tracing/data_source.h
+++ b/include/perfetto/tracing/data_source.h
@@ -56,8 +56,14 @@
 // should be made visible outside the current module. (e.g., in Chrome's
 // component build).
 #if !defined(PERFETTO_COMPONENT_EXPORT)
+#if PERFETTO_BUILDFLAG(PERFETTO_COMPILER_MSVC)
+// Workaround for C4003: not enough arguments for function-like macro invocation
+// 'PERFETTO_INTERNAL_DECLARE_TRACK_EVENT_DATA_SOURCE'
+#define PERFETTO_COMPONENT_EXPORT __declspec()
+#else
 #define PERFETTO_COMPONENT_EXPORT
 #endif
+#endif
 
 namespace perfetto {
 namespace internal {
diff --git a/protos/third_party/chromium/chrome_track_event.proto b/protos/third_party/chromium/chrome_track_event.proto
index fb35740..911dbe0 100644
--- a/protos/third_party/chromium/chrome_track_event.proto
+++ b/protos/third_party/chromium/chrome_track_event.proto
@@ -728,6 +728,7 @@
     TASK_TYPE_INTERNAL_POST_MESSAGE_FORWARDING = 79;
     TASK_TYPE_INTERNAL_NAVIGATION_CANCELLATION = 80;
     TASK_TYPE_LOW_PRIORITY_SCRIPT_EXECUTION = 81;
+    TASK_TYPE_STORAGE = 82;
   }
 
   enum FrameType {
diff --git a/python/tools/cpu_profile.py b/python/tools/cpu_profile.py
index a743981..46b258f 100644
--- a/python/tools/cpu_profile.py
+++ b/python/tools/cpu_profile.py
@@ -79,7 +79,7 @@
   traces if requested.
 
   For usage instructions, please see:
-  https://perfetto.dev/docs/quickstart/cpu-profiling
+  https://perfetto.dev/docs/quickstart/callstack-sampling
   """
   parser = argparse.ArgumentParser(description=DESCRIPTION)
   parser.add_argument(
diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc
index 29582c9..6e57384 100644
--- a/src/trace_processor/importers/ftrace/ftrace_parser.cc
+++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc
@@ -1702,6 +1702,8 @@
   proc_tracker->UpdateThreadNameByUtid(new_utid, new_comm,
                                        ThreadNamePriority::kFtrace);
   proc_tracker->AssociateThreads(source_utid, new_utid);
+
+  ThreadStateTracker::GetOrCreate(context_)->PushNewTaskEvent(timestamp, new_utid, source_utid);
 }
 
 void FtraceParser::ParseTaskRename(ConstBytes blob) {
diff --git a/src/trace_processor/importers/ftrace/thread_state_tracker.cc b/src/trace_processor/importers/ftrace/thread_state_tracker.cc
index 9ff75e3..227a90a 100644
--- a/src/trace_processor/importers/ftrace/thread_state_tracker.cc
+++ b/src/trace_processor/importers/ftrace/thread_state_tracker.cc
@@ -70,6 +70,12 @@
   AddOpenState(event_ts, utid, runnable_string_id_, base::nullopt, waker_utid);
 }
 
+void ThreadStateTracker::PushNewTaskEvent(int64_t event_ts,
+                                         UniqueTid utid,
+                                         UniqueTid waker_utid) {
+  AddOpenState(event_ts, utid, runnable_string_id_, base::nullopt, waker_utid);
+}
+
 void ThreadStateTracker::PushBlockedReason(
     UniqueTid utid,
     base::Optional<bool> io_wait,
diff --git a/src/trace_processor/importers/ftrace/thread_state_tracker.h b/src/trace_processor/importers/ftrace/thread_state_tracker.h
index af3ad4c..3f8b7a5 100644
--- a/src/trace_processor/importers/ftrace/thread_state_tracker.h
+++ b/src/trace_processor/importers/ftrace/thread_state_tracker.h
@@ -51,6 +51,10 @@
   // Will add a runnable state for utid and close the previously blocked one.
   void PushWakingEvent(int64_t event_ts, UniqueTid utid, UniqueTid waker_utid);
 
+  // Will add a runnable state for utid. For a new task there are no previous
+  // states to close.
+  void PushNewTaskEvent(int64_t event_ts, UniqueTid utid, UniqueTid waker_utid);
+
   // Updates the current blocked state for utid with blocked reason.
   void PushBlockedReason(UniqueTid utid,
                          base::Optional<bool> io_wait,
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
index f48f5b8..4542096 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_expand_camera.png.sha256
@@ -1 +1 @@
-2642993d0ccbdcc083d863a15d3a60e4e4458c278190bd057491a68727601ac5
\ No newline at end of file
+42318df513cb597e8eed8f30da87e0d5549e450458ee2a72096617564f1c9641
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256 b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
index 8049eda..435886a 100644
--- a/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
+++ b/test/data/ui-screenshots/ui-android_trace_30s_load.png.sha256
@@ -1 +1 @@
-604b0837fc54444c0f347a26821892ce502796859daea4634bbd371b0248b4fd
\ No newline at end of file
+304307cd023efbd545daa08c981fc8f28f94181eea2229247a217d3379982ce9
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
index f5893a1..c2c4480 100644
--- a/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_missing_track_names_load.png.sha256
@@ -1 +1 @@
-9ce961410f075c01643dbee74ad0f57155f799c2af1c0164e9cbebc9681c65a1
\ No newline at end of file
+a74598d5e5bfc01edc3893310ee565d951634caa48408e7909d57c2ef9112df0
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
index 9950bf8..0bf5879 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_expand_browser_proc.png.sha256
@@ -1 +1 @@
-b94937e792f3103cbb504357fb3cf4c7e0e6e0bad788c8eef05fb7954f52abf9
\ No newline at end of file
+be9aed5344f35089cc633006ccdd695073a34cc74064cd89235521c9d7787aca
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
index bd9d924..8d20ae2 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_load.png.sha256
@@ -1 +1 @@
-fd6a8a39085b3b2d4fd9f719f08c3f529eac99c06f30dc457278ebc4231dc6fe
\ No newline at end of file
+a1719fb24ddb802efd12be5dcd33ca6936ab8c1bb952bb5c5458f1e26bce9625
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256 b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
index 70a462d..4a2f0c4 100644
--- a/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
+++ b/test/data/ui-screenshots/ui-chrome_rendering_desktop_select_slice_with_flows.png.sha256
@@ -1 +1 @@
-72b31cf41144b44831443984cf80abe87fb213a8d73df767268d7c9ba0a63398
\ No newline at end of file
+7306700e0412cdb55390941b3d52e986414e2acbb2e74c32a93f8d9a4de1d43a
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
index d9fed2d..11e6f1f 100644
--- a/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_navigate_open_trace_from_url.png.sha256
@@ -1 +1 @@
-a9bf192426e9a29380ae8dd47d3974e8607bc7fd01ab0498e9b2cb1cdca75acb
\ No newline at end of file
+6e57bf0534cd22c5452d49580451043f9bedaa5fa560beea334a451daea96e42
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
index 4ee2372..556052a 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_access_subpage_then_go_back.png.sha256
@@ -1 +1 @@
-c4773556fad9c5b83fc6d8cd2f271faef9e088da862b32a0b1ef14f9d56fa162
\ No newline at end of file
+b74e614897b9c0fc652b36c8c2cc025f6ea3d54754edbcf828d137275921c89c
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
index d9fed2d..11e6f1f 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_first_trace_from_url.png.sha256
@@ -1 +1 @@
-a9bf192426e9a29380ae8dd47d3974e8607bc7fd01ab0498e9b2cb1cdca75acb
\ No newline at end of file
+6e57bf0534cd22c5452d49580451043f9bedaa5fa560beea334a451daea96e42
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256 b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
index 4ee2372..556052a 100644
--- a/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_open_two_traces_then_go_back_open_second_trace_from_url.png.sha256
@@ -1 +1 @@
-c4773556fad9c5b83fc6d8cd2f271faef9e088da862b32a0b1ef14f9d56fa162
\ No newline at end of file
+b74e614897b9c0fc652b36c8c2cc025f6ea3d54754edbcf828d137275921c89c
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
index a00bc34..890256b 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_go_back_to_first_trace.png.sha256
@@ -1 +1 @@
-c3461778784561480bd02f6202651ffa3736ac19abfefc8ddd3bbed1e5a2fe08
\ No newline at end of file
+f6d364436cb58281efdca972d3645ab3e95408f6aecfaaf286217fa55f40bcca
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
index d9fed2d..11e6f1f 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_second_trace.png.sha256
@@ -1 +1 @@
-a9bf192426e9a29380ae8dd47d3974e8607bc7fd01ab0498e9b2cb1cdca75acb
\ No newline at end of file
+6e57bf0534cd22c5452d49580451043f9bedaa5fa560beea334a451daea96e42
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
index 4ee2372..556052a 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_open_trace_.png.sha256
@@ -1 +1 @@
-c4773556fad9c5b83fc6d8cd2f271faef9e088da862b32a0b1ef14f9d56fa162
\ No newline at end of file
+b74e614897b9c0fc652b36c8c2cc025f6ea3d54754edbcf828d137275921c89c
\ No newline at end of file
diff --git a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256 b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
index 4ee2372..556052a 100644
--- a/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
+++ b/test/data/ui-screenshots/ui-routing_start_from_no_trace_refresh.png.sha256
@@ -1 +1 @@
-c4773556fad9c5b83fc6d8cd2f271faef9e088da862b32a0b1ef14f9d56fa162
\ No newline at end of file
+b74e614897b9c0fc652b36c8c2cc025f6ea3d54754edbcf828d137275921c89c
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/parsing/tests.py b/test/trace_processor/diff_tests/parsing/tests.py
index 1352521..69a8d94 100644
--- a/test/trace_processor/diff_tests/parsing/tests.py
+++ b/test/trace_processor/diff_tests/parsing/tests.py
@@ -1126,3 +1126,46 @@
         679375600673065,3797,385482,"__handle_mm_fault",0
         679375600673769,1726,385482,"alloc_pages_vma",1
         """))
+
+  # Kernel task_newtask waker_utid parsing
+  def test_task_newtask_waker_utid(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+        packet {
+          first_packet_on_sequence: true
+          ftrace_events {
+            cpu: 1
+            event {
+              timestamp: 201315132677
+              pid: 518
+              task_newtask {
+                pid: 3294
+                comm: "adbd"
+                clone_flags: 18874368
+                oom_score_adj: -1000
+              }
+            }
+            event {
+              timestamp: 201319417828
+              pid: 518
+              task_newtask {
+                pid: 3295
+                comm: "adbd"
+                clone_flags: 4001536
+                oom_score_adj: -1000
+              }
+            }
+          }
+          trusted_uid: 9999
+          trusted_packet_sequence_id: 2
+          trusted_pid: 521
+          previous_packet_dropped: true
+        }
+        """),
+        query="""
+        SELECT waker_utid FROM thread_state
+        """,
+        out=Csv("""
+        "waker_utid"
+        1
+        """))
diff --git a/tools/cpu_profile b/tools/cpu_profile
index d0c52e8..943d6fb 100755
--- a/tools/cpu_profile
+++ b/tools/cpu_profile
@@ -342,7 +342,7 @@
   traces if requested.
 
   For usage instructions, please see:
-  https://perfetto.dev/docs/quickstart/cpu-profiling
+  https://perfetto.dev/docs/quickstart/callstack-sampling
   """
   parser = argparse.ArgumentParser(description=DESCRIPTION)
   parser.add_argument(
diff --git a/ui/build.js b/ui/build.js
index 73b2aac..9a0ded5 100644
--- a/ui/build.js
+++ b/ui/build.js
@@ -222,14 +222,14 @@
   console.log('Entering', cfg.outDir);
   process.chdir(cfg.outDir);
 
-  updateSymlinks();  // Links //ui/out -> //out/xxx/ui/
-
   // Enqueue empty task. This is needed only for --no-build --serve. The HTTP
   // server is started when the task queue reaches quiescence, but it takes at
   // least one task for that.
   addTask(() => {});
 
   if (!args.no_build) {
+    updateSymlinks();  // Links //ui/out -> //out/xxx/ui/
+
     buildWasm(args.no_wasm);
     scanDir('ui/src/assets');
     scanDir('ui/src/chrome_extension');
@@ -253,11 +253,18 @@
 
   // We should enter the loop only in watch mode, where tsc and rollup are
   // asynchronous because they run in watch mode.
-  const tStart = Date.now();
-  while (!isDistComplete()) {
-    const secs = Math.ceil((Date.now() - tStart) / 1000);
-    process.stdout.write(`\t\tWaiting for first build to complete... ${secs} s\r`);
-    await new Promise((r) => setTimeout(r, 500));
+  if (args.no_build && !isDistComplete()) {
+    console.log('No build was requested, but artifacts are not available.');
+    console.log('In case of execution error, re-run without --no-build.');
+  }
+  if (!args.no_build) {
+    const tStart = Date.now();
+    while (!isDistComplete()) {
+      const secs = Math.ceil((Date.now() - tStart) / 1000);
+      process.stdout.write(
+          `\t\tWaiting for first build to complete... ${secs} s\r`);
+      await new Promise((r) => setTimeout(r, 500));
+    }
   }
   if (cfg.watch) console.log('\nFirst build completed!');
 
diff --git a/ui/src/common/actions.ts b/ui/src/common/actions.ts
index c5e40d6..2909c73 100644
--- a/ui/src/common/actions.ts
+++ b/ui/src/common/actions.ts
@@ -1024,6 +1024,13 @@
     }
   },
 
+  clearAllPinnedTracks(state: StateDraft, _: {}) {
+    if (state.pinnedTracks.length > 0) {
+      // Clear pinnedTracks array
+      state.pinnedTracks.length = 0;
+    }
+  },
+
   togglePivotTableRedux(state: StateDraft, args: {areaId: string|null}) {
     state.nonSerializableState.pivotTableRedux.selectionArea =
         args.areaId === null ?
diff --git a/ui/src/controller/selection_controller.ts b/ui/src/controller/selection_controller.ts
index 134d78b..4b4ee82 100644
--- a/ui/src/controller/selection_controller.ts
+++ b/ui/src/controller/selection_controller.ts
@@ -466,7 +466,7 @@
 
     // If this is the first sched slice for this utid or if the wakeup found
     // was after the previous slice then we know the wakeup was for this slice.
-    if (prevSchedResult.numRows() === 0 ||
+    if (prevSchedResult.numRows() !== 0 &&
         wakeupTs < prevSchedResult.firstRow({ts: NUM}).ts) {
       return undefined;
     }
diff --git a/ui/src/frontend/notes_panel.ts b/ui/src/frontend/notes_panel.ts
index 9896611..295c893 100644
--- a/ui/src/frontend/notes_panel.ts
+++ b/ui/src/frontend/notes_panel.ts
@@ -83,17 +83,29 @@
           },
         },
         isTraceLoaded() ?
-            m('button',
-              {
-                onclick: (e: Event) => {
-                  e.preventDefault();
-                  globals.dispatch(
-                      Actions.toggleAllTrackGroups({collapsed: !allCollapsed}));
+            [
+              m('button',
+                {
+                  onclick: (e: Event) => {
+                    e.preventDefault();
+                    globals.dispatch(Actions.toggleAllTrackGroups(
+                        {collapsed: !allCollapsed}));
+                  },
                 },
-              },
-              m('i.material-icons',
-                {title: allCollapsed ? 'Expand all' : 'Collapse all'},
-                allCollapsed ? 'unfold_more' : 'unfold_less')) :
+                m('i.material-icons',
+                  {title: allCollapsed ? 'Expand all' : 'Collapse all'},
+                  allCollapsed ? 'unfold_more' : 'unfold_less')),
+              m('button',
+                {
+                  onclick: (e: Event) => {
+                    e.preventDefault();
+                    globals.dispatch(Actions.clearAllPinnedTracks({}));
+                  },
+                },
+                m('i.material-icons',
+                  {title: 'Clear all pinned tracks'},
+                  'clear_all')),
+            ] :
             '');
   }