Merge "trace_processor: prevent window table from allowing zero duration tables"
diff --git a/src/trace_processor/event_tracker.cc b/src/trace_processor/event_tracker.cc
index 60c6f40..7119edd 100644
--- a/src/trace_processor/event_tracker.cc
+++ b/src/trace_processor/event_tracker.cc
@@ -55,7 +55,7 @@
     // If the this events previous pid does not match the previous event's next
     // pid, make a note of this.
     if (prev_pid != pending_slice->pid) {
-      context_->storage->mutable_stats()->mismatched_sched_switch_tids_++;
+      context_->storage->mutable_stats()->mismatched_sched_switch_tids++;
     }
 
     size_t idx = pending_slice->storage_index;
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index f7e6a12..fc6ad1f 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -448,6 +448,7 @@
     PERFETTO_DLOG("Could not find process associated with utid %" PRIu32
                   " when parsing mem counters.",
                   utid);
+    context_->storage->mutable_stats()->mem_counter_no_process++;
     return;
   }
 
@@ -670,6 +671,7 @@
     PERFETTO_DLOG("Could not find process associated with utid %" PRIu32
                   " when parsing rss stat.",
                   utid);
+    context_->storage->mutable_stats()->rss_stat_no_process++;
     return;
   }
 
diff --git a/src/trace_processor/stats_table.cc b/src/trace_processor/stats_table.cc
index b8d7f15..afbb974 100644
--- a/src/trace_processor/stats_table.cc
+++ b/src/trace_processor/stats_table.cc
@@ -74,6 +74,10 @@
   switch (row) {
     case StatsTable::Row::kMismatchedSchedSwitch:
       return "mismatched_ss";
+    case StatsTable::Row::kRssStatNoProcess:
+      return "rss_stat_no_process";
+    case StatsTable::Row::kMemCounterNoProcess:
+      return "mem_count_no_process";
     default:
       PERFETTO_FATAL("Unknown row %u", row);
   }
@@ -82,7 +86,15 @@
 int StatsTable::Cursor::ValueForRow(uint8_t row) {
   switch (row) {
     case StatsTable::Row::kMismatchedSchedSwitch: {
-      auto val = storage_->stats().mismatched_sched_switch_tids_;
+      auto val = storage_->stats().mismatched_sched_switch_tids;
+      return static_cast<int>(val);
+    }
+    case StatsTable::Row::kRssStatNoProcess: {
+      auto val = storage_->stats().rss_stat_no_process;
+      return static_cast<int>(val);
+    }
+    case StatsTable::Row::kMemCounterNoProcess: {
+      auto val = storage_->stats().mem_counter_no_process;
       return static_cast<int>(val);
     }
     default:
diff --git a/src/trace_processor/stats_table.h b/src/trace_processor/stats_table.h
index 41000c4..2d2ff81 100644
--- a/src/trace_processor/stats_table.h
+++ b/src/trace_processor/stats_table.h
@@ -28,7 +28,12 @@
 
 class StatsTable : public Table {
  public:
-  enum Row { kMismatchedSchedSwitch = 0, kMax = kMismatchedSchedSwitch + 1 };
+  enum Row {
+    kMismatchedSchedSwitch = 0,
+    kRssStatNoProcess = 1,
+    kMemCounterNoProcess = 2,
+    kMax = kMemCounterNoProcess + 1
+  };
   enum Column { kKey = 0, kValue = 1 };
 
   static void RegisterTable(sqlite3* db, const TraceStorage* storage);
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 06d959e..621bae7 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -64,7 +64,9 @@
   virtual ~TraceStorage();
 
   struct Stats {
-    uint64_t mismatched_sched_switch_tids_ = 0;
+    uint64_t mismatched_sched_switch_tids = 0;
+    uint64_t rss_stat_no_process = 0;
+    uint64_t mem_counter_no_process = 0;
   };
 
   // Information about a unique process seen in a trace.
diff --git a/test/trace_processor/android_sched_and_ps_stats.out b/test/trace_processor/android_sched_and_ps_stats.out
index 33d85ac..37889b6 100644
--- a/test/trace_processor/android_sched_and_ps_stats.out
+++ b/test/trace_processor/android_sched_and_ps_stats.out
@@ -1,2 +1,4 @@
 "key","value"
 "mismatched_ss",9
+"rss_stat_no_process",0
+"mem_count_no_process",0
diff --git a/tools/trace_to_text/ftrace_event_formatter.cc b/tools/trace_to_text/ftrace_event_formatter.cc
index 913188a..2357eef 100644
--- a/tools/trace_to_text/ftrace_event_formatter.cc
+++ b/tools/trace_to_text/ftrace_event_formatter.cc
@@ -3534,13 +3534,21 @@
     uint64_t timestamp,
     uint32_t cpu,
     const protos::FtraceEvent& event,
-    const std::unordered_map<uint32_t /*tid*/, uint32_t /*tgid*/>& thread_map) {
+    const std::unordered_map<uint32_t /*tid*/, uint32_t /*tgid*/>& thread_map,
+    std::unordered_map<uint32_t /*tid*/, std::string>& thread_names) {
   // Sched_switch events contain the thread name so use that in the prefix.
   std::string name;
   if (event.has_sched_switch()) {
     name = event.sched_switch().prev_comm();
+    thread_names[event.pid()] = event.sched_switch().prev_comm();
   } else {
-    name = "<...>";
+    // For non sched switch events use name stored from a sched switch event.
+    auto it = thread_names.find(event.pid());
+    if (it != thread_names.end()) {
+      name = it->second;
+    } else {
+      name = "<...>";
+    }
   }
 
   std::string line = FormatEventText(event);
diff --git a/tools/trace_to_text/ftrace_event_formatter.h b/tools/trace_to_text/ftrace_event_formatter.h
index 593cee2..0309a0e 100644
--- a/tools/trace_to_text/ftrace_event_formatter.h
+++ b/tools/trace_to_text/ftrace_event_formatter.h
@@ -30,7 +30,8 @@
     uint64_t timestamp,
     uint32_t cpu,
     const protos::FtraceEvent&,
-    const std::unordered_map<uint32_t /*tid*/, uint32_t /*tgid*/>& thread_map);
+    const std::unordered_map<uint32_t /*tid*/, uint32_t /*tgid*/>& thread_map,
+    std::unordered_map<uint32_t /*tid*/, std::string>& thread_names);
 
 }  // namespace perfetto
 
