Merge "ui: add offline support via ServiceWorker"
diff --git a/src/trace_processor/forwarding_trace_parser.cc b/src/trace_processor/forwarding_trace_parser.cc
index b28b89b..ea63b8e 100644
--- a/src/trace_processor/forwarding_trace_parser.cc
+++ b/src/trace_processor/forwarding_trace_parser.cc
@@ -39,9 +39,13 @@
 namespace trace_processor {
 namespace {
 
+inline bool isspace(unsigned char c) {
+  return ::isspace(c);
+}
+
 std::string RemoveWhitespace(const std::string& input) {
   std::string str(input);
-  str.erase(std::remove_if(str.begin(), str.end(), ::isspace), str.end());
+  str.erase(std::remove_if(str.begin(), str.end(), isspace), str.end());
   return str;
 }
 
diff --git a/src/trace_processor/importers/proto/heap_graph_tracker.cc b/src/trace_processor/importers/proto/heap_graph_tracker.cc
index c2908a0..7942263 100644
--- a/src/trace_processor/importers/proto/heap_graph_tracker.cc
+++ b/src/trace_processor/importers/proto/heap_graph_tracker.cc
@@ -242,7 +242,7 @@
     int32_t row_id = static_cast<int32_t>(callsite_id.value);
     node_to_row_id[i] = row_id;
 
-    tables::ExperimentalHeapGraphAllocationTable::Row alloc_row{
+    tables::ExperimentalFlamegraphNodesTable::Row alloc_row{
         sequence_state.current_ts,
         sequence_state.current_upid,
         row_id,
@@ -250,8 +250,8 @@
         static_cast<int64_t>(node_to_cumulative_count[i]),
         static_cast<int64_t>(node.size),
         static_cast<int64_t>(node_to_cumulative_size[i])};
-    context_->storage->mutable_experimental_heap_graph_allocation_table()
-        ->Insert(alloc_row);
+    context_->storage->mutable_experimental_flamegraph_nodes_table()->Insert(
+        alloc_row);
   }
 }
 
diff --git a/src/trace_processor/tables/profiler_tables.h b/src/trace_processor/tables/profiler_tables.h
index 65c5304..7cbf445 100644
--- a/src/trace_processor/tables/profiler_tables.h
+++ b/src/trace_processor/tables/profiler_tables.h
@@ -87,16 +87,15 @@
 
 // This will eventually go away, when we also pre-compute the cumulative
 // sizes for native heap profiles.
-#define PERFETTO_TP_HEAP_GRAPH_ALLOCATION_DEF(NAME, PARENT, C) \
-  NAME(ExperimentalHeapGraphAllocationTable,                   \
-       "experimental_heap_graph_allocation")                   \
-  PERFETTO_TP_ROOT_TABLE(PARENT, C)                            \
-  C(int64_t, ts, Column::Flag::kSorted)                        \
-  C(uint32_t, upid)                                            \
-  C(int64_t, callsite_id)                                      \
-  C(int64_t, count)                                            \
-  C(int64_t, cumulative_count)                                 \
-  C(int64_t, size)                                             \
+#define PERFETTO_TP_HEAP_GRAPH_ALLOCATION_DEF(NAME, PARENT, C)            \
+  NAME(ExperimentalFlamegraphNodesTable, "experimental_flamegraph_nodes") \
+  PERFETTO_TP_ROOT_TABLE(PARENT, C)                                       \
+  C(int64_t, ts, Column::Flag::kSorted)                                   \
+  C(uint32_t, upid)                                                       \
+  C(int64_t, callsite_id)                                                 \
+  C(int64_t, count)                                                       \
+  C(int64_t, cumulative_count)                                            \
+  C(int64_t, size)                                                        \
   C(int64_t, cumulative_size)
 
 PERFETTO_TP_TABLE(PERFETTO_TP_HEAP_GRAPH_ALLOCATION_DEF);
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 5692b0b..d06580d 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -448,8 +448,8 @@
       *db_, &storage->heap_profile_allocation_table(),
       storage->heap_profile_allocation_table().table_name());
   DbSqliteTable::RegisterTable(
-      *db_, &storage->experimental_heap_graph_allocation_table(),
-      storage->experimental_heap_graph_allocation_table().table_name());
+      *db_, &storage->experimental_flamegraph_nodes_table(),
+      storage->experimental_flamegraph_nodes_table().table_name());
   DbSqliteTable::RegisterTable(
       *db_, &storage->cpu_profile_stack_sample_table(),
       storage->cpu_profile_stack_sample_table().table_name());
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 18067d6..146d260 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -569,13 +569,13 @@
     return &heap_profile_allocation_table_;
   }
 
