iorap: Add support to filter the compiled trace with app pid.

This will help mitigate potential contention caused by IORap.
For adobe reader, it could reduce the size of compiled trace
from ~400KB to ~100KB on my flame.

The performance is not affected based on benchmarking result
https://dashboards.corp.google.com/_f31ff276_6cb2_4ed6_973b_9640c4fb0df4?fb=BootImageProfileId:eq:2894

Bug: 173546018
Test: atest iorap-host-test
Test: Run apps with perfetto tracing and check the content of the
compiled trace.

Change-Id: Ie85cd7181fd0e11522f7db47217a0594cb2ecd3c
diff --git a/src/compiler/compiler.cc b/src/compiler/compiler.cc
index 7d0e624..488b30a 100644
--- a/src/compiler/compiler.cc
+++ b/src/compiler/compiler.cc
@@ -60,6 +60,11 @@
    * It's used to truncate the trace file.
    */
   uint64_t timestamp_limit_ns;
+  /*
+   * The pid of the app.
+   * If positive, it's used to filter out other page cache events.
+   */
+  int32_t pid;
 };
 
 struct PerfettoTracePtrInfo {
@@ -70,6 +75,11 @@
    * It's used to truncate the trace file.
    */
   uint64_t timestamp_limit_ns;
+  /*
+   * The pid of the app.
+   * If positive, it's used to filter out other page cache events.
+   */
+  int32_t pid;
 };
 
 // Attempt to read protobufs from the filenames.