diff --git a/tools/trace_to_text/trace_to_systrace.cc b/tools/trace_to_text/trace_to_systrace.cc
index 19818a9..0b2cc12 100644
--- a/tools/trace_to_text/trace_to_systrace.cc
+++ b/tools/trace_to_text/trace_to_systrace.cc
@@ -100,6 +100,7 @@
   std::vector<std::string> proc_dump;
   std::vector<std::string> thread_dump;
   std::unordered_map<uint32_t /*tid*/, uint32_t /*tgid*/> thread_map;
+  std::unordered_map<uint32_t /*tid*/, std::string> thread_names;
 
   std::vector<const char*> meminfo_strs = BuildMeminfoCounterNames();
   std::vector<const char*> vmstat_strs = BuildVmstatCounterNames();
@@ -107,7 +108,7 @@
   std::vector<protos::TracePacket> packets_to_process;
 
   ForEachPacketInTrace(
-      input, [&thread_map, &packets_to_process, &proc_dump,
+      input, [&thread_map, &packets_to_process, &proc_dump, &thread_names,
               &thread_dump](const protos::TracePacket& packet) {
         if (!packet.has_process_tree()) {
           packets_to_process.emplace_back(std::move(packet));
@@ -125,6 +126,9 @@
           // Populate thread map for matching tids to tgids.
           thread_map[static_cast<uint32_t>(thread.tid())] =
               static_cast<uint32_t>(thread.tgid());
+          if (thread.has_name()) {
+            thread_names[static_cast<uint32_t>(thread.tid())] = thread.name();
+          }
           std::string t = FormatThread(thread);
           thread_dump.emplace_back(t);
         }
@@ -135,7 +139,7 @@
       const FtraceEventBundle& bundle = packet.ftrace_events();
       for (const FtraceEvent& event : bundle.event()) {
         std::string line = FormatFtraceEvent(event.timestamp(), bundle.cpu(),
-                                             event, thread_map);
+                                             event, thread_map, thread_names);
         if (line == "")
           continue;
         ftrace_sorted.emplace(event.timestamp(), line);
@@ -153,7 +157,8 @@
         sprintf(str, "C|1|%s|%" PRIu64, meminfo_strs[meminfo.key()],
                 static_cast<uint64_t>(meminfo.value()));
         event.mutable_print()->set_buf(str);
-        ftrace_sorted.emplace(ts, FormatFtraceEvent(ts, 0, event, thread_map));
+        ftrace_sorted.emplace(
+            ts, FormatFtraceEvent(ts, 0, event, thread_map, thread_names));
       }
       for (const auto& vmstat : sys_stats.vmstat()) {
         FtraceEvent event;
@@ -164,7 +169,8 @@
         sprintf(str, "C|1|%s|%" PRIu64, vmstat_strs[vmstat.key()],
                 static_cast<uint64_t>(vmstat.value()));
         event.mutable_print()->set_buf(str);
-        ftrace_sorted.emplace(ts, FormatFtraceEvent(ts, 0, event, thread_map));
+        ftrace_sorted.emplace(
+            ts, FormatFtraceEvent(ts, 0, event, thread_map, thread_names));
       }
     }
   }
diff --git a/ui/src/tracks/cpu_slices/controller.ts b/ui/src/tracks/cpu_slices/controller.ts
index 26e46ba..bb987f9 100644
--- a/ui/src/tracks/cpu_slices/controller.ts
+++ b/ui/src/tracks/cpu_slices/controller.ts
@@ -63,7 +63,7 @@
     if (isQuantized) {
       windowStartNs = Math.floor(windowStartNs / bucketSizeNs) * bucketSizeNs;
     }
-    const windowDurNs = endNs - windowStartNs;
+    const windowDurNs = Math.max(1, endNs - windowStartNs);
 
     this.query(`update window_${this.trackState.id} set
       window_start=${windowStartNs},
diff --git a/ui/src/tracks/process_summary/controller.ts b/ui/src/tracks/process_summary/controller.ts
index 462b525..b61838f 100644
--- a/ui/src/tracks/process_summary/controller.ts
+++ b/ui/src/tracks/process_summary/controller.ts
@@ -66,7 +66,7 @@
     // |resolution| is in s/px we want # ns for 10px window:
     const bucketSizeNs = Math.round(resolution * 10 * 1e9);
     const windowStartNs = Math.floor(startNs / bucketSizeNs) * bucketSizeNs;
-    const windowDurNs = endNs - windowStartNs;
+    const windowDurNs = Math.max(1, endNs - windowStartNs);
 
     this.query(`update ${this.tableName('window')} set
       window_start=${windowStartNs},