Add signal events to t2t and trace processor

These events are added into a new table called "instants" for
instantaneous events.

Bug: 118687476
Change-Id: I1ea7953436cbf3e4139fa3a5db3624f9f95c6a6f
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index cd90729..124c7cb 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -47,6 +47,8 @@
     "counters_table.h",
     "event_tracker.cc",
     "event_tracker.h",
+    "instants_table.cc",
+    "instants_table.h",
     "process_table.cc",
     "process_table.h",
     "process_tracker.cc",
diff --git a/src/trace_processor/instants_table.cc b/src/trace_processor/instants_table.cc
new file mode 100644
index 0000000..d5399a9
--- /dev/null
+++ b/src/trace_processor/instants_table.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "src/trace_processor/instants_table.h"
+
+#include "src/trace_processor/storage_cursor.h"
+#include "src/trace_processor/table_utils.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+InstantsTable::InstantsTable(sqlite3*, const TraceStorage* storage)
+    : storage_(storage) {
+  ref_types_.resize(RefType::kMax);
+  ref_types_[RefType::kNoRef] = "";
+  ref_types_[RefType::kUtid] = "utid";
+  ref_types_[RefType::kCpuId] = "cpu";
+  ref_types_[RefType::kIrq] = "irq";
+  ref_types_[RefType::kSoftIrq] = "softirq";
+  ref_types_[RefType::kUpid] = "upid";
+};
+
+void InstantsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) {
+  Table::Register<InstantsTable>(db, storage, "instants");
+}
+
+Table::Schema InstantsTable::CreateSchema(int, const char* const*) {
+  const auto& instants = storage_->instants();
+  std::unique_ptr<StorageSchema::Column> cols[] = {
+      StorageSchema::NumericColumnPtr("ts", &instants.timestamps(),
+                                      false /* hidden */, true /* ordered */),
+      StorageSchema::StringColumnPtr("name", &instants.name_ids(),
+                                     &storage_->string_pool()),
+      StorageSchema::NumericColumnPtr("value", &instants.values()),
+      StorageSchema::NumericColumnPtr("ref", &instants.refs()),
+      StorageSchema::StringColumnPtr("ref_type", &instants.types(),
+                                     &ref_types_)};
+  schema_ = StorageSchema({
+      std::make_move_iterator(std::begin(cols)),
+      std::make_move_iterator(std::end(cols)),
+  });
+  return schema_.ToTableSchema({"name", "ts", "ref"});
+}
+
+std::unique_ptr<Table::Cursor> InstantsTable::CreateCursor(
+    const QueryConstraints& qc,
+    sqlite3_value** argv) {
+  uint32_t count = static_cast<uint32_t>(storage_->instants().instant_count());
+  auto it = table_utils::CreateBestRowIteratorForGenericSchema(schema_, count,
+                                                               qc, argv);
+  return std::unique_ptr<Table::Cursor>(
+      new StorageCursor(std::move(it), schema_.ToColumnReporters()));
+}
+
+int InstantsTable::BestIndex(const QueryConstraints& qc, BestIndexInfo* info) {
+  info->estimated_cost =
+      static_cast<uint32_t>(storage_->counters().counter_count());
+
+  // Only the string columns are handled by SQLite
+  info->order_by_consumed = true;
+  size_t name_index = schema_.ColumnIndexFromName("name");
+  size_t ref_type_index = schema_.ColumnIndexFromName("ref_type");
+  for (size_t i = 0; i < qc.constraints().size(); i++) {
+    info->omit[i] =
+        qc.constraints()[i].iColumn != static_cast<int>(name_index) &&
+        qc.constraints()[i].iColumn != static_cast<int>(ref_type_index);
+  }
+
+  return SQLITE_OK;
+}
+}  // namespace trace_processor
+}  // namespace perfetto
diff --git a/src/trace_processor/instants_table.h b/src/trace_processor/instants_table.h
new file mode 100644
index 0000000..38379fa
--- /dev/null
+++ b/src/trace_processor/instants_table.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SRC_TRACE_PROCESSOR_INSTANTS_TABLE_H_
+#define SRC_TRACE_PROCESSOR_INSTANTS_TABLE_H_
+
+#include "src/trace_processor/storage_schema.h"
+#include "src/trace_processor/table.h"
+#include "src/trace_processor/trace_storage.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class InstantsTable : public Table {
+ public:
+  static void RegisterTable(sqlite3* db, const TraceStorage* storage);
+
+  InstantsTable(sqlite3*, const TraceStorage*);
+
+  // Table implementation.
+  Table::Schema CreateSchema(int argc, const char* const* argv) override;
+  std::unique_ptr<Table::Cursor> CreateCursor(const QueryConstraints&,
+                                              sqlite3_value**) override;
+  int BestIndex(const QueryConstraints&, BestIndexInfo*) override;
+
+ private:
+  std::deque<std::string> ref_types_;
+  StorageSchema schema_;
+  const TraceStorage* const storage_;
+};
+}  // namespace trace_processor
+}  // namespace perfetto
+
+#endif  // SRC_TRACE_PROCESSOR_INSTANTS_TABLE_H_
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index 87da1ad..b4db65e 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -124,7 +124,9 @@
       cpu_times_softirq_ns_id_(
           context->storage->InternString("cpu.times.softirq_ns")),
       ion_heap_grow_id_(context->storage->InternString("ion_heap_grow")),