@@ -86,14 +96,15 @@
     .map([](const CompilationInput& file_info) ->
          std::optional<PerfettoTraceProtoInfo> {
       LOG(VERBOSE) << "compiler::ReadProtosFromFileNames " << file_info.filename
-                   << " TimeStampLimit "<< file_info.timestamp_limit_ns << " [begin]";
+                   << " TimeStampLimit "<< file_info.timestamp_limit_ns
+                   << " Pid " << file_info.pid << " [begin]";
       std::optional<BinaryWireProtoT> maybe_proto =
           BinaryWireProtoT::ReadFullyFromFile(file_info.filename);
       if (!maybe_proto) {
         LOG(ERROR) << "Failed to read file: " << file_info.filename;
         return std::nullopt;
       }
-      return {{std::move(maybe_proto.value()), file_info.timestamp_limit_ns}};
+      return {{std::move(maybe_proto.value()), file_info.timestamp_limit_ns, file_info.pid}};
     })
     .filter([](const std::optional<PerfettoTraceProtoInfo>& proto_info) {
       return proto_info.has_value();
@@ -109,7 +120,7 @@
         LOG(ERROR) << "Failed to parse protobuf: ";  // TODO: filename.
         return std::nullopt;
       }
-      return {{std::move(t.value()), proto_info.timestamp_limit_ns}};
+      return {{std::move(t.value()), proto_info.timestamp_limit_ns, proto_info.pid}};
     })
     .filter([](const std::optional<PerfettoTracePtrInfo>& trace_info) {
       return trace_info.has_value();
@@ -291,7 +302,9 @@
   constexpr bool kDebugFunction = true;
 
   return rxcpp::observable<>::create<PageCacheFtraceEvent>(
-      [trace=std::move(trace), timestamp_limit_ns=trace_info.timestamp_limit_ns]
+      [trace=std::move(trace),
+      timestamp_limit_ns=trace_info.timestamp_limit_ns,
+      app_pid=trace_info.pid]
       (rxcpp::subscriber<PageCacheFtraceEvent> sub) {
     uint64_t timestamp = 0;
     uint64_t timestamp_relative = 0;
@@ -347,6 +360,12 @@
             return;
           }
 
+          if (app_pid >= 0 &&
+              (!event.has_pid() ||
+               event.pid() != static_cast<uint32_t>(app_pid))) {
+            continue;
+          }
+
           if (event.has_timestamp()) {
             timestamp = event.timestamp();
             if(timestamp > timestamp_limit_ns) {
@@ -821,7 +840,8 @@
 /** Makes a vector of info that includes filename and timestamp limit. */
 std::vector<CompilationInput> MakeCompilationInputs(
     std::vector<std::string> input_file_names,
-    std::vector<uint64_t> timestamp_limit_ns){
+    std::vector<uint64_t> timestamp_limit_ns,
+    std::vector<int32_t> pids){
   // If the timestamp limit is empty, set the limit to max value
   // for each trace file.
   if (timestamp_limit_ns.empty()) {
@@ -829,10 +849,18 @@
       timestamp_limit_ns.push_back(std::numeric_limits<uint64_t>::max());
     }
   }
+
+  // If the pids is empty, set all of them to -1. Because negative pid means any.
+  if (pids.empty()) {
+    for (size_t i = 0; i < input_file_names.size(); i++) {
+      pids.push_back(-1);
+    }
+  }
+
   DCHECK_EQ(input_file_names.size(), timestamp_limit_ns.size());
   std::vector<CompilationInput> file_infos;
   for (size_t i = 0; i < input_file_names.size(); i++) {
-    file_infos.push_back({input_file_names[i], timestamp_limit_ns[i]});
+    file_infos.push_back({input_file_names[i], timestamp_limit_ns[i], pids[i]});
   }
   return file_infos;
 }
diff --git a/src/compiler/compiler.h b/src/compiler/compiler.h
index 1fa9ff1..243ab36 100644
--- a/src/compiler/compiler.h
+++ b/src/compiler/compiler.h
@@ -30,6 +30,12 @@
    * It's used to truncate the trace file.
    */
   uint64_t timestamp_limit_ns;
+
+  /*
+   * The pid of the app.
+   * If positive, it's used to filter out other page cache events.
+   */
+  int32_t pid;
 };
 
 // Compile one or more perfetto TracePacket protobufs that are stored on the filesystem
@@ -59,7 +65,8 @@
 // If timestamp_limit_ns is empty, will use the max uint64_t.
 std::vector<CompilationInput> MakeCompilationInputs(
     std::vector<std::string> input_file_names,
-    std::vector<uint64_t> timestamp_limit_ns);
+    std::vector<uint64_t> timestamp_limit_ns,
+    std::vector<int32_t> pids);
 }
 
 #endif  // IORAP_SRC_COMPILER_COMPILER_H_
diff --git a/src/compiler/main.cc b/src/compiler/main.cc
index 264f94f..2f3bc96 100644
--- a/src/compiler/main.cc
+++ b/src/compiler/main.cc
@@ -75,6 +75,7 @@
   std::cerr << "    --inode-textcache $,-it $  Resolve inode->filename from textcache (disables diskscan)." << std::endl;
   std::cerr << "    --verbose,-v               Set verbosity (default off)." << std::endl;
   std::cerr << "    --wait,-w                  Wait for key stroke before continuing (default off)." << std::endl;
+  std::cerr << "    --pid,-p                   Set the pid for the compiled trace" << std::endl;
   std::cerr << "    --timestamp_limit_ns,-tl   Set the limit timestamp in nanoseconds for the compiled trace. "
                                               "The order and size of the timestamp should match that of "
                                               "the input trace files. If not specified at all, All of"
@@ -95,6 +96,7 @@
   std::optional<std::string> arg_inode_textcache;
 
   std::vector<uint64_t> timestamp_limit_ns;
+  std::vector<int32_t> pids;
 
   if (argc == 1) {
     // Need at least 1 input file to do anything.
@@ -138,6 +140,18 @@
       enable_verbose = true;
     } else if (argstr == "--wait" || argstr == "-w") {
       wait_for_keystroke = true;
+    } else if (argstr == "--pid" || argstr == "-p") {
+      if (!has_arg_next) {
+        std::cerr << "Missing --pid <value>" << std::endl;
+        return 1;
+      }
+      int32_t pid;
+      if (!::android::base::ParseInt<int32_t>(arg_next, &pid)) {
+        std::cerr << "Invalid --pid "<< pid << std::endl;
+        return 1;
+      }
+      pids.push_back(pid);
+      ++arg;
     } else if (argstr == "--timestamp_limit_ns" || argstr == "-tl") {
       if (!has_arg_next) {
         std::cerr << "Missing --timestamp_limit_ns <value>" << std::endl;
@@ -162,6 +176,11 @@
     return 1;
   }
 
+  if (!pids.empty() && pids.size() != arg_input_filenames.size()) {
+    std::cerr << "The size of pids doesn't match the size of input files."
+              << std::endl;
+    return 1;
+  }
   if (enable_verbose) {
     android::base::SetMinimumLogSeverity(android::base::VERBOSE);
 
@@ -213,7 +232,7 @@
 
   int return_code = 0;
   std::vector<CompilationInput> perfetto_traces =
-      MakeCompilationInputs(arg_input_filenames, timestamp_limit_ns);
+      MakeCompilationInputs(arg_input_filenames, timestamp_limit_ns, pids);
   return_code =
       !PerformCompilation(std::move(perfetto_traces),
                           std::move(arg_output_proto),
diff --git a/src/db/models.h b/src/db/models.h
index df6beb6..79823fd 100644
--- a/src/db/models.h
+++ b/src/db/models.h
@@ -34,7 +34,7 @@
 
 namespace iorap::db {
 
-const constexpr int kDbVersion = 2;
+const constexpr int kDbVersion = 3;
 
 struct SqliteDbDeleter {
   void operator()(sqlite3* db) {
@@ -509,6 +509,8 @@
             total_time_ns INTEGER CHECK(total_time_ns IS NULL or total_time_ns >= 0),
             -- absolute timestamp since epoch
             report_fully_drawn_ns INTEGER CHECK(report_fully_drawn_ns IS NULL or report_fully_drawn_ns >= 0),
+            -- pid of the app
+            pid INTEGER CHECK(pid IS NULL or pid >= 0),
 
             FOREIGN KEY (activity_id) REFERENCES activities (id) ON DELETE CASCADE
         );
@@ -810,7 +812,8 @@
                                     p.readahead_enabled,
                                     p.intent_started_ns,
                                     p.total_time_ns,
-                                    p.report_fully_drawn_ns)) {
+                                    p.report_fully_drawn_ns,
+                                    p.pid)) {
       return std::nullopt;
     }
 
@@ -843,7 +846,8 @@
                                       p.readahead_enabled,
                                       p.intent_started_ns,
                                       p.total_time_ns,
-                                      p.report_fully_drawn_ns)) {
+                                      p.report_fully_drawn_ns,
+                                      p.pid)) {
       result.push_back(p);
     }
     return result;
