tp: Add TO_REALTIME

Change-Id: I622d4dfd55a448946c48aedcd2f82f0b63577b08
diff --git a/src/trace_processor/importers/common/clock_converter.h b/src/trace_processor/importers/common/clock_converter.h
index a5662b4..5ce504f 100644
--- a/src/trace_processor/importers/common/clock_converter.h
+++ b/src/trace_processor/importers/common/clock_converter.h
@@ -56,6 +56,11 @@
     return TimeToStr(*real_ts);
   }
 
+  // Converts trace time to REAL clock time.
+  base::StatusOr<Timestamp> ToRealtime(Timestamp ts) {
+    return FromTraceTime(kRealClock, ts);
+  }
+
   // Converts trace time to MONO clock time.
   base::StatusOr<Timestamp> ToMonotonic(Timestamp ts) {
     return FromTraceTime(kMonoClock, ts);
diff --git a/src/trace_processor/importers/common/clock_converter_unittest.cc b/src/trace_processor/importers/common/clock_converter_unittest.cc
index f88fd13..bcd4734 100644
--- a/src/trace_processor/importers/common/clock_converter_unittest.cc
+++ b/src/trace_processor/importers/common/clock_converter_unittest.cc
@@ -60,6 +60,17 @@
   EXPECT_EQ(cc_.ToMonotonic(10).value(), 20);
 }
 
+TEST_F(ClockConverterTest, TrivialToRealtime) {
+  tables::ClockSnapshotTable::Row row;
+  row.ts = 10;
+  row.clock_id = kReal;
+  row.clock_value = 20;
+  context_.storage->mutable_clock_snapshot_table()->Insert(row);
+
+  EXPECT_TRUE(cc_.ToRealtime(10).ok());
+  EXPECT_EQ(cc_.ToRealtime(10).value(), 20);
+}
+
 TEST_F(ClockConverterTest, TrivialToAbsTime) {
   tables::ClockSnapshotTable::Row row;
   row.ts = 10;
@@ -107,6 +118,36 @@
   EXPECT_EQ(cc_.ToMonotonic(45).value(), 25);
 }
 
+TEST_F(ClockConverterTest, Realtime) {
+  // We will add 3 snapshots for real time clock, and the last snapshot will be
+  // earlier then the second one.
+  {
+    tables::ClockSnapshotTable::Row rows;
+    rows.ts = 10;
+    rows.clock_id = kReal;
+    rows.clock_value = 0;
+    context_.storage->mutable_clock_snapshot_table()->Insert(rows);
+  }
+  {
+    tables::ClockSnapshotTable::Row rows;
+    rows.ts = 20;
+    rows.clock_id = kReal;
+    rows.clock_value = 10;
+    context_.storage->mutable_clock_snapshot_table()->Insert(rows);
+  }
+  {
+    tables::ClockSnapshotTable::Row rows;
+    rows.ts = 30;
+    rows.clock_id = kReal;
+    rows.clock_value = 5;
+    context_.storage->mutable_clock_snapshot_table()->Insert(rows);
+  }
+
+  EXPECT_EQ(cc_.ToRealtime(15).value(), 5);
+  EXPECT_EQ(cc_.ToRealtime(25).value(), 5);
+  EXPECT_EQ(cc_.ToRealtime(35).value(), 10);
+}
+
 TEST_F(ClockConverterTest, AbsTime) {
   // We will add 3 snapshots for real time clock, and the last snapshot will be
   // earlier then the second one.
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/clock_functions.h b/src/trace_processor/perfetto_sql/intrinsics/functions/clock_functions.h
index 605cea5..a30993d 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/clock_functions.h
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/clock_functions.h
@@ -80,7 +80,7 @@
                           Destructors& destructors);
 };
 
