Merge "trace_to_text: Add summary mode"
diff --git a/include/perfetto/base/logging.h b/include/perfetto/base/logging.h
index ce4a656..c15597a 100644
--- a/include/perfetto/base/logging.h
+++ b/include/perfetto/base/logging.h
@@ -100,22 +100,22 @@
     PERFETTO_IMMEDIATE_CRASH();        \
   } while (0)
 
-#define PERFETTO_PLOG(x) \
-  PERFETTO_ELOG("%s (errno: %d, %s)", (x), errno, strerror(errno))
+#define PERFETTO_PLOG(x, ...) \
+  PERFETTO_ELOG(x " (errno: %d, %s)", ##__VA_ARGS__, errno, strerror(errno))
 
 #if PERFETTO_DCHECK_IS_ON()
 
 #define PERFETTO_DLOG(fmt, ...) PERFETTO_XLOG(kLogDebug, fmt, ##__VA_ARGS__)
 
-#define PERFETTO_DPLOG(x) \
-  PERFETTO_DLOG("%s (errno: %d, %s)", (x), errno, strerror(errno))
+#define PERFETTO_DPLOG(x, ...) \
+  PERFETTO_DLOG(x " (errno: %d, %s)", ##__VA_ARGS__, errno, strerror(errno))
 
-#define PERFETTO_DCHECK(x)                      \
-  do {                                          \
-    if (PERFETTO_UNLIKELY(!(x))) {              \
-      PERFETTO_DPLOG("PERFETTO_CHECK(" #x ")"); \
-      PERFETTO_IMMEDIATE_CRASH();               \
-    }                                           \
+#define PERFETTO_DCHECK(x)                            \
+  do {                                                \
+    if (PERFETTO_UNLIKELY(!(x))) {                    \
+      PERFETTO_DPLOG("%s", "PERFETTO_CHECK(" #x ")"); \
+      PERFETTO_IMMEDIATE_CRASH();                     \
+    }                                                 \
   } while (0)
 
 #else
diff --git a/src/ftrace_reader/cpu_reader_unittest.cc b/src/ftrace_reader/cpu_reader_unittest.cc
index 1a7795c..b4a12c1 100644
--- a/src/ftrace_reader/cpu_reader_unittest.cc
+++ b/src/ftrace_reader/cpu_reader_unittest.cc
@@ -206,6 +206,7 @@
   {
     Event event;
     event.name = "foo";
+    event.group = "foo_group";
     event.ftrace_event_id = 1;
     events.push_back(event);
   }
@@ -213,6 +214,7 @@
   {
     Event event;
     event.name = "bar";
+    event.group = "bar_group";
     event.ftrace_event_id = 10;
     events.push_back(event);
   }
diff --git a/src/ftrace_reader/ftrace_config_muxer.cc b/src/ftrace_reader/ftrace_config_muxer.cc
index 0d2e1ef..3642b24 100644
--- a/src/ftrace_reader/ftrace_config_muxer.cc
+++ b/src/ftrace_reader/ftrace_config_muxer.cc
@@ -45,13 +45,159 @@
   return result;
 }
 
+void AddEventGroup(const ProtoTranslationTable* table,
+                   const std::string& group,
+                   std::set<std::string>* to) {
+  const std::vector<const Event*>* events = table->GetEventsByGroup(group);
+  if (!events)
+    return;
+  for (const Event* event : *events)
+    to->insert(event->name);
+}
+
 }  // namespace
 
-std::set<std::string> GetFtraceEvents(const FtraceConfig& request) {
+std::set<std::string> GetFtraceEvents(const FtraceConfig& request,
+                                      const ProtoTranslationTable* table) {
   std::set<std::string> events;
   events.insert(request.ftrace_events().begin(), request.ftrace_events().end());
   if (RequiresAtrace(request)) {
     events.insert("print");
+
+    // Ideally we should keep this code in sync with:
+    // platform/frameworks/native/cmds/atrace/atrace.cpp
+    // It's not a disaster if they go out of sync, we can always add the ftrace
+    // categories manually server side but this is user friendly and reduces the
+    // size of the configs.
+    for (const std::string& category : request.atrace_categories()) {
+      if (category == "gfx") {
+        AddEventGroup(table, "mdss", &events);
+        AddEventGroup(table, "sde", &events);
+        continue;
+      }
+
+      if (category == "sched") {
+        events.insert("sched_switch");
+        events.insert("sched_wakeup");
+        events.insert("sched_waking");
+        events.insert("sched_blocked_reason");
+        events.insert("sched_cpu_hotplug");
+        AddEventGroup(table, "cgroup", &events);
+        continue;
+      }
+
+      if (category == "irq") {
+        AddEventGroup(table, "irq", &events);
+        AddEventGroup(table, "ipi", &events);
+        continue;
+      }
+
+      if (category == "irqoff") {
+        events.insert("irq_enable");
+        events.insert("irq_disable");
+        continue;
+      }
+
+      if (category == "preemptoff") {
+        events.insert("preempt_enable");
+        events.insert("preempt_disable");
+        continue;
+      }
+
+      if (category == "i2c") {
+        AddEventGroup(table, "i2c", &events);
+        continue;
+      }
+
+      if (category == "freq") {
+        events.insert("cpu_frequency");
+        events.insert("clock_set_rate");
+        events.insert("clock_disable");
+        events.insert("clock_enable");
+        events.insert("clk_set_rate");
+        events.insert("clk_disable");
+        events.insert("clk_enable");
+        events.insert("cpu_frequency_limits");
+        continue;
+      }
+
+      if (category == "membus") {
+        AddEventGroup(table, "memory_bus", &events);
+        continue;
+      }
+
+      if (category == "idle") {
+        events.insert("cpu_idle");
+        continue;
+      }
+
+      if (category == "disk") {
+        events.insert("f2fs_sync_file_enter");
+        events.insert("f2fs_sync_file_exit");
+        events.insert("f2fs_write_begin");
+        events.insert("f2fs_write_end");
+        events.insert("ext4_da_write_begin");
+        events.insert("ext4_da_write_end");
+        events.insert("ext4_sync_file_enter");
+        events.insert("ext4_sync_file_exit");
+        events.insert("block_rq_issue");
+        events.insert("block_rq_complete");
+        continue;
+      }
+
+      if (category == "mmc") {
+        AddEventGroup(table, "mmc", &events);
+        continue;
+      }
+
+      if (category == "load") {
+        AddEventGroup(table, "cpufreq_interactive", &events);
+        continue;
+      }
+
+      if (category == "sync") {
+        AddEventGroup(table, "sync", &events);
+        continue;
+      }
+
+      if (category == "workq") {
+        AddEventGroup(table, "workqueue", &events);
+        continue;
+      }
+
+      if (category == "memreclaim") {
+        events.insert("mm_vmscan_direct_reclaim_begin");
+        events.insert("mm_vmscan_direct_reclaim_end");
+        events.insert("mm_vmscan_kswapd_wake");
+        events.insert("mm_vmscan_kswapd_sleep");
+        AddEventGroup(table, "lowmemorykiller", &events);
+        continue;
+      }
+
+      if (category == "regulators") {
+        AddEventGroup(table, "regulator", &events);
+        continue;
+      }
+
+      if (category == "binder_driver") {
+        events.insert("binder_transaction");
+        events.insert("binder_transaction_received");
+        events.insert("binder_set_priority");
+        continue;
+      }
+
+      if (category == "binder_lock") {
+        events.insert("binder_lock");
+        events.insert("binder_locked");
+        events.insert("binder_unlock");
+        continue;
+      }
+
+      if (category == "pagecache") {
+        AddEventGroup(table, "pagecache", &events);
+        continue;
+      }
+    }
   }
   return events;
 }
@@ -100,7 +246,7 @@
       return 0;
   }
 
-  std::set<std::string> events = GetFtraceEvents(request);
+  std::set<std::string> events = GetFtraceEvents(request, table_);
 
   for (auto& name : events) {
     const Event* event = table_->GetEventByName(name);
diff --git a/src/ftrace_reader/ftrace_config_muxer.h b/src/ftrace_reader/ftrace_config_muxer.h
index ce4edb4..de2a7b0 100644
--- a/src/ftrace_reader/ftrace_config_muxer.h
+++ b/src/ftrace_reader/ftrace_config_muxer.h
@@ -93,7 +93,8 @@
   std::map<FtraceConfigId, FtraceConfig> configs_;
 };
 
-std::set<std::string> GetFtraceEvents(const FtraceConfig& request);
+std::set<std::string> GetFtraceEvents(const FtraceConfig& request,
+                                      const ProtoTranslationTable*);
 size_t ComputeCpuBufferSizeInPages(size_t requested_buffer_size_kb);
 
 }  // namespace perfetto
diff --git a/src/ftrace_reader/ftrace_config_muxer_unittest.cc b/src/ftrace_reader/ftrace_config_muxer_unittest.cc
index 9a88bae..e3be7aa 100644
--- a/src/ftrace_reader/ftrace_config_muxer_unittest.cc
+++ b/src/ftrace_reader/ftrace_config_muxer_unittest.cc
@@ -94,7 +94,31 @@
     Event event;
     event.name = "sched_new";
     event.group = "sched";
-    event.ftrace_event_id = 20;
+    event.ftrace_event_id = 11;
+    events.push_back(event);
+  }
+
+  {
+    Event event;
+    event.name = "cgroup_mkdir";
+    event.group = "cgroup";
+    event.ftrace_event_id = 12;
+    events.push_back(event);
+  }
+
+  {
+    Event event;
+    event.name = "mm_vmscan_direct_reclaim_begin";
+    event.group = "vmscan";
+    event.ftrace_event_id = 13;
+    events.push_back(event);
+  }
+
+  {
+    Event event;
+    event.name = "lowmemory_kill";
+    event.group = "lowmemorykiller";
+    event.ftrace_event_id = 14;
     events.push_back(event);
   }
 
@@ -234,19 +258,37 @@
 }
 
 TEST(FtraceConfigMuxerTest, GetFtraceEvents) {
+  std::unique_ptr<ProtoTranslationTable> table = CreateFakeTable();
   FtraceConfig config = CreateFtraceConfig({"sched_switch"});
-  std::set<std::string> events = GetFtraceEvents(config);
+  std::set<std::string> events = GetFtraceEvents(config, table.get());
 
   EXPECT_THAT(events, Contains("sched_switch"));
   EXPECT_THAT(events, Not(Contains("print")));
 }
 
 TEST(FtraceConfigMuxerTest, GetFtraceEventsAtrace) {
-  FtraceConfig config = CreateFtraceConfig({"sched_switch"});
+  std::unique_ptr<ProtoTranslationTable> table = CreateFakeTable();
+  FtraceConfig config = CreateFtraceConfig({});
   *config.add_atrace_categories() = "sched";
-  std::set<std::string> events = GetFtraceEvents(config);
+  std::set<std::string> events = GetFtraceEvents(config, table.get());
 
   EXPECT_THAT(events, Contains("sched_switch"));
+  EXPECT_THAT(events, Contains("sched_cpu_hotplug"));
+  EXPECT_THAT(events, Contains("print"));
+}
+
+TEST(FtraceConfigMuxerTest, GetFtraceEventsAtraceCategories) {
+  std::unique_ptr<ProtoTranslationTable> table = CreateFakeTable();
+  FtraceConfig config = CreateFtraceConfig({});
+  *config.add_atrace_categories() = "sched";
+  *config.add_atrace_categories() = "memreclaim";
+  std::set<std::string> events = GetFtraceEvents(config, table.get());
+
+  EXPECT_THAT(events, Contains("sched_switch"));
+  EXPECT_THAT(events, Contains("sched_cpu_hotplug"));
+  EXPECT_THAT(events, Contains("cgroup_mkdir"));
+  EXPECT_THAT(events, Contains("mm_vmscan_direct_reclaim_begin"));
+  EXPECT_THAT(events, Contains("lowmemory_kill"));
   EXPECT_THAT(events, Contains("print"));
 }
 