@@ -856,12 +860,13 @@
                                                      bool readahead_enabled,
                                                      std::optional<uint64_t> intent_started_ns,
                                                      std::optional<uint64_t> total_time_ns,
-                                                     std::optional<uint64_t> report_fully_drawn_ns)
+                                                     std::optional<uint64_t> report_fully_drawn_ns,
+                                                     int32_t pid)
   {
     const char* sql = "INSERT INTO app_launch_histories (activity_id, temperature, trace_enabled, "
                                                         "readahead_enabled, intent_started_ns, "
-                                                        "total_time_ns, report_fully_drawn_ns) "
-                      "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7);";
+                                                        "total_time_ns, report_fully_drawn_ns, pid) "
+                      "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8);";
 
     std::optional<int> inserted_row_id =
         DbQueryBuilder::Insert(db,
@@ -872,7 +877,8 @@
                                readahead_enabled,
                                intent_started_ns,
                                total_time_ns,
-                               report_fully_drawn_ns);
+                               report_fully_drawn_ns,
+                               pid);
     if (!inserted_row_id) {
       return std::nullopt;
     }
@@ -886,6 +892,7 @@
     p.intent_started_ns = intent_started_ns;
     p.total_time_ns = total_time_ns;
     p.report_fully_drawn_ns = report_fully_drawn_ns;
