trace_processor: Parse systrace counter events

Parsing systrace counter events, made tracker code generic
and added value delta.

Change-Id: I81bfce42ad3bba1f893d38cec4dc46aa0c5800ae
diff --git a/src/trace_processor/counters_table.cc b/src/trace_processor/counters_table.cc
index eec57f9..4f2173f 100644
--- a/src/trace_processor/counters_table.cc
+++ b/src/trace_processor/counters_table.cc
@@ -42,8 +42,9 @@
          "name text, "
          "value UNSIGNED BIG INT, "
          "dur UNSIGNED BIG INT, "
+         "value_delta UNSIGNED BIG INT, "
          "ref UNSIGNED INT, "
-         "reftype TEXT, "
+         "ref_type TEXT, "
          "PRIMARY KEY(name, ts, ref)"
          ") WITHOUT ROWID;";
 }
@@ -107,6 +108,12 @@
           static_cast<int64_t>(storage_->counters().durations()[row_]));
       break;
     }
+    case Column::kValueDelta: {
+      sqlite3_result_int64(
+          context,
+          static_cast<int64_t>(storage_->counters().value_deltas()[row_]));
+      break;
+    }
     default:
       PERFETTO_FATAL("Unknown column %d", N);
       break;
diff --git a/src/trace_processor/counters_table.h b/src/trace_processor/counters_table.h
index 9e257e3..5ef21ba 100644
--- a/src/trace_processor/counters_table.h
+++ b/src/trace_processor/counters_table.h
@@ -33,8 +33,9 @@
     kName = 1,
     kValue = 2,
     kDuration = 3,
-    kRef = 4,
-    kRefType = 5,
+    kValueDelta = 4,
+    kRef = 5,
+    kRefType = 6,
   };
 
   static void RegisterTable(sqlite3* db, const TraceStorage* storage);
diff --git a/src/trace_processor/counters_table_unittest.cc b/src/trace_processor/counters_table_unittest.cc
index 0ff7cde..211cb78 100644
--- a/src/trace_processor/counters_table_unittest.cc
+++ b/src/trace_processor/counters_table_unittest.cc
@@ -63,11 +63,11 @@
   uint64_t timestamp = 1000;
   uint32_t freq = 3000;
   context_.storage->mutable_counters()->AddCounter(
-      timestamp, 0, 1, freq, 1 /* cpu */, RefType::kCPU_ID);
+      timestamp, 0, 1, freq, 0, 1 /* cpu */, RefType::kCPU_ID);
   context_.storage->mutable_counters()->AddCounter(
-      timestamp + 1, 1, 1, freq + 1000, 1 /* cpu */, RefType::kCPU_ID);
+      timestamp + 1, 1, 1, freq + 1000, 1000, 1 /* cpu */, RefType::kCPU_ID);
   context_.storage->mutable_counters()->AddCounter(
-      timestamp + 2, 1, 1, freq + 2000, 2 /* cpu */, RefType::kCPU_ID);
+      timestamp + 2, 1, 1, freq + 2000, 1000, 2 /* cpu */, RefType::kCPU_ID);
 
   PrepareValidStatement("SELECT ts, dur, value FROM counters where ref = 1");
 
@@ -87,12 +87,16 @@
 TEST_F(CountersTableUnittest, GroupByFreq) {
   uint64_t timestamp = 1000;
   uint32_t freq = 3000;
+  uint32_t name_id = 1;
   context_.storage->mutable_counters()->AddCounter(
-      timestamp, 1, 1, freq, 1 /* cpu */, RefType::kCPU_ID);
+      timestamp, 1 /* dur */, name_id, freq, 0 /* value delta */, 1 /* cpu */,
+      RefType::kCPU_ID);
   context_.storage->mutable_counters()->AddCounter(
-      timestamp + 1, 2, 1, freq + 1000, 1 /* cpu */, RefType::kCPU_ID);
+      timestamp + 1, 2 /* dur */, name_id, freq + 1000, 1000 /* value delta */,
+      1 /* cpu */, RefType::kCPU_ID);
   context_.storage->mutable_counters()->AddCounter(
-      timestamp + 3, 0, 1, freq, 1 /* cpu */, RefType::kCPU_ID);
+      timestamp + 3, 0 /* dur */, name_id, freq, -1000 /* value delta */,
+      1 /* cpu */, RefType::kCPU_ID);
 
   PrepareValidStatement(
       "SELECT value, sum(dur) as dur_sum FROM counters where value > 0 group "
diff --git a/src/trace_processor/proto_trace_parser.cc b/src/trace_processor/proto_trace_parser.cc
index 78ee7ad..8593a26 100644
--- a/src/trace_processor/proto_trace_parser.cc
+++ b/src/trace_processor/proto_trace_parser.cc
@@ -71,10 +71,25 @@
       out->name = base::StringView(s + name_index, len - name_index);
       return true;
     }