diff --git a/src/ftrace_reader/proto_translation_table.cc b/src/ftrace_reader/proto_translation_table.cc
index f32813b..485c601 100644
--- a/src/ftrace_reader/proto_translation_table.cc
+++ b/src/ftrace_reader/proto_translation_table.cc
@@ -306,6 +306,7 @@
       common_fields_(std::move(common_fields)) {
   for (const Event& event : events) {
     name_to_event_[event.name] = &events_.at(event.ftrace_event_id);
+    group_to_events_[event.group].push_back(&events_.at(event.ftrace_event_id));
   }
 }
 
diff --git a/src/ftrace_reader/proto_translation_table.h b/src/ftrace_reader/proto_translation_table.h
index 53a4fc1..b08cc36 100644
--- a/src/ftrace_reader/proto_translation_table.h
+++ b/src/ftrace_reader/proto_translation_table.h
@@ -67,6 +67,13 @@
     return name_to_event_.at(name);
   }
 
+  const std::vector<const Event*>* GetEventsByGroup(
+      const std::string& group) const {
+    if (!group_to_events_.count(group))
+      return nullptr;
+    return &group_to_events_.at(group);
+  }
+
   const Event* GetEventById(size_t id) const {
     if (id == 0 || id > largest_id_)
       return nullptr;
@@ -90,6 +97,7 @@
   const std::vector<Event> events_;
   size_t largest_id_;
   std::map<std::string, const Event*> name_to_event_;
+  std::map<std::string, std::vector<const Event*>> group_to_events_;
   std::vector<Field> common_fields_;
 };
 