-base::Status ToMonotonic::Run(ClockConverter* tracker,
+base::Status ToMonotonic::Run(ClockConverter* converter,
                               size_t argc,
                               sqlite3_value** argv,
                               SqlValue& out,
@@ -98,7 +98,7 @@
   }
 
   int64_t ts = sqlite3_value_int64(argv[0]);
-  base::StatusOr<int64_t> monotonic = tracker->ToMonotonic(ts);
+  base::StatusOr<int64_t> monotonic = converter->ToMonotonic(ts);
 
   if (!monotonic.ok()) {
     // We are returning an OkStatus, because one bad timestamp shouldn't stop
@@ -110,6 +110,45 @@
   return base::OkStatus();
 }
 
+struct ToRealtime : public SqlFunction {
+  using Context = ClockConverter;
+  static base::Status Run(ClockConverter* tracker,
+                          size_t argc,
+                          sqlite3_value** argv,
+                          SqlValue& out,
+                          Destructors& destructors);
+};
+
+base::Status ToRealtime::Run(ClockConverter* converter,
+                             size_t argc,
+                             sqlite3_value** argv,
+                             SqlValue& out,
+                             Destructors&) {
+  if (argc != 1) {
+    return base::ErrStatus("TO_REALTIME: 1 arg required");
+  }
+
+  // If the timestamp is null, just return null as the result.
+  if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
+    return base::OkStatus();
+  }
+  if (sqlite3_value_type(argv[0]) != SQLITE_INTEGER) {
+    return base::ErrStatus("TO_REALTIME: first argument should be timestamp");
+  }
+
+  int64_t ts = sqlite3_value_int64(argv[0]);
+  base::StatusOr<int64_t> realtime = converter->ToRealtime(ts);
+
+  if (!realtime.ok()) {
+    // We are returning an OkStatus, because one bad timestamp shouldn't stop
+    // the query.
+    return base::OkStatus();
+  }
+
+  out = SqlValue::Long(*realtime);
+  return base::OkStatus();
+}
+
 struct ToTimecode : public SqlFunction {
   static base::Status Run(void*,
                           size_t argc,
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 0eedff4..cc9472b 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -421,6 +421,8 @@
   RegisterFunction<Reverse>(&engine_, "REVERSE", 1);
   RegisterFunction<ToMonotonic>(&engine_, "TO_MONOTONIC", 1,
                                 context_.clock_converter.get());
+  RegisterFunction<ToMonotonic>(&engine_, "TO_REALTIME", 1,
+                                context_.clock_converter.get());
   RegisterFunction<ToTimecode>(&engine_, "TO_TIMECODE", 1);
   RegisterFunction<CreateFunction>(&engine_, "CREATE_FUNCTION", 3, &engine_);
   RegisterFunction<CreateViewFunction>(&engine_, "CREATE_VIEW_FUNCTION", 3,
diff --git a/test/trace_processor/diff_tests/dynamic/tests.py b/test/trace_processor/diff_tests/dynamic/tests.py
index e061ff5..304c53a 100644
--- a/test/trace_processor/diff_tests/dynamic/tests.py
+++ b/test/trace_processor/diff_tests/dynamic/tests.py
@@ -134,6 +134,37 @@
         "[NULL]","[NULL]","[NULL]"
         """))
 
+  # TO_REALTIME function
+  def test_various_clocks_to_realtime(self):
+    return DiffTestBlueprint(
+        trace=Path('various_clocks.textproto'),
+        query="""
+        SELECT
+          TO_REALTIME(15) AS t15,
+          TO_REALTIME(25) AS t25,
+          TO_REALTIME(35) AS t35;
+        """,
+        out=Csv("""
+        "t15","t25","t35"
+        15,15,20
+        """))
+
+  def test_empty_to_realtime(self):
+    return DiffTestBlueprint(
+        trace=TextProto(r"""
+
+        """),
+        query="""
+        SELECT
+          TO_REALTIME(15) AS t15,
+          TO_REALTIME(25) AS t25,
+          TO_REALTIME(35) AS t35;
+        """,
+        out=Csv("""
+        "t15","t25","t35"
+        "[NULL]","[NULL]","[NULL]"
+        """))
+
   # TO_MONOTONIC function
   def test_various_clocks_to_monotonic(self):
     return DiffTestBlueprint(