-  const tables::ExperimentalHeapGraphAllocationTable&
-  experimental_heap_graph_allocation_table() const {
-    return experimental_heap_graph_allocation_table_;
+  const tables::ExperimentalFlamegraphNodesTable&
+  experimental_flamegraph_nodes_table() const {
+    return experimental_flamegraph_nodes_table_;
   }
-  tables::ExperimentalHeapGraphAllocationTable*
-  mutable_experimental_heap_graph_allocation_table() {
-    return &experimental_heap_graph_allocation_table_;
+  tables::ExperimentalFlamegraphNodesTable*
+  mutable_experimental_flamegraph_nodes_table() {
+    return &experimental_flamegraph_nodes_table_;
   }
 
   const tables::CpuProfileStackSampleTable& cpu_profile_stack_sample_table()
@@ -805,8 +805,8 @@
                                                                   nullptr};
   tables::HeapProfileAllocationTable heap_profile_allocation_table_{
       &string_pool_, nullptr};
-  tables::ExperimentalHeapGraphAllocationTable
-      experimental_heap_graph_allocation_table_{&string_pool_, nullptr};
+  tables::ExperimentalFlamegraphNodesTable experimental_flamegraph_nodes_table_{
+      &string_pool_, nullptr};
   tables::CpuProfileStackSampleTable cpu_profile_stack_sample_table_{
       &string_pool_, nullptr};
 
diff --git a/src/tracing/track.cc b/src/tracing/track.cc
index 91045c4..9543c96 100644
--- a/src/tracing/track.cc
+++ b/src/tracing/track.cc
@@ -35,15 +35,15 @@
 void ProcessTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
   Track::Serialize(desc);
   auto pd = desc->set_process();
-  pd->set_pid(pid);
+  pd->set_pid(static_cast<int32_t>(pid));
   // TODO(skyostil): Record command line.
 }
 
 void ThreadTrack::Serialize(protos::pbzero::TrackDescriptor* desc) const {
   Track::Serialize(desc);
   auto td = desc->set_thread();
-  td->set_pid(pid);
-  td->set_tid(tid);
+  td->set_pid(static_cast<int32_t>(pid));
+  td->set_tid(static_cast<int32_t>(tid));
   // TODO(skyostil): Record thread name.
 }
 
diff --git a/tools/heap_profile b/tools/heap_profile
index c4c9b07..8662bbf 100755
--- a/tools/heap_profile
+++ b/tools/heap_profile
@@ -31,8 +31,8 @@
 import urllib
 
 TRACE_TO_TEXT_SHAS = {
-    'linux': 'cd6d89e0ada48c0d7850206d80c324b912a3db42',
-    'mac': 'ff18507c87fc768dfc299d7d1c6a9f0d16b07e79',
+    'linux': 'f9c206e242c49ebd4ec5e4138c61f4fb2816065b',
+    'mac': '7e1803f5c51d0763061d2980fd9af5750ac9d9c8',
 }
 TRACE_TO_TEXT_PATH = tempfile.gettempdir()
 TRACE_TO_TEXT_BASE_URL = ('https://storage.googleapis.com/perfetto/')
@@ -99,8 +99,11 @@
 duration_ms: {duration}
 write_into_file: true
 flush_timeout_ms: 30000