diff --git a/src/ftrace_reader/proto_translation_table_unittest.cc b/src/ftrace_reader/proto_translation_table_unittest.cc
index ce75cba..0a144c9 100644
--- a/src/ftrace_reader/proto_translation_table_unittest.cc
+++ b/src/ftrace_reader/proto_translation_table_unittest.cc
@@ -26,6 +26,10 @@
 using testing::TestWithParam;
 using testing::Return;
 using testing::AnyNumber;
+using testing::IsNull;
+using testing::Contains;
+using testing::Eq;
+using testing::Pointee;
 
 namespace perfetto {
 namespace {
@@ -299,6 +303,7 @@
   {
     Event event;
     event.name = "foo";
+    event.group = "group_one";
     event.ftrace_event_id = 1;
     events.push_back(event);
   }
@@ -306,6 +311,7 @@
   {
     Event event;
     event.name = "bar";
+    event.group = "group_one";
     event.ftrace_event_id = 2;
     events.push_back(event);
   }
@@ -313,6 +319,7 @@
   {
     Event event;
     event.name = "baz";
+    event.group = "group_two";
     event.ftrace_event_id = 100;
     events.push_back(event);
   }
@@ -326,6 +333,14 @@
   EXPECT_EQ(table.GetEventById(3), nullptr);
   EXPECT_EQ(table.GetEventById(200), nullptr);
   EXPECT_EQ(table.GetEventById(0), nullptr);
+  EXPECT_EQ(table.GetEventByName("foo")->ftrace_event_id, 1u);
+  EXPECT_THAT(*table.GetEventsByGroup("group_one"),
+              Contains(testing::Field(&Event::name, "foo")));
+  EXPECT_THAT(*table.GetEventsByGroup("group_one"),
+              Contains(testing::Field(&Event::name, "bar")));
+  EXPECT_THAT(*table.GetEventsByGroup("group_two"),
+              Contains(testing::Field(&Event::name, "baz")));
+  EXPECT_THAT(table.GetEventsByGroup("group_three"), IsNull());
 }
 
 }  // namespace