-      ion_heap_shrink_id_(context->storage->InternString("ion_heap_shrink")) {
+      ion_heap_shrink_id_(context->storage->InternString("ion_heap_shrink")),
+      signal_deliver_id_(context->storage->InternString("signal_deliver")),
+      signal_generate_id_(context->storage->InternString("signal_generate")) {
   for (const auto& name : BuildMeminfoCounterNames()) {
     meminfo_strs_id_.emplace_back(context->storage->InternString(name));
   }
@@ -546,6 +548,18 @@
         ParseIonHeapShrink(timestamp, pid, ftrace.slice(fld_off, fld.size()));
         break;
       }
+      case protos::FtraceEvent::kSignalGenerate: {
+        PERFETTO_DCHECK(timestamp > 0);
+        const size_t fld_off = ftrace.offset_of(fld.data());
+        ParseSignalGenerate(timestamp, ftrace.slice(fld_off, fld.size()));
+        break;
+      }
+      case protos::FtraceEvent::kSignalDeliver: {
+        PERFETTO_DCHECK(timestamp > 0);
+        const size_t fld_off = ftrace.offset_of(fld.data());
+        ParseSignalDeliver(timestamp, pid, ftrace.slice(fld_off, fld.size()));
+        break;
+      }
 
       default:
         break;
@@ -554,6 +568,45 @@
   PERFETTO_DCHECK(decoder.IsEndOfBuffer());
 }
 
