1 /*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #ifndef SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_CLOCK_FUNCTIONS_H_
18 #define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_CLOCK_FUNCTIONS_H_
19
20 #include <sqlite3.h>
21 #include <unordered_map>
22 #include "perfetto/ext/base/base64.h"
23 #include "protos/perfetto/common/builtin_clock.pbzero.h"
24 #include "src/trace_processor/importers/common/clock_converter.h"
25 #include "src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.h"
26 #include "src/trace_processor/util/status_macros.h"
27
28 namespace perfetto {
29 namespace trace_processor {
30
31 struct AbsTimeStr : public SqlFunction {
32 using Context = ClockConverter;
33 static base::Status Run(ClockConverter* tracker,
34 size_t argc,
35 sqlite3_value** argv,
36 SqlValue& out,
37 Destructors& destructors);
38 };
39
Run(ClockConverter * tracker,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors & destructors)40 base::Status AbsTimeStr::Run(ClockConverter* tracker,
41 size_t argc,
42 sqlite3_value** argv,
43 SqlValue& out,
44 Destructors& destructors) {
45 if (argc != 1) {
46 return base::ErrStatus("ABS_TIME_STR: 1 arg required");
47 }
48
49 // If the timestamp is null, just return null as the result.
50 if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
51 return base::OkStatus();
52 }
53 if (sqlite3_value_type(argv[0]) != SQLITE_INTEGER) {
54 return base::ErrStatus("ABS_TIME_STR: first argument should be timestamp");
55 }
56
57 int64_t ts = sqlite3_value_int64(argv[0]);
58 base::StatusOr<std::string> iso8601 = tracker->ToAbsTime(ts);
59 if (!iso8601.ok()) {
60 // We are returning an OkStatus, because one bad timestamp shouldn't stop
61 // the query.
62 return base::OkStatus();
63 }
64
65 std::unique_ptr<char, base::FreeDeleter> s(
66 static_cast<char*>(malloc(iso8601->size() + 1)));
67 memcpy(s.get(), iso8601->c_str(), iso8601->size() + 1);
68
69 destructors.string_destructor = free;
70 out = SqlValue::String(s.release());
71 return base::OkStatus();
72 }
73
74 struct ToMonotonic : public SqlFunction {
75 using Context = ClockConverter;
76 static base::Status Run(ClockConverter* tracker,
77 size_t argc,
78 sqlite3_value** argv,
79 SqlValue& out,
80 Destructors& destructors);
81 };
82
Run(ClockConverter * converter,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors &)83 base::Status ToMonotonic::Run(ClockConverter* converter,
84 size_t argc,
85 sqlite3_value** argv,
86 SqlValue& out,
87 Destructors&) {
88 if (argc != 1) {
89 return base::ErrStatus("TO_MONOTONIC: 1 arg required");
90 }
91
92 // If the timestamp is null, just return null as the result.
93 if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
94 return base::OkStatus();
95 }
96 if (sqlite3_value_type(argv[0]) != SQLITE_INTEGER) {
97 return base::ErrStatus("TO_MONOTONIC: first argument should be timestamp");
98 }
99
100 int64_t ts = sqlite3_value_int64(argv[0]);
101 base::StatusOr<int64_t> monotonic = converter->ToMonotonic(ts);
102
103 if (!monotonic.ok()) {
104 // We are returning an OkStatus, because one bad timestamp shouldn't stop
105 // the query.
106 return base::OkStatus();
107 }
108
109 out = SqlValue::Long(*monotonic);
110 return base::OkStatus();
111 }
112
113 struct ToRealtime : public SqlFunction {
114 using Context = ClockConverter;
115 static base::Status Run(ClockConverter* tracker,
116 size_t argc,
117 sqlite3_value** argv,
118 SqlValue& out,
119 Destructors& destructors);
120 };
121
Run(ClockConverter * converter,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors &)122 base::Status ToRealtime::Run(ClockConverter* converter,
123 size_t argc,
124 sqlite3_value** argv,
125 SqlValue& out,
126 Destructors&) {
127 if (argc != 1) {
128 return base::ErrStatus("TO_REALTIME: 1 arg required");
129 }
130
131 // If the timestamp is null, just return null as the result.
132 if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
133 return base::OkStatus();
134 }
135 if (sqlite3_value_type(argv[0]) != SQLITE_INTEGER) {
136 return base::ErrStatus("TO_REALTIME: first argument should be timestamp");
137 }
138
139 int64_t ts = sqlite3_value_int64(argv[0]);
140 base::StatusOr<int64_t> realtime = converter->ToRealtime(ts);
141
142 if (!realtime.ok()) {
143 // We are returning an OkStatus, because one bad timestamp shouldn't stop
144 // the query.
145 return base::OkStatus();
146 }
147
148 out = SqlValue::Long(*realtime);
149 return base::OkStatus();
150 }
151
152 struct ToTimecode : public SqlFunction {
153 static base::Status Run(void*,
154 size_t argc,
155 sqlite3_value** argv,
156 SqlValue& out,
157 Destructors& destructors);
158 };
159
Run(void *,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors & destructors)160 base::Status ToTimecode::Run(void*,
161 size_t argc,
162 sqlite3_value** argv,
163 SqlValue& out,
164 Destructors& destructors) {
165 if (argc != 1) {
166 return base::ErrStatus("TO_TIMECODE: 1 arg required");
167 }
168
169 // If the timestamp is null, just return null as the result.
170 if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
171 return base::OkStatus();
172 }
173 if (sqlite3_value_type(argv[0]) != SQLITE_INTEGER) {
174 return base::ErrStatus("TO_TIMECODE: first argument should be timestamp");
175 }
176
177 int64_t ns = sqlite3_value_int64(argv[0]);
178
179 int64_t us = ns / 1000;
180 ns = ns % 1000;
181
182 int64_t ms = us / 1000;
183 us = us % 1000;
184
185 int64_t ss = ms / 1000;
186 ms = ms % 1000;
187
188 int64_t mm = ss / 60;
189 ss = ss % 60;
190
191 int64_t hh = mm / 60;
192 mm = mm % 60;
193
194 base::StackString<64> buf("%02" PRId64 ":%02" PRId64 ":%02" PRId64
195 " %03" PRId64 " %03" PRId64 " %03" PRId64,
196 hh, mm, ss, ms, us, ns);
197 std::unique_ptr<char, base::FreeDeleter> s(
198 static_cast<char*>(malloc(buf.len() + 1)));
199 memcpy(s.get(), buf.c_str(), buf.len() + 1);
200
201 destructors.string_destructor = free;
202 out = SqlValue::String(s.release());
203
204 return base::OkStatus();
205 }
206
207 } // namespace trace_processor
208 } // namespace perfetto
209
210 #endif // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_CLOCK_FUNCTIONS_H_
211