-    case 'E':
+    case 'E': {
       return true;
-    case 'C':
+    }
+    case 'C': {
+      size_t name_index = 2 + pid_length + 1;
+      size_t name_length = 0;
+      for (size_t i = name_index; i < len; i++) {
+        if (s[i] == '|' || s[i] == '\n') {
+          name_length = i - name_index;
+          break;
+        }
+      }
+      out->name = base::StringView(s + name_index, name_length);
+      size_t value_index = name_index + name_length + 1;
+      char value_str[32];
+      std::strcpy(value_str, s + value_index);
+      out->value = std::stod(value_str);
       return true;
+    }
     default:
       return false;
   }
@@ -285,6 +300,12 @@
       context_->slice_tracker->End(timestamp, upid);
       break;
     }
+
+    case 'C': {
+      StringId name_id = context_->storage->InternString(point.name);
+      context_->sched_tracker->PushCounter(timestamp, point.value, name_id,
+                                           upid, RefType::kUPID);
+    }
   }
   PERFETTO_DCHECK(decoder.IsEndOfBuffer());
 }
diff --git a/src/trace_processor/proto_trace_parser.h b/src/trace_processor/proto_trace_parser.h
index bccf534..2586e5c 100644
--- a/src/trace_processor/proto_trace_parser.h
+++ b/src/trace_processor/proto_trace_parser.h
@@ -37,7 +37,7 @@
   base::StringView name;
 
   // For phase = 'C' only.
-  int64_t value;
+  double value;
 };
 
 inline bool operator==(const SystraceTracePoint& x,
diff --git a/src/trace_processor/proto_trace_parser_unittest.cc b/src/trace_processor/proto_trace_parser_unittest.cc
index a2c1576..c0881c8 100644
--- a/src/trace_processor/proto_trace_parser_unittest.cc
+++ b/src/trace_processor/proto_trace_parser_unittest.cc
@@ -297,6 +297,10 @@
 
   ASSERT_TRUE(ParseSystraceTracePoint(base::StringView("B|42|Bar"), &result));
   EXPECT_EQ(result, (SystraceTracePoint{'B', 42, base::StringView("Bar"), 0}));
+
+  ASSERT_TRUE(
+      ParseSystraceTracePoint(base::StringView("C|543|foo|8"), &result));
+  EXPECT_EQ(result, (SystraceTracePoint{'C', 543, base::StringView("foo"), 8}));
 }
 
 }  // namespace
diff --git a/src/trace_processor/sched_tracker.cc b/src/trace_processor/sched_tracker.cc
index 5e9021b..4dcc097 100644
--- a/src/trace_processor/sched_tracker.cc
+++ b/src/trace_processor/sched_tracker.cc
@@ -81,21 +81,24 @@
     return;
   }
   prev_timestamp_ = timestamp;
-  Counter& prev = last_counter_per_cpu_[static_cast<size_t>(ref)];
+
+  // The previous counter with the same ref and name_id.
+  Counter& prev = prev_counters_[CounterKey{ref, name_id}];
+
+  uint64_t duration = 0;
+  double value_delta = 0;
+
   if (prev.timestamp != 0) {
-    uint64_t duration = 0;
-    // TODO(taylori): Add handling of events other than cpu freq.
-    if (ref_type == RefType::kCPU_ID) {
-      duration = timestamp - prev.timestamp;
-    }
+    duration = timestamp - prev.timestamp;
+    value_delta = value - prev.value;
+
     context_->storage->mutable_counters()->AddCounter(
-        prev.timestamp, duration, name_id, prev.value,
-        static_cast<int64_t>(ref), RefType::kCPU_ID);
+        prev.timestamp, duration, name_id, prev.value, value_delta,
+        static_cast<int64_t>(ref), ref_type);
   }
 
   prev.timestamp = timestamp;
   prev.value = value;
-  prev.name_id = name_id;
 };
 
 }  // namespace trace_processor
diff --git a/src/trace_processor/sched_tracker.h b/src/trace_processor/sched_tracker.h
index 71037b6..b2c5791 100644
--- a/src/trace_processor/sched_tracker.h
+++ b/src/trace_processor/sched_tracker.h
@@ -52,7 +52,25 @@
   struct Counter {
     uint64_t timestamp = 0;
     double value = 0;
-    StringId name_id = 0;
+  };
+
+  // Used as the key in |prev_counters_| to find the previous counter with the
+  // same ref and name_id.
+  struct CounterKey {
+    uint64_t ref;      // cpu, utid, ...
+    StringId name_id;  // "cpufreq"
+
+    bool operator==(const CounterKey& other) const {
+      return (ref == other.ref && name_id == other.name_id);
+    }
+
+    struct Hasher {
+      size_t operator()(const CounterKey& c) const {
+        size_t const h1(std::hash<uint64_t>{}(c.ref));
+        size_t const h2(std::hash<size_t>{}(c.name_id));
+        return h1 ^ (h2 << 1);
+      }
+    };
   };
 
   // This method is called when a sched switch event is seen in the trace.