+void ProtoTraceParser::ParseSignalDeliver(uint64_t timestamp,
+                                          uint32_t pid,
+                                          TraceBlobView view) {
+  ProtoDecoder decoder(view.data(), view.length());
+  uint32_t sig = 0;
+  for (auto fld = decoder.ReadField(); fld.id != 0; fld = decoder.ReadField()) {
+    switch (fld.id) {
+      case protos::SignalDeliverFtraceEvent::kSigFieldNumber:
+        sig = fld.as_uint32();
+        break;
+    }
+  }
+  auto* instants = context_->storage->mutable_instants();
+  UniqueTid utid = context_->process_tracker->UpdateThread(timestamp, pid, 0);
+  instants->AddInstantEvent(timestamp, signal_deliver_id_, sig, utid,
+                            RefType::kUtid);
+}
+
+void ProtoTraceParser::ParseSignalGenerate(uint64_t timestamp,
+                                           TraceBlobView view) {
+  ProtoDecoder decoder(view.data(), view.length());
+  uint32_t pid = 0;
+  uint32_t sig = 0;
+  for (auto fld = decoder.ReadField(); fld.id != 0; fld = decoder.ReadField()) {
+    switch (fld.id) {
+      case protos::SignalGenerateFtraceEvent::kPidFieldNumber:
+        pid = fld.as_uint32();
+        break;
+      case protos::SignalGenerateFtraceEvent::kSigFieldNumber:
+        sig = fld.as_uint32();
+        break;
+    }
+  }
+  auto* instants = context_->storage->mutable_instants();
+  UniqueTid utid = context_->process_tracker->UpdateThread(timestamp, pid, 0);
+  instants->AddInstantEvent(timestamp, signal_generate_id_, sig, utid,
+                            RefType::kUtid);
+}
+
 void ProtoTraceParser::ParseRssStat(uint64_t timestamp,
                                     uint32_t pid,
                                     TraceBlobView view) {
diff --git a/src/trace_processor/proto_trace_parser.h b/src/trace_processor/proto_trace_parser.h
index 75e34f9..5767191 100644
--- a/src/trace_processor/proto_trace_parser.h
+++ b/src/trace_processor/proto_trace_parser.h
@@ -76,6 +76,8 @@
   void ParseRssStat(uint64_t ts, uint32_t pid, TraceBlobView);
   void ParseIonHeapGrow(uint64_t ts, uint32_t pid, TraceBlobView);
   void ParseIonHeapShrink(uint64_t ts, uint32_t pid, TraceBlobView);
+  void ParseSignalDeliver(uint64_t ts, uint32_t pid, TraceBlobView);
+  void ParseSignalGenerate(uint64_t ts, TraceBlobView);
 
  private:
   TraceProcessorContext* context_;
@@ -94,6 +96,8 @@
   const StringId cpu_times_softirq_ns_id_;
   const StringId ion_heap_grow_id_;
   const StringId ion_heap_shrink_id_;
+  const StringId signal_deliver_id_;
+  const StringId signal_generate_id_;
   std::vector<StringId> meminfo_strs_id_;
   std::vector<StringId> vmstat_strs_id_;
   std::vector<StringId> rss_members_;
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 52aa8a6..571c399 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -22,6 +22,7 @@
 #include "perfetto/base/time.h"
 #include "src/trace_processor/counters_table.h"
 #include "src/trace_processor/event_tracker.h"
+#include "src/trace_processor/instants_table.h"
 #include "src/trace_processor/json_trace_parser.h"
 #include "src/trace_processor/process_table.h"
 #include "src/trace_processor/process_tracker.h"
@@ -65,6 +66,7 @@
   CountersTable::RegisterTable(*db_, context_.storage.get());
   SpanOperatorTable::RegisterTable(*db_, context_.storage.get());
   WindowOperatorTable::RegisterTable(*db_, context_.storage.get());
+  InstantsTable::RegisterTable(*db_, context_.storage.get());
 }
 
 TraceProcessorImpl::~TraceProcessorImpl() = default;
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index cc59228..57de9ed 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -229,6 +229,41 @@
     std::deque<uint64_t> times_ended_;
   };
 
+  class Instants {
+   public:
+    inline size_t AddInstantEvent(uint64_t timestamp,
+                                  StringId name_id,
+                                  double value,
+                                  int64_t ref,
+                                  RefType type) {
+      timestamps_.emplace_back(timestamp);
+      name_ids_.emplace_back(name_id);
+      values_.emplace_back(value);
+      refs_.emplace_back(ref);
+      types_.emplace_back(type);
+      return instant_count() - 1;
+    }
+
+    size_t instant_count() const { return timestamps_.size(); }
+
+    const std::deque<uint64_t>& timestamps() const { return timestamps_; }
+
+    const std::deque<StringId>& name_ids() const { return name_ids_; }
+
+    const std::deque<double>& values() const { return values_; }
+
+    const std::deque<int64_t>& refs() const { return refs_; }
+
+    const std::deque<RefType>& types() const { return types_; }
+
+   private:
+    std::deque<uint64_t> timestamps_;
+    std::deque<StringId> name_ids_;
+    std::deque<double> values_;
+    std::deque<int64_t> refs_;
+    std::deque<RefType> types_;
+  };
+
   void ResetStorage();
 
   UniqueTid AddEmptyThread(uint32_t tid) {
@@ -287,6 +322,9 @@
   const SqlStats& sql_stats() const { return sql_stats_; }
   SqlStats* mutable_sql_stats() { return &sql_stats_; }
 
+  const Instants& instants() const { return instants_; }
+  Instants* mutable_instants() { return &instants_; }
+
   const std::deque<std::string>& string_pool() const { return string_pool_; }
 
   // |unique_processes_| always contains at least 1 element becuase the 0th ID
@@ -331,6 +369,10 @@
   Counters counters_;
 
   SqlStats sql_stats_;
+  // These are instantaneous events in the trace. They have no duration
+  // and do not have a value that make sense to track over time.
+  // e.g. signal events
+  Instants instants_;
 };
 
 }  // namespace trace_processor