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(