+    p.pid = pid;
 
     return p;
   }
@@ -915,6 +922,7 @@
   std::optional<uint64_t> intent_started_ns;
   std::optional<uint64_t> total_time_ns;
   std::optional<uint64_t> report_fully_drawn_ns;
+  int32_t pid;
 };
 
 inline std::ostream& operator<<(std::ostream& os, const AppLaunchHistoryModel& p) {
@@ -943,6 +951,8 @@
   } else {
     os << "(nullopt)";
   }
+  os << ",";
+  os << "pid=" << p.pid;
   os << "}";
   return os;
 }
diff --git a/src/maintenance/controller.cc b/src/maintenance/controller.cc
index daaf08f..3bf0d6a 100644
--- a/src/maintenance/controller.cc
+++ b/src/maintenance/controller.cc
@@ -89,6 +89,7 @@
   std::vector<std::string> input_pbs;
   std::vector<uint64_t> timestamp_limit_ns;
   std::string output_proto;
+  std::vector<int32_t> pids;
   ControllerParameters controller_params;
 
   CompilerForkParameters(const std::vector<compiler::CompilationInput>& perfetto_traces,
@@ -98,6 +99,7 @@
         for (compiler::CompilationInput perfetto_trace : perfetto_traces) {
           input_pbs.push_back(perfetto_trace.filename);
           timestamp_limit_ns.push_back(perfetto_trace.timestamp_limit_ns);
+          pids.push_back(perfetto_trace.pid);
         }
   }
 };
@@ -108,6 +110,7 @@
 
     common::AppendArgsRepeatedly(argv, params.input_pbs);
     common::AppendArgsRepeatedly(argv, "--timestamp_limit_ns", params.timestamp_limit_ns);
+    common::AppendArgsRepeatedly(argv, "--pid", params.pids);
 
     if (controller_params.output_text) {
       argv.push_back("--output-text");
@@ -227,6 +230,11 @@
       continue;
     }
 
+    if (!history.pid) {
+      LOG(DEBUG) << "Missing pid for history " << history.id;
+      continue;
+    }
+
     uint64_t timestamp_limit = std::numeric_limits<uint64_t>::max();
     // Get corresponding timestamp limit.
     if (history.report_fully_drawn_ns) {
@@ -236,7 +244,7 @@
     } else {
       LOG(DEBUG) << " No timestamp exists. Using the max value.";
     }
-    perfetto_traces.push_back({raw_trace->file_path, timestamp_limit});
+    perfetto_traces.push_back({raw_trace->file_path, timestamp_limit, history.pid});
   }
   return perfetto_traces;
 }
diff --git a/src/manager/event_manager.cc b/src/manager/event_manager.cc
index 2ccd42c..485c1da 100644
--- a/src/manager/event_manager.cc
+++ b/src/manager/event_manager.cc
@@ -335,7 +335,7 @@
         if (event.timestamp_nanos >= 0) {
            total_time_ns_ = event.timestamp_nanos;
         }
-        RecordDbLaunchHistory();
+        RecordDbLaunchHistory(event.activity_record_proto->proc_id());
         // Finish tracing and collect trace buffer.
         //
         // TODO: this happens automatically when perfetto finishes its
@@ -621,8 +621,8 @@
     // FIXME: how do we clear this vector?
   }
 