@@ -64,7 +82,6 @@
                                uint32_t next_pid);
 
   // This method is called when a cpu freq event is seen in the trace.
-  // In the future it will be called for all counters.
   // TODO(taylori): Move to a more appropriate class or rename class.
   virtual void PushCounter(uint64_t timestamp,
                            double value,
@@ -76,9 +93,9 @@
   // Store the previous sched event to calculate the duration before storing it.
   std::array<SchedSwitchEvent, base::kMaxCpus> last_sched_per_cpu_;
 
-  // Store the previous counter event to calculate the duration before storing
-  // in trace storage.
-  std::array<Counter, base::kMaxCpus> last_counter_per_cpu_;
+  // Store the previous counter event to calculate the duration and value delta
+  // before storing it in trace storage.
+  std::unordered_map<CounterKey, Counter, CounterKey::Hasher> prev_counters_;
 
   // Timestamp of the previous event. Used to discard events arriving out
   // of order.
diff --git a/src/trace_processor/sched_tracker_unittest.cc b/src/trace_processor/sched_tracker_unittest.cc
index 298de15..de20f3b 100644
--- a/src/trace_processor/sched_tracker_unittest.cc
+++ b/src/trace_processor/sched_tracker_unittest.cc
@@ -126,6 +126,33 @@
   ASSERT_EQ(context.storage->counters().values().at(2), 5000);
 }
 
+TEST_F(SchedTrackerTest, MixedEventsValueDelta) {
+  uint32_t cpu = 3;
+  uint64_t timestamp = 100;
+  StringId name_id_cpu = 0;
+  StringId name_id_upid = 0;
+  UniquePid upid = 12;
+  context.sched_tracker->PushCounter(timestamp, 1000, name_id_cpu, cpu,
+                                     RefType::kCPU_ID);
+  context.sched_tracker->PushCounter(timestamp + 1, 0, name_id_upid, upid,
+                                     RefType::kUPID);
+  context.sched_tracker->PushCounter(timestamp + 3, 5000, name_id_cpu, cpu,
+                                     RefType::kCPU_ID);
+  context.sched_tracker->PushCounter(timestamp + 9, 1, name_id_upid, upid,
+                                     RefType::kUPID);
+
+  ASSERT_EQ(context.storage->counters().counter_count(), 2ul);
+  ASSERT_EQ(context.storage->counters().timestamps().at(0), timestamp);
+  ASSERT_EQ(context.storage->counters().durations().at(0), 3);
+  ASSERT_EQ(context.storage->counters().values().at(0), 1000);
+  ASSERT_EQ(context.storage->counters().value_deltas().at(0), 4000);
+
+  ASSERT_EQ(context.storage->counters().timestamps().at(1), timestamp + 1);
+  ASSERT_EQ(context.storage->counters().durations().at(1), 8);
+  ASSERT_EQ(context.storage->counters().values().at(1), 0);
+  ASSERT_EQ(context.storage->counters().value_deltas().at(1), 1);
+}
+
 }  // namespace
 }  // namespace trace_processor
 }  // namespace perfetto
diff --git a/src/trace_processor/trace_storage.h b/src/trace_processor/trace_storage.h
index 5a7e1be..fe2651b 100644
--- a/src/trace_processor/trace_storage.h
+++ b/src/trace_processor/trace_storage.h
@@ -153,12 +153,14 @@
                            uint64_t duration,
                            StringId name_id,
                            double value,
+                           double value_delta,
                            int64_t ref,
                            RefType type) {
       timestamps_.emplace_back(timestamp);
       durations_.emplace_back(duration);
       name_ids_.emplace_back(name_id);
       values_.emplace_back(value);
+      value_deltas_.emplace_back(value_delta);
       refs_.emplace_back(ref);
       types_.emplace_back(type);
     }
@@ -172,6 +174,8 @@
 
     const std::deque<double>& values() const { return values_; }
 
+    const std::deque<double>& value_deltas() const { return value_deltas_; }
+
     const std::deque<int64_t>& refs() const { return refs_; }
 
     const std::deque<RefType>& types() const { return types_; }
@@ -181,6 +185,7 @@
     std::deque<uint64_t> durations_;
     std::deque<StringId> name_ids_;
     std::deque<double> values_;
+    std::deque<double> value_deltas_;
     std::deque<int64_t> refs_;
     std::deque<RefType> types_;
   };