diff --git a/src/perfetto_cmd/perfetto_cmd.cc b/src/perfetto_cmd/perfetto_cmd.cc
index 3c2bacd..144b008 100644
--- a/src/perfetto_cmd/perfetto_cmd.cc
+++ b/src/perfetto_cmd/perfetto_cmd.cc
@@ -138,7 +138,7 @@
         test_config.SerializeToString(&trace_config_raw);
       } else {
         if (!base::ReadFile(optarg, &trace_config_raw)) {
-          PERFETTO_ELOG("Could not open %s", optarg);
+          PERFETTO_PLOG("Could not open %s", optarg);
           return 1;
         }
       }
diff --git a/src/traced/probes/filesystem/fs_mount.cc b/src/traced/probes/filesystem/fs_mount.cc
index 1db29ba..da2030e 100644
--- a/src/traced/probes/filesystem/fs_mount.cc
+++ b/src/traced/probes/filesystem/fs_mount.cc
@@ -44,7 +44,7 @@
     const char* mountpoint = words.cur_token();
     struct stat buf {};
     if (stat(mountpoint, &buf) == -1) {
-      PERFETTO_PLOG("stat");
+      PERFETTO_PLOG("stat %s", mountpoint);
       continue;
     }
     device_to_mountpoints.emplace(buf.st_dev, mountpoint);