-  void RecordDbLaunchHistory() {
-    std::optional<db::AppLaunchHistoryModel> history = InsertDbLaunchHistory();
+  void RecordDbLaunchHistory(int32_t pid) {
+    std::optional<db::AppLaunchHistoryModel> history = InsertDbLaunchHistory(pid);
 
     // RecordDbLaunchHistory happens-after kIntentStarted
     if (!history_id_subscriber_.has_value()) {
@@ -647,7 +647,7 @@
     history_id_subscriber_ = std::nullopt;
   }
 
-  std::optional<db::AppLaunchHistoryModel> InsertDbLaunchHistory() {
+  std::optional<db::AppLaunchHistoryModel> InsertDbLaunchHistory(int32_t pid) {
     // TODO: deferred queue into a different lower priority thread.
     if (!component_name_ || !temperature_) {
       LOG(VERBOSE) << "Skip RecordDbLaunchHistory, no component name available.";
@@ -689,7 +689,8 @@
                                       intent_started_ns_,
                                       total_time_ns_,
                                       // ReportFullyDrawn event normally occurs after this. Need update later.
-                                      /* report_fully_drawn_ns= */ std::nullopt);
+                                      /* report_fully_drawn_ns= */ std::nullopt,
+                                      pid);
     //Repo
     if (!alh) {
       LOG(WARNING) << "Failed to insert app_launch_histories row";
diff --git a/tests/src/compiler/compiler_test.cc b/tests/src/compiler/compiler_test.cc
index fb3e70b..26b56ec 100644
--- a/tests/src/compiler/compiler_test.cc
+++ b/tests/src/compiler/compiler_test.cc
@@ -59,7 +59,7 @@
 
 
   std::vector<CompilationInput> perfetto_traces =
-      MakeCompilationInputs(input_file_names, timestamp_limit_ns);
+      MakeCompilationInputs(input_file_names, timestamp_limit_ns, /*pids=*/{});
   bool result = PerformCompilation(perfetto_traces,
                                    output_file_name,
                                    output_proto,
@@ -89,7 +89,7 @@
   bool output_proto = false;
 
   std::vector<CompilationInput> perfetto_traces =
-      MakeCompilationInputs(input_file_names, timestamp_limit_ns);
+      MakeCompilationInputs(input_file_names, timestamp_limit_ns, /*pids=*/{});
   bool result = PerformCompilation(perfetto_traces,
                                    output_file_name,
                                    output_proto,
@@ -118,7 +118,7 @@
   bool output_proto = false;
 
   std::vector<CompilationInput> perfetto_traces =
-      MakeCompilationInputs(input_file_names, /* timestamp_limit_ns= */{});
+      MakeCompilationInputs(input_file_names, /* timestamp_limit_ns= */{}, /*pids=*/{});
   bool result = PerformCompilation(perfetto_traces,
                                    output_file_name,
                                    output_proto,
@@ -145,7 +145,7 @@
   //                    --blacklist-filter "[.](art|oat|odex|vdex|dex)$" common_perfetto_trace.pb
 
   std::vector<CompilationInput> perfetto_traces =
-      MakeCompilationInputs(input_file_names, /* timestamp_limit_ns= */{});
+      MakeCompilationInputs(input_file_names, /* timestamp_limit_ns= */{}, /*pids=*/{});
   bool result = PerformCompilation(perfetto_traces,
                                    output_file_name,
                                    output_proto,
@@ -159,4 +159,26 @@
   EXPECT_EQ(result, true);
   EXPECT_EQ(line_num, 1617UL);
 }
+
+TEST_F(CompilerTest, PidFilter) {
+  std::vector<std::string> input_file_names{GetTestDataPath("common_perfetto_trace.pb")};
+  TemporaryFile tmp_file;
+  char* output_file_name = tmp_file.path;
+  bool output_proto = false;
+
+  std::vector<CompilationInput> perfetto_traces =
+      MakeCompilationInputs(input_file_names, /*timestamp_limit_ns=*/{}, /*pids=*/{30716});
+  bool result = PerformCompilation(perfetto_traces,
+                                   output_file_name,
+                                   output_proto,
+                                   /*deny_filter*/std::nullopt,
+                                   ir_dependencies);
+  std::ifstream ifs(output_file_name);
+  size_t line_num = std::count((std::istreambuf_iterator<char>(ifs)),
+                               (std::istreambuf_iterator<char>()),
+                               '\n');
+
+  EXPECT_EQ(result, true);
+  EXPECT_EQ(line_num, 13UL);
+}
 }  // namespace iorap::compiler