+flush_period_ms: 604800000
 '''
 
+# flush_period_ms of 1 week to suppress trace_processor_shell warning.
+
 CONTINUOUS_DUMP = """
       continuous_dump_config {{
         dump_phase_ms: 0
@@ -119,6 +122,13 @@
   IS_INTERRUPTED = True
 
 
+def print_no_profile_error():
+  print("No profiles generated", file=sys.stderr)
+  print(
+    "If this is unexpected, check "
+    "https://docs.perfetto.dev/#/heapprofd?id=troubleshooting.",
+    file=sys.stderr)
+
 def main(argv):
   parser = argparse.ArgumentParser()
   parser.add_argument(
@@ -344,6 +354,7 @@
   old_handler = signal.signal(signal.SIGINT, sigint_handler)
   print("Profiling active. Press Ctrl+C to terminate.")
   print("You may disconnect your device.")
+  print()
   exists = True
   device_connected = True
   while not device_connected or (exists and not IS_INTERRUPTED):
@@ -385,16 +396,12 @@
     if 'heap_profile-' in word:
       profile_path = word
   if profile_path is None:
-    print("Could not find trace_to_text output path.", file=sys.stderr)
+    print_no_profile_error();
     return 1
 
   profile_files = os.listdir(profile_path)
   if not profile_files:
-    print("No profiles generated", file=sys.stderr)
-    print(
-        "If this is unexpected, check "
-        "https://docs.perfetto.dev/#/heapprofd?id=troubleshooting.",
-        file=sys.stderr)
+    print_no_profile_error();
     return 1
 
   subprocess.check_call(
@@ -417,7 +424,8 @@
               env=os.environ,
               stdout=fd)
           if ret != 0:
-              print("Failed to symbolize.", file=sys.stderr)
+              print("Failed to symbolize. Continuing without symbols.",
+                    file=sys.stderr)
 
   print("Wrote profiles to {} (symlink {})".format(profile_path, symlink_path))
   print("These can be viewed using pprof. Googlers: head to pprof/ and "
diff --git a/ui/src/assets/record.scss b/ui/src/assets/record.scss
index 7600ebd..62e88f4 100644
--- a/ui/src/assets/record.scss
+++ b/ui/src/assets/record.scss
@@ -693,7 +693,6 @@
 
       &.two-columns {
         height: 400px;
-        width: auto;
         margin: var(--record-section-padding);
         optgroup {
           display: grid;
@@ -719,10 +718,6 @@
     height: 152px;
   }
 
-  .chrome-categories {
-    height: 152px;
-  }
-
   textarea.extra-input {
     width: 100%;
     height: 60px;
@@ -774,6 +769,8 @@
       font-size: 12px;
       line-height: 20px;
       overflow-y: auto;
+      white-space: pre-wrap;
+      word-wrap: break-word;
 
       // 510px and not 500px, so the overflowing line gets truncated, giving
       // a clear indication that the code box scrolls.
diff --git a/ui/src/frontend/record_page.ts b/ui/src/frontend/record_page.ts
index 65e0dcf..4053907 100644
--- a/ui/src/frontend/record_page.ts
+++ b/ui/src/frontend/record_page.ts
@@ -619,7 +619,7 @@
 
   return m(Dropdown, {
     title: 'Additional Chrome categories',
-    cssClass: '.multicolumn.two-columns.chrome-categories',
+    cssClass: '.multicolumn.two-columns',
     options: categoriesMap,
     set: (cfg, val) => cfg.chromeCategoriesSelected = val,
     get: (cfg) => cfg.chromeCategoriesSelected
@@ -854,7 +854,7 @@
          'Start Recording'.`)) :
         [];
   }
-  return m(CodeSnippet, {text: getRecordCommand(target), hardWhitespace: true});
+  return m(CodeSnippet, {text: getRecordCommand(target)});
 }
 
 function getRecordCommand(target: RecordingTarget) {
diff --git a/ui/src/frontend/record_widgets.ts b/ui/src/frontend/record_widgets.ts
index 3d683f7..ebc2267 100644
--- a/ui/src/frontend/record_widgets.ts
+++ b/ui/src/frontend/record_widgets.ts
@@ -258,12 +258,7 @@
             onclick: () => copyToClipboard(attrs.text),
           },
           m('i.material-icons', 'assignment')),
-        m('code',
-          {
-            style: {
-              'white-space': attrs.hardWhitespace ? 'pre' : null,
-            },
-          },
-          attrs.text), );
+        m('code', attrs.text),
+    );
   }
 }