Merge "Trace Redaction - Refine process name tests" into main
diff --git a/Android.bp b/Android.bp
index 1a7fd1d..d5da1dd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -15548,12 +15548,6 @@
defaults: [
"perfetto_defaults",
],
- required: [
- "libperfetto_android_internal",
- "mm_events",
- "traced_perf",
- "trigger_perfetto",
- ],
target: {
android: {
shared_libs: [
@@ -15921,3 +15915,13 @@
sub_dir: "perfetto",
src: "persistent_cfg.pbtxt",
}
+
+phony {
+ name: "perfetto-extras",
+ required: [
+ "libperfetto_android_internal",
+ "mm_events",
+ "traced_perf",
+ "trigger_perfetto",
+ ],
+}
diff --git a/Android.bp.extras b/Android.bp.extras
index 2ce8e95..3aab5af 100644
--- a/Android.bp.extras
+++ b/Android.bp.extras
@@ -205,3 +205,13 @@
sub_dir: "perfetto",
src: "persistent_cfg.pbtxt",
}
+
+phony {
+ name: "perfetto-extras",
+ required: [
+ "libperfetto_android_internal",
+ "mm_events",
+ "traced_perf",
+ "trigger_perfetto",
+ ],
+}
diff --git a/BUILD b/BUILD
index d0deed7..8eedd8d 100644
--- a/BUILD
+++ b/BUILD
@@ -2658,12 +2658,14 @@
"src/trace_processor/sqlite/sql_stats_table.h",
"src/trace_processor/sqlite/sqlite_engine.cc",
"src/trace_processor/sqlite/sqlite_engine.h",
+ "src/trace_processor/sqlite/sqlite_result.h",
"src/trace_processor/sqlite/sqlite_table.cc",
"src/trace_processor/sqlite/sqlite_table.h",
"src/trace_processor/sqlite/sqlite_tokenizer.cc",
"src/trace_processor/sqlite/sqlite_tokenizer.h",
"src/trace_processor/sqlite/sqlite_utils.cc",
"src/trace_processor/sqlite/sqlite_utils.h",
+ "src/trace_processor/sqlite/sqlite_window_function.h",
"src/trace_processor/sqlite/stats_table.cc",
"src/trace_processor/sqlite/stats_table.h",
],
diff --git a/src/trace_processor/BUILD.gn b/src/trace_processor/BUILD.gn
index e37c9c6..84c09ce 100644
--- a/src/trace_processor/BUILD.gn
+++ b/src/trace_processor/BUILD.gn
@@ -156,6 +156,7 @@
"../../protos/perfetto/common:zero",
"../../protos/perfetto/trace:zero",
"../../protos/perfetto/trace/perfetto:zero",
+ "../../protos/perfetto/trace_processor:zero",
"../base",
"../protozero",
"db",
diff --git a/src/trace_processor/iterator_impl.h b/src/trace_processor/iterator_impl.h
index 89f300b..47e2e5f 100644
--- a/src/trace_processor/iterator_impl.h
+++ b/src/trace_processor/iterator_impl.h
@@ -18,22 +18,18 @@
#define SRC_TRACE_PROCESSOR_ITERATOR_IMPL_H_
#include <sqlite3.h>
+#include <cstddef>
+#include <cstdint>
+#include <string>
-#include <memory>
-#include <optional>
-#include <vector>
-
-#include "perfetto/base/build_config.h"
-#include "perfetto/base/export.h"
+#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
+#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/status_or.h"
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/iterator.h"
-#include "perfetto/trace_processor/status.h"
#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
-#include "src/trace_processor/sqlite/scoped_db.h"
#include "src/trace_processor/sqlite/sqlite_engine.h"
-#include "src/trace_processor/sqlite/sqlite_utils.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/metrics/metrics.cc b/src/trace_processor/metrics/metrics.cc
index 639e252..d351e0a 100644
--- a/src/trace_processor/metrics/metrics.cc
+++ b/src/trace_processor/metrics/metrics.cc
@@ -465,8 +465,8 @@
if (repeated_field_type_ && repeated_field_type_ != type) {
return base::ErrStatus(
"Inconsistent type in RepeatedField: was %s but now seen value %s",
- sqlite_utils::SqliteTypeToFriendlyString(*repeated_field_type_),
- sqlite_utils::SqliteTypeToFriendlyString(type));
+ sqlite::utils::SqliteTypeToFriendlyString(*repeated_field_type_),
+ sqlite::utils::SqliteTypeToFriendlyString(type));
}
repeated_field_type_ = type;
return base::OkStatus();
@@ -514,13 +514,13 @@
return base::OkStatus();
}
- out = sqlite_utils::SqliteValueToSqlValue(argv[0]);
+ out = sqlite::utils::SqliteValueToSqlValue(argv[0]);
return base::OkStatus();
}
void RepeatedFieldStep(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
if (argc != 1) {
- sqlite3_result_error(ctx, "RepeatedField: only expected one arg", -1);
+ sqlite::result::Error(ctx, "RepeatedField: only expected one arg");
return;
}
@@ -538,11 +538,11 @@
*builder_ptr_ptr = new RepeatedFieldBuilder();
}
- auto value = sqlite_utils::SqliteValueToSqlValue(argv[0]);
+ auto value = sqlite::utils::SqliteValueToSqlValue(argv[0]);
RepeatedFieldBuilder* builder = *builder_ptr_ptr;
auto status = builder->AddSqlValue(value);
if (!status.ok()) {
- sqlite3_result_error(ctx, status.c_message(), -1);
+ sqlite::result::Error(ctx, status.c_message());
}
}
@@ -554,7 +554,7 @@
// If Step has never been called, |builder_ptr_ptr| will be null.
if (builder_ptr_ptr == nullptr) {
- sqlite3_result_null(ctx);
+ sqlite::result::Null(ctx);
return;
}
@@ -563,14 +563,15 @@
std::unique_ptr<RepeatedFieldBuilder> builder(*builder_ptr_ptr);
std::vector<uint8_t> raw = builder->SerializeToProtoBuilderResult();
if (raw.empty()) {
- sqlite3_result_null(ctx);
+ sqlite::result::Null(ctx);
return;
}
std::unique_ptr<uint8_t[], base::FreeDeleter> data(
static_cast<uint8_t*>(malloc(raw.size())));
memcpy(data.get(), raw.data(), raw.size());
- sqlite3_result_blob(ctx, data.release(), static_cast<int>(raw.size()), free);
+ return sqlite::result::RawBytes(ctx, data.release(),
+ static_cast<int>(raw.size()), free);
}
// SQLite function implementation used to build a proto directly in SQL. The
@@ -600,7 +601,7 @@
const char* key =
reinterpret_cast<const char*>(sqlite3_value_text(argv[i]));
- SqlValue value = sqlite_utils::SqliteValueToSqlValue(argv[i + 1]);
+ SqlValue value = sqlite::utils::SqliteValueToSqlValue(argv[i + 1]);
RETURN_IF_ERROR(builder.AppendSqlValue(key, value));
}
@@ -610,7 +611,7 @@
if (raw.empty()) {
// Passing nullptr to SQLite feels dangerous so just pass an empty string
// and zero as the size so we don't deref nullptr accidentially somewhere.
- destructors.bytes_destructor = sqlite_utils::kSqliteStatic;
+ destructors.bytes_destructor = sqlite::utils::kSqliteStatic;
out = SqlValue::Bytes("", 0);
return base::OkStatus();
}
@@ -647,10 +648,10 @@
return base::ErrStatus("RUN_METRIC: all keys must be strings");
}
- std::optional<std::string> key_str = sqlite_utils::SqlValueToString(
- sqlite_utils::SqliteValueToSqlValue(argv[i]));
- std::optional<std::string> value_str = sqlite_utils::SqlValueToString(
- sqlite_utils::SqliteValueToSqlValue(argv[i + 1]));
+ std::optional<std::string> key_str = sqlite::utils::SqlValueToString(
+ sqlite::utils::SqliteValueToSqlValue(argv[i]));
+ std::optional<std::string> value_str = sqlite::utils::SqlValueToString(
+ sqlite::utils::SqliteValueToSqlValue(argv[i + 1]));
if (!value_str) {
return base::ErrStatus(
@@ -682,8 +683,8 @@
"arguments");
}
- SqlValue proto = sqlite_utils::SqliteValueToSqlValue(argv[0]);
- SqlValue message_type = sqlite_utils::SqliteValueToSqlValue(argv[1]);
+ SqlValue proto = sqlite::utils::SqliteValueToSqlValue(argv[0]);
+ SqlValue message_type = sqlite::utils::SqliteValueToSqlValue(argv[1]);
if (proto.type != SqlValue::Type::kBytes) {
return base::ErrStatus("UNWRAP_METRIC_PROTO: proto is not a blob");
@@ -696,7 +697,7 @@
const uint8_t* ptr = static_cast<const uint8_t*>(proto.AsBytes());
size_t size = proto.bytes_count;
if (size == 0) {
- destructors.bytes_destructor = sqlite_utils::kSqliteStatic;
+ destructors.bytes_destructor = sqlite::utils::kSqliteStatic;
out = SqlValue::Bytes("", 0);
return base::OkStatus();
}
@@ -766,7 +767,7 @@
sql_metric.output_table_name.value().c_str());
}
- SqlValue col = sqlite_utils::SqliteValueToSqlValue(
+ SqlValue col = sqlite::utils::SqliteValueToSqlValue(
sqlite3_column_value(it->stmt.sqlite_stmt(), 0));
if (col.type != SqlValue::kBytes) {
return base::ErrStatus("Output table %s column has invalid type",
diff --git a/src/trace_processor/perfetto_sql/engine/created_function.cc b/src/trace_processor/perfetto_sql/engine/created_function.cc
index 7df16a8..be4f956 100644
--- a/src/trace_processor/perfetto_sql/engine/created_function.cc
+++ b/src/trace_processor/perfetto_sql/engine/created_function.cc
@@ -75,7 +75,7 @@
}
SqlValue result =
- sqlite_utils::SqliteValueToSqlValue(sqlite3_column_value(stmt, 0));
+ sqlite::utils::SqliteValueToSqlValue(sqlite3_column_value(stmt, 0));
// If we return a bytes type but have a null pointer, SQLite will convert this
// to an SQL null. However, for proto build functions, we actively want to
@@ -205,7 +205,7 @@
if (argc != 1) {
return std::nullopt;
}
- SqlValue arg = sqlite_utils::SqliteValueToSqlValue(argv[0]);
+ SqlValue arg = sqlite::utils::SqliteValueToSqlValue(argv[0]);
if (arg.type != SqlValue::Type::kLong) {
return std::nullopt;
}
@@ -611,7 +611,7 @@
for (size_t i = 0; i < argc; ++i) {
sqlite3_value* arg = argv[i];
sql_argument::Type type = state->prototype().arguments[i].type();
- base::Status status = sqlite_utils::TypeCheckSqliteValue(
+ base::Status status = sqlite::utils::TypeCheckSqliteValue(
arg, sql_argument::TypeToSqlValueType(type),
sql_argument::TypeToHumanFriendlyString(type));
if (!status.ok()) {
diff --git a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
index 69e6b58..f11d04e 100644
--- a/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
+++ b/src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h
@@ -41,7 +41,9 @@
#include "src/trace_processor/sqlite/query_cache.h"
#include "src/trace_processor/sqlite/sql_source.h"
#include "src/trace_processor/sqlite/sqlite_engine.h"
+#include "src/trace_processor/sqlite/sqlite_result.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/sqlite/sqlite_window_function.h"
#include "src/trace_processor/util/sql_argument.h"
#include "src/trace_processor/util/sql_modules.h"
@@ -86,7 +88,7 @@
//
// The format of the function is given by the |SqlFunction|.
//
- // |name|: name of the function in SQL
+ // |name|: name of the function in SQL.
// |argc|: number of arguments for this function. This can be -1 if
// the number of arguments is variable.
// |ctx|: context object for the function (see SqlFunction::Run);
@@ -113,6 +115,24 @@
std::unique_ptr<typename Function::Context> ctx,
bool deterministic = true);
+ // Registers a trace processor C++ window function to be runnable from SQL.
+ //
+ // The format of the function is given by the |SqliteWindowFunction|.
+ //
+ // |name|: name of the function in SQL.
+ // |argc|: number of arguments for this function. This can be -1 if
+ // the number of arguments is variable.
+ // |ctx|: context object for the function (see SqlFunction::Run);
+ // this object *must* outlive the function so should likely be
+ // either static or scoped to the lifetime of TraceProcessor.
+ // |determistic|: whether this function has deterministic output given the
+ // same set of arguments.
+ template <typename Function = SqliteWindowFunction>
+ base::Status RegisterSqliteWindowFunction(const char* name,
+ int argc,
+ typename Function::Context* ctx,
+ bool deterministic = true);
+
// Registers a function with the prototype |prototype| which returns a value
// of |return_type| and is implemented by executing the SQL statement |sql|.
base::Status RegisterRuntimeFunction(bool replace,
@@ -172,7 +192,7 @@
// The missing objects from the above query are static functions, runtime
// functions and macros. Add those in now.
return query_count + static_function_count_ + runtime_function_count_ +
- macros_.size();
+ static_window_function_count_ + macros_.size();
}
// Find RuntimeTable registered with engine with provided name.
@@ -233,6 +253,7 @@
uint64_t static_function_count_ = 0;
uint64_t runtime_function_count_ = 0;
+ uint64_t static_window_function_count_ = 0;
base::FlatHashMap<std::string, std::unique_ptr<RuntimeTableFunction::State>>
runtime_table_fn_states_;
@@ -267,13 +288,13 @@
base::Status status =
Function::Run(ud, static_cast<size_t>(argc), argv, value, destructors);
if (!status.ok()) {
- sqlite3_result_error(ctx, status.c_message(), -1);
+ sqlite::result::Error(ctx, status.c_message());
return;
}
if (Function::kVoidReturn) {
if (!value.is_null()) {
- sqlite3_result_error(ctx, "void SQL function returned value", -1);
+ sqlite::result::Error(ctx, "void SQL function returned value");
return;
}
@@ -283,15 +304,15 @@
// if we don't actually read it - just set it to a pointer to an empty
// string for this reason.
static char kVoidValue[] = "";
- sqlite3_result_pointer(ctx, kVoidValue, "VOID", nullptr);
+ sqlite::result::StaticPointer(ctx, kVoidValue, "VOID");
} else {
- sqlite_utils::ReportSqlValue(ctx, value, destructors.string_destructor,
- destructors.bytes_destructor);
+ sqlite::utils::ReportSqlValue(ctx, value, destructors.string_destructor,
+ destructors.bytes_destructor);
}
status = Function::VerifyPostConditions(ud);
if (!status.ok()) {
- sqlite3_result_error(ctx, status.c_message(), -1);
+ sqlite::result::Error(ctx, status.c_message());
return;
}
}
@@ -315,6 +336,18 @@
}
template <typename Function>
+base::Status PerfettoSqlEngine::RegisterSqliteWindowFunction(
+ const char* name,
+ int argc,
+ typename Function::Context* ctx,
+ bool deterministic) {
+ static_window_function_count_++;
+ return engine_->RegisterWindowFunction(
+ name, argc, Function::Step, Function::Inverse, Function::Value,
+ Function::Final, ctx, nullptr, deterministic);
+}
+
+template <typename Function>
base::Status PerfettoSqlEngine::RegisterStaticFunction(
const char* name,
int argc,
diff --git a/src/trace_processor/perfetto_sql/engine/runtime_table_function.cc b/src/trace_processor/perfetto_sql/engine/runtime_table_function.cc
index 247d79b..1eaab01 100644
--- a/src/trace_processor/perfetto_sql/engine/runtime_table_function.cc
+++ b/src/trace_processor/perfetto_sql/engine/runtime_table_function.cc
@@ -20,6 +20,7 @@
#include <utility>
#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/sqlite/sqlite_result.h"
#include "src/trace_processor/util/status_macros.h"
namespace perfetto {
@@ -148,13 +149,13 @@
// We only support equality constraints as we're expecting "input arguments"
// to our "function".
- if (!sqlite_utils::IsOpEq(cs.op)) {
+ if (!sqlite::utils::IsOpEq(cs.op)) {
return base::ErrStatus("%s: non-equality constraint passed",
state_->prototype.function_name.c_str());
}
const auto& arg = state_->prototype.arguments[col_to_arg_idx(cs.column)];
- base::Status status = sqlite_utils::TypeCheckSqliteValue(
+ base::Status status = sqlite::utils::TypeCheckSqliteValue(
argv[i], sql_argument::TypeToSqlValueType(arg.type()),
sql_argument::TypeToHumanFriendlyString(arg.type()));
if (!status.ok()) {
@@ -229,16 +230,16 @@
base::Status RuntimeTableFunction::Cursor::Column(sqlite3_context* ctx, int i) {
size_t idx = static_cast<size_t>(i);
if (state_->IsReturnValueColumn(idx)) {
- sqlite3_result_value(ctx, sqlite3_column_value(stmt_->sqlite_stmt(), i));
+ sqlite::result::Value(ctx, sqlite3_column_value(stmt_->sqlite_stmt(), i));
} else if (state_->IsArgumentColumn(idx)) {
// TODO(lalitm): it may be more appropriate to keep a note of the arguments
// which we passed in and return them here. Not doing this to because it
// doesn't seem necessary for any useful thing but something which may need
// to be changed in the future.
- sqlite3_result_null(ctx);
+ sqlite::result::Null(ctx);
} else {
PERFETTO_DCHECK(state_->IsPrimaryKeyColumn(idx));
- sqlite3_result_int(ctx, next_call_count_);
+ sqlite::result::Long(ctx, next_call_count_);
}
return base::OkStatus();
}
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/base64.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/base64.cc
index 9c16baf..cc0eddc 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/base64.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/base64.cc
@@ -39,7 +39,7 @@
return base::ErrStatus("BASE64: expected one arg but got %zu", argc);
}
- auto in = sqlite_utils::SqliteValueToSqlValue(argv[0]);
+ auto in = sqlite::utils::SqliteValueToSqlValue(argv[0]);
const char* src = nullptr;
size_t src_size = 0;
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/create_function.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/create_function.cc
index 18394d7..a7fc1d4 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/create_function.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/create_function.cc
@@ -38,7 +38,7 @@
sqlite3_value** argv,
SqlValue&,
Destructors&) {
- RETURN_IF_ERROR(sqlite_utils::CheckArgCount("CREATE_FUNCTION", argc, 3u));
+ RETURN_IF_ERROR(sqlite::utils::CheckArgCount("CREATE_FUNCTION", argc, 3u));
sqlite3_value* prototype_value = argv[0];
sqlite3_value* return_type_value = argv[1];
@@ -48,7 +48,7 @@
{
auto type_check = [prototype_value](sqlite3_value* value,
SqlValue::Type type, const char* desc) {
- base::Status status = sqlite_utils::TypeCheckSqliteValue(value, type);
+ base::Status status = sqlite::utils::TypeCheckSqliteValue(value, type);
if (!status.ok()) {
return base::ErrStatus("CREATE_FUNCTION[prototype=%s]: %s %s",
sqlite3_value_text(prototype_value), desc,
@@ -85,9 +85,10 @@
sqlite3_value** argv,
SqlValue&,
Destructors&) {
- RETURN_IF_ERROR(sqlite_utils::CheckArgCount("EXPERIMENTAL_MEMOIZE", argc, 1));
+ RETURN_IF_ERROR(
+ sqlite::utils::CheckArgCount("EXPERIMENTAL_MEMOIZE", argc, 1));
base::StatusOr<std::string> function_name =
- sqlite_utils::ExtractStringArg("MEMOIZE", "function_name", argv[0]);
+ sqlite::utils::ExtractStringArg("MEMOIZE", "function_name", argv[0]);
RETURN_IF_ERROR(function_name.status());
return engine->EnableSqlFunctionMemoization(*function_name);
}
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/create_view_function.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/create_view_function.cc
index 1a19bd4..44782e7 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/create_view_function.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/create_view_function.cc
@@ -54,7 +54,7 @@
{
auto type_check = [prototype_value](sqlite3_value* value,
SqlValue::Type type, const char* desc) {
- base::Status status = sqlite_utils::TypeCheckSqliteValue(value, type);
+ base::Status status = sqlite::utils::TypeCheckSqliteValue(value, type);
if (!status.ok()) {
return base::ErrStatus("CREATE_VIEW_FUNCTION[prototype=%s]: %s %s",
sqlite3_value_text(prototype_value), desc,
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/import.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/import.cc
index 30d363e..a660723 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/import.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/import.cc
@@ -48,8 +48,8 @@
// Type check
{
- base::Status status =
- sqlite_utils::TypeCheckSqliteValue(import_val, SqlValue::Type::kString);
+ base::Status status = sqlite::utils::TypeCheckSqliteValue(
+ import_val, SqlValue::Type::kString);
if (!status.ok()) {
return base::ErrStatus("IMPORT(%s): %s", sqlite3_value_text(import_val),
status.c_message());
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.cc
index cc5cc8a..70b3bce 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.cc
@@ -14,11 +14,18 @@
#include "src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.h"
+#include <cstddef>
+#include <cstdint>
#include <queue>
#include <vector>
+#include "perfetto/base/logging.h"
+#include "perfetto/base/status.h"
#include "perfetto/ext/base/status_or.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/sqlite/sqlite_result.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/sqlite/sqlite_window_function.h"
#include "src/trace_processor/util/status_macros.h"
namespace perfetto::trace_processor {
@@ -118,7 +125,7 @@
base::StatusOr<SlicePacker*> GetOrCreateAggregationContext(
sqlite3_context* ctx) {
- SlicePacker** packer = static_cast<SlicePacker**>(
+ auto** packer = static_cast<SlicePacker**>(
sqlite3_aggregate_context(ctx, sizeof(SlicePacker*)));
if (!packer) {
return base::ErrStatus("Failed to allocate aggregate context");
@@ -130,74 +137,68 @@
return *packer;
}
-base::Status Step(sqlite3_context* ctx, size_t argc, sqlite3_value** argv) {
+base::Status StepStatus(sqlite3_context* ctx,
+ size_t argc,
+ sqlite3_value** argv) {
base::StatusOr<SlicePacker*> slice_packer =
GetOrCreateAggregationContext(ctx);
RETURN_IF_ERROR(slice_packer.status());
base::StatusOr<SqlValue> ts =
- sqlite_utils::ExtractArgument(argc, argv, "ts", 0, SqlValue::kLong);
+ sqlite::utils::ExtractArgument(argc, argv, "ts", 0, SqlValue::kLong);
RETURN_IF_ERROR(ts.status());
base::StatusOr<SqlValue> dur =
- sqlite_utils::ExtractArgument(argc, argv, "dur", 1, SqlValue::kLong);
+ sqlite::utils::ExtractArgument(argc, argv, "dur", 1, SqlValue::kLong);
RETURN_IF_ERROR(dur.status());
return slice_packer.value()->AddSlice(ts->AsLong(), dur.value().AsLong());
}
-void StepWrapper(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
- PERFETTO_CHECK(argc >= 0);
+struct InternalLayout : public SqliteWindowFunction {
+ static void Step(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
+ PERFETTO_CHECK(argc >= 0);
- base::Status status = Step(ctx, static_cast<size_t>(argc), argv);
- if (!status.ok()) {
- sqlite_utils::SetSqliteError(ctx, kFunctionName, status);
- return;
+ base::Status status = StepStatus(ctx, static_cast<size_t>(argc), argv);
+ if (!status.ok()) {
+ return sqlite::utils::SetError(ctx, kFunctionName, status);
+ }
}
-}
-void FinalWrapper(sqlite3_context* ctx) {
- SlicePacker** slice_packer = static_cast<SlicePacker**>(
- sqlite3_aggregate_context(ctx, sizeof(SlicePacker*)));
- if (!slice_packer || !*slice_packer) {
- return;
- }
- sqlite3_result_int64(ctx,
- static_cast<int64_t>((*slice_packer)->GetLastDepth()));
- delete *slice_packer;
-}
-
-void ValueWrapper(sqlite3_context* ctx) {
- base::StatusOr<SlicePacker*> slice_packer =
- GetOrCreateAggregationContext(ctx);
- if (!slice_packer.ok()) {
- sqlite_utils::SetSqliteError(ctx, kFunctionName, slice_packer.status());
- return;
- }
- sqlite3_result_int64(
- ctx, static_cast<int64_t>(slice_packer.value()->GetLastDepth()));
-}
-
-void InverseWrapper(sqlite3_context* ctx, int, sqlite3_value**) {
- sqlite_utils::SetSqliteError(ctx, kFunctionName, base::ErrStatus(R"(
+ static void Inverse(sqlite3_context* ctx, int, sqlite3_value**) {
+ sqlite::utils::SetError(ctx, kFunctionName, base::ErrStatus(R"(
The inverse step is not supported: the window clause should be
"BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW".
)"));
-}
+ }
+
+ static void Value(sqlite3_context* ctx) {
+ base::StatusOr<SlicePacker*> slice_packer =
+ GetOrCreateAggregationContext(ctx);
+ if (!slice_packer.ok()) {
+ return sqlite::utils::SetError(ctx, kFunctionName, slice_packer.status());
+ }
+ return sqlite::result::Long(
+ ctx, static_cast<int64_t>(slice_packer.value()->GetLastDepth()));
+ }
+
+ static void Final(sqlite3_context* ctx) {
+ auto** slice_packer = static_cast<SlicePacker**>(
+ sqlite3_aggregate_context(ctx, sizeof(SlicePacker*)));
+ if (!slice_packer || !*slice_packer) {
+ return;
+ }
+ sqlite::result::Long(ctx,
+ static_cast<int64_t>((*slice_packer)->GetLastDepth()));
+ delete *slice_packer;
+ }
+};
} // namespace
-base::Status LayoutFunctions::Register(sqlite3* db,
- TraceProcessorContext* context) {
- int flags = SQLITE_UTF8 | SQLITE_DETERMINISTIC;
- int ret = sqlite3_create_window_function(
- db, kFunctionName, 2, flags, context, StepWrapper, FinalWrapper,
- ValueWrapper, InverseWrapper, nullptr);
- if (ret != SQLITE_OK) {
- return base::ErrStatus("Unable to register function with name %s",
- kFunctionName);
- }
- return base::OkStatus();
+base::Status RegisterLayoutFunctions(PerfettoSqlEngine& engine) {
+ return engine.RegisterSqliteWindowFunction<InternalLayout>(kFunctionName, 2,
+ nullptr);
}
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.h b/src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.h
index 8d3543c..3b1dc4c 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.h
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.h
@@ -18,6 +18,7 @@
#include <sqlite3.h>
#include "perfetto/base/status.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
namespace perfetto::trace_processor {
@@ -26,14 +27,12 @@
// Implements INTERNAL_LAYOUT(ts, dur) window aggregate function.
// This function takes a set of slices (ordered by ts) and computes depths
// allowing them to be displayed on a single track in a non-overlapping manner,
-// while trying to minimising total height.
+// while trying to minimise the total height.
//
// TODO(altimin): this should support grouping sets of sets of slices (aka
// "tracks") by passing 'track_id' parameter. The complication is that we will
// need to know the max depth for each "track", so it's punted for now.
-struct LayoutFunctions {
- static base::Status Register(sqlite3* db, TraceProcessorContext* context);
-};
+base::Status RegisterLayoutFunctions(PerfettoSqlEngine& engine);
} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc
index c3126e0..d02eaeb 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc
@@ -21,6 +21,7 @@
#include <cstddef>
#include <cstdint>
#include <limits>
+#include <memory>
#include <string>
#include <utility>
#include <vector>
@@ -28,6 +29,7 @@
#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
#include "perfetto/ext/base/status_or.h"
+#include "perfetto/ext/base/utils.h"
#include "perfetto/protozero/packed_repeated_fields.h"
#include "perfetto/trace_processor/basic_types.h"
#include "perfetto/trace_processor/status.h"
@@ -41,8 +43,7 @@
// should cache this somewhere maybe even have a helper table that stores all
// this data.
-namespace perfetto {
-namespace trace_processor {
+namespace perfetto::trace_processor {
namespace {
using protos::pbzero::Stack;
@@ -69,8 +70,8 @@
base::Status Step(size_t argc, sqlite3_value** argv) {
RETURN_IF_ERROR(UpdateSampleValue(argc, argv));
- base::StatusOr<SqlValue> value =
- sqlite_utils::ExtractArgument(argc, argv, "stack", 0, SqlValue::kBytes);
+ base::StatusOr<SqlValue> value = sqlite::utils::ExtractArgument(
+ argc, argv, "stack", 0, SqlValue::kBytes);
if (!value.ok()) {
return value.status();
}
@@ -78,7 +79,7 @@
Stack::Decoder stack(static_cast<const uint8_t*>(value->bytes_value),
value->bytes_count);
if (stack.bytes_left() != 0) {
- return sqlite_utils::ToInvalidArgumentError(
+ return sqlite::utils::ToInvalidArgumentError(
"stack", 0, base::ErrStatus("failed to deserialize Stack proto"));
}
if (!builder_.AddSample(stack, sample_values_)) {
@@ -94,8 +95,8 @@
std::unique_ptr<uint8_t[], base::FreeDeleter> data(
static_cast<uint8_t*>(malloc(profile_proto.size())));
memcpy(data.get(), profile_proto.data(), profile_proto.size());
- sqlite3_result_blob(ctx, data.release(),
- static_cast<int>(profile_proto.size()), free);
+ return sqlite::result::RawBytes(
+ ctx, data.release(), static_cast<int>(profile_proto.size()), free);
}
private:
@@ -109,13 +110,13 @@
}
for (size_t i = 1; i < argc; i += 3) {
- base::StatusOr<SqlValue> type = sqlite_utils::ExtractArgument(
+ base::StatusOr<SqlValue> type = sqlite::utils::ExtractArgument(
argc, argv, "sample_type", i, SqlValue::kString);
if (!type.ok()) {
return type.status();
}
- base::StatusOr<SqlValue> units = sqlite_utils::ExtractArgument(
+ base::StatusOr<SqlValue> units = sqlite::utils::ExtractArgument(
argc, argv, "sample_units", i + 1, SqlValue::kString);
if (!units.ok()) {
return units.status();
@@ -140,7 +141,7 @@
PERFETTO_CHECK(argc == 1 + (sample_values_.size() * 3));
for (size_t i = 0; i < sample_values_.size(); ++i) {
- base::StatusOr<SqlValue> value = sqlite_utils::ExtractArgument(
+ base::StatusOr<SqlValue> value = sqlite::utils::ExtractArgument(
argc, argv, "sample_value", 3 + i * 3, SqlValue::kLong);
if (!value.ok()) {
return value.status();
@@ -155,17 +156,15 @@
std::vector<int64_t> sample_values_;
};
-static base::Status Step(sqlite3_context* ctx,
- size_t argc,
- sqlite3_value** argv) {
- AggregateContext** agg_context_ptr = static_cast<AggregateContext**>(
+base::Status Step(sqlite3_context* ctx, size_t argc, sqlite3_value** argv) {
+ auto** agg_context_ptr = static_cast<AggregateContext**>(
sqlite3_aggregate_context(ctx, sizeof(AggregateContext*)));
if (!agg_context_ptr) {
return base::ErrStatus("Failed to allocate aggregate context");
}
if (!*agg_context_ptr) {
- TraceProcessorContext* tp_context =
+ auto* tp_context =
static_cast<TraceProcessorContext*>(sqlite3_user_data(ctx));
base::StatusOr<std::unique_ptr<AggregateContext>> agg_context =
AggregateContext::Create(tp_context, argc, argv);
@@ -179,18 +178,18 @@
return (*agg_context_ptr)->Step(argc, argv);
}
-static void StepWrapper(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
+void StepWrapper(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
PERFETTO_CHECK(argc >= 0);
base::Status status = Step(ctx, static_cast<size_t>(argc), argv);
if (!status.ok()) {
- sqlite_utils::SetSqliteError(ctx, kFunctionName, status);
+ sqlite::utils::SetError(ctx, kFunctionName, status);
}
}
-static void FinalWrapper(sqlite3_context* ctx) {
- AggregateContext** agg_context_ptr =
+void FinalWrapper(sqlite3_context* ctx) {
+ auto** agg_context_ptr =
static_cast<AggregateContext**>(sqlite3_aggregate_context(ctx, 0));
if (!agg_context_ptr) {
@@ -217,5 +216,4 @@
return base::OkStatus();
}
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.cc
index 04a9996..9553947 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.cc
@@ -16,8 +16,9 @@
#include "src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.h"
-namespace perfetto {
-namespace trace_processor {
+#include "perfetto/base/status.h"
+
+namespace perfetto::trace_processor {
base::Status SqlFunction::VerifyPostConditions(Context*) {
return base::OkStatus();
@@ -25,5 +26,4 @@
void SqlFunction::Cleanup(Context*) {}
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc
index 3cd9325..f504b2aa 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc
@@ -32,27 +32,27 @@
sqlite3_value** argv) {
PERFETTO_DCHECK(argc == 3);
if (sqlite3_value_type(argv[1]) != SQLITE_TEXT) {
- sqlite3_result_error(context, kDelimiterError, -1);
+ sqlite::result::Error(context, kDelimiterError);
return;
}
const char* delimiter =
reinterpret_cast<const char*>(sqlite3_value_text(argv[1]));
const size_t delimiter_len = strlen(delimiter);
if (delimiter_len == 0) {
- sqlite3_result_error(context, kDelimiterError, -1);
+ sqlite::result::Error(context, kDelimiterError);
return;
}
if (sqlite3_value_type(argv[2]) != SQLITE_INTEGER) {
- sqlite3_result_error(context, kSplitFieldIndexError, -1);
+ sqlite::result::Error(context, kSplitFieldIndexError);
return;
}
int fld = sqlite3_value_int(argv[2]);
if (fld < 0) {
- sqlite3_result_error(context, kSplitFieldIndexError, -1);
+ sqlite::result::Error(context, kSplitFieldIndexError);
return;
}
if (sqlite3_value_type(argv[0]) != SQLITE_TEXT) {
- sqlite3_result_null(context);
+ sqlite::result::Null(context);
return;
}
const char* in = reinterpret_cast<const char*>(sqlite3_value_text(argv[0]));
@@ -62,7 +62,8 @@
if (fld == 0) {
int size = next != nullptr ? static_cast<int>(next - in)
: static_cast<int>(strlen(in));
- sqlite3_result_text(context, in, size, sqlite_utils::kSqliteTransient);
+ sqlite::result::RawString(context, in, size,
+ sqlite::utils::kSqliteTransient);
return;
} else if (next == nullptr) {
break;
@@ -70,7 +71,7 @@
in = next + delimiter_len;
--fld;
} while (fld >= 0);
- sqlite3_result_null(context);
+ sqlite::result::Null(context);
}
} // namespace
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc
index 3fa7bd0..1babe3d 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc
@@ -87,7 +87,7 @@
// Stack expects the opposite, thus iterates the args in reverse order.
for (size_t i = argc; i > 0; --i) {
size_t arg_index = i - 1;
- SqlValue value = sqlite_utils::SqliteValueToSqlValue(argv[arg_index]);
+ SqlValue value = sqlite::utils::SqliteValueToSqlValue(argv[arg_index]);
switch (value.type) {
case SqlValue::kBytes: {
stack->AppendRawProtoBytes(value.bytes_value, value.bytes_count);
@@ -101,7 +101,7 @@
break;
case SqlValue::kLong:
case SqlValue::kDouble:
- return sqlite_utils::InvalidArgumentTypeError(
+ return sqlite::utils::InvalidArgumentTypeError(
"entry", arg_index, value.type, SqlValue::kBytes,
SqlValue::kString, SqlValue::kNull);
}
@@ -148,7 +148,7 @@
kFunctionName, argc);
}
- base::StatusOr<SqlValue> value = sqlite_utils::ExtractArgument(
+ base::StatusOr<SqlValue> value = sqlite::utils::ExtractArgument(
argc, argv, "callsite_id", 0, SqlValue::kNull, SqlValue::kLong);
if (!value.ok()) {
return value.status();
@@ -162,7 +162,7 @@
.FindById(tables::StackProfileCallsiteTable::Id(
static_cast<uint32_t>(value->AsLong())))
.has_value()) {
- return sqlite_utils::ToInvalidArgumentError(
+ return sqlite::utils::ToInvalidArgumentError(
"callsite_id", 0,
base::ErrStatus("callsite_id does not exist: %" PRId64,
value->AsLong()));
@@ -172,8 +172,8 @@
bool annotate = false;
if (argc == 2) {
- value = sqlite_utils::ExtractArgument(argc, argv, "annotate", 1,
- SqlValue::Type::kLong);
+ value = sqlite::utils::ExtractArgument(argc, argv, "annotate", 1,
+ SqlValue::Type::kLong);
if (!value.ok()) {
return value.status();
}
@@ -215,7 +215,7 @@
sqlite3_value** argv,
SqlValue& out,
Destructors& destructors) {
- base::StatusOr<SqlValue> value = sqlite_utils::ExtractArgument(
+ base::StatusOr<SqlValue> value = sqlite::utils::ExtractArgument(
argc, argv, "frame_id", 0, SqlValue::kNull, SqlValue::kLong);
if (!value.ok()) {
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/utils.h b/src/trace_processor/perfetto_sql/intrinsics/functions/utils.h
index 57bd8dc..cc502ff 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/utils.h
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/utils.h
@@ -230,13 +230,13 @@
}
base::Status status =
- sqlite_utils::TypeCheckSqliteValue(argv[0], SqlValue::kString);
+ sqlite::utils::TypeCheckSqliteValue(argv[0], SqlValue::kString);
if (!status.ok()) {
return base::ErrStatus("WRITE_FILE: argument 1, filename; %s",
status.c_message());
}
- status = sqlite_utils::TypeCheckSqliteValue(argv[1], SqlValue::kBytes);
+ status = sqlite::utils::TypeCheckSqliteValue(argv[1], SqlValue::kBytes);
if (!status.ok()) {
return base::ErrStatus("WRITE_FILE: argument 2, content; %s",
status.c_message());
@@ -305,7 +305,7 @@
// This function always returns static strings (i.e. scoped to lifetime
// of the TraceStorage thread pool) so prevent SQLite from making copies.
- destructors.string_destructor = sqlite_utils::kSqliteStatic;
+ destructors.string_destructor = sqlite::utils::kSqliteStatic;
switch (opt_value->type) {
case Variadic::kNull:
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/window_functions.h b/src/trace_processor/perfetto_sql/intrinsics/functions/window_functions.h
index 3b90896..00de395 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/window_functions.h
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/window_functions.h
@@ -18,18 +18,16 @@
#define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_WINDOW_FUNCTIONS_H_
#include <sqlite3.h>
-#include <unordered_map>
-#include "perfetto/ext/base/base64.h"
-#include "perfetto/ext/base/file_utils.h"
-#include "perfetto/ext/trace_processor/demangle.h"
-#include "protos/perfetto/common/builtin_clock.pbzero.h"
-#include "src/trace_processor/export_json.h"
-#include "src/trace_processor/importers/common/clock_tracker.h"
-#include "src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.h"
-#include "src/trace_processor/util/status_macros.h"
+#include <cstdint>
+#include <type_traits>
-namespace perfetto {
-namespace trace_processor {
+#include "perfetto/base/logging.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/sqlite/sqlite_result.h"
+#include "src/trace_processor/sqlite/sqlite_window_function.h"
+
+namespace perfetto::trace_processor {
+
// Keeps track of the latest non null value and its position withing the
// window. Every time the window shrinks (`xInverse` is called) the window size
// is reduced by one and the position of the value moves one back, if it gets
@@ -89,66 +87,59 @@
sqlite3_value* last_non_null_value_;
};
-static_assert(std::is_standard_layout<LastNonNullAggregateContext>::value,
+static_assert(std::is_standard_layout_v<LastNonNullAggregateContext>,
"Must be able to be initialized by sqlite3_aggregate_context "
"(similar to calloc, i.e. no constructor called)");
-static_assert(std::is_trivial<LastNonNullAggregateContext>::value,
+static_assert(std::is_trivial_v<LastNonNullAggregateContext>,
"Must be able to be destroyed by just calling free (i.e. no "
"destructor called)");
-inline void LastNonNullStep(sqlite3_context* ctx,
- int argc,
- sqlite3_value** argv) {
- if (argc != 1) {
- sqlite3_result_error(
- ctx, "Unsupported number of args passed to LAST_NON_NULL", -1);
- return;
+class LastNonNull : public SqliteWindowFunction {
+ public:
+ static void Step(sqlite3_context* ctx, int argc, sqlite3_value** argv) {
+ if (argc != 1) {
+ return sqlite::result::Error(
+ ctx, "Unsupported number of args passed to LAST_NON_NULL");
+ }
+
+ auto* ptr = LastNonNullAggregateContext::GetOrCreate(ctx);
+ if (!ptr) {
+ return sqlite::result::Error(ctx,
+ "LAST_NON_NULL: Failed to allocate context");
+ }
+
+ ptr->PushBack(argv[0]);
}
- auto* ptr = LastNonNullAggregateContext::GetOrCreate(ctx);
- if (!ptr) {
- sqlite3_result_error(ctx, "LAST_NON_NULL: Failed to allocate context", -1);
- return;
+ static void Inverse(sqlite3_context* ctx, int, sqlite3_value**) {
+ auto* ptr = LastNonNullAggregateContext::GetOrCreate(ctx);
+ PERFETTO_CHECK(ptr != nullptr);
+ ptr->PopFront();
}
- ptr->PushBack(argv[0]);
-}
-
-inline void LastNonNullInverse(sqlite3_context* ctx, int, sqlite3_value**) {
- auto* ptr = LastNonNullAggregateContext::GetOrCreate(ctx);
- PERFETTO_CHECK(ptr != nullptr);
- ptr->PopFront();
-}
-
-inline void LastNonNullValue(sqlite3_context* ctx) {
- auto* ptr = LastNonNullAggregateContext::GetOrCreate(ctx);
- if (!ptr || !ptr->last_non_null_value()) {
- sqlite3_result_null(ctx);
- } else {
+ static void Value(sqlite3_context* ctx) {
+ auto* ptr = LastNonNullAggregateContext::GetOrCreate(ctx);
+ if (!ptr || !ptr->last_non_null_value()) {
+ return sqlite::result::Null(ctx);
+ }
sqlite3_result_value(ctx, ptr->last_non_null_value());
}
-}
-inline void LastNonNullFinal(sqlite3_context* ctx) {
- auto* ptr = LastNonNullAggregateContext::Get(ctx);
- if (!ptr || !ptr->last_non_null_value()) {
- sqlite3_result_null(ctx);
- } else {
- sqlite3_result_value(ctx, ptr->last_non_null_value());
+ static void Final(sqlite3_context* ctx) {
+ auto* ptr = LastNonNullAggregateContext::Get(ctx);
+ if (!ptr || !ptr->last_non_null_value()) {
+ return sqlite::result::Null(ctx);
+ }
+ sqlite::result::Value(ctx, ptr->last_non_null_value());
ptr->Destroy();
}
+};
+
+inline base::Status RegisterLastNonNullFunction(PerfettoSqlEngine& engine) {
+ return engine.RegisterSqliteWindowFunction<LastNonNull>("LAST_NON_NULL", 1,
+ nullptr);
}
-inline void RegisterLastNonNullFunction(sqlite3* db) {
- auto ret = sqlite3_create_window_function(
- db, "LAST_NON_NULL", 1, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr,
- &LastNonNullStep, &LastNonNullFinal, &LastNonNullValue,
- &LastNonNullInverse, nullptr);
- if (ret) {
- PERFETTO_ELOG("Error initializing LAST_NON_NULL");
- }
-}
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
#endif // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_WINDOW_FUNCTIONS_H_
diff --git a/src/trace_processor/perfetto_sql/intrinsics/operators/span_join_operator.cc b/src/trace_processor/perfetto_sql/intrinsics/operators/span_join_operator.cc
index a1d9630..6fe221d 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/operators/span_join_operator.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/operators/span_join_operator.cc
@@ -274,7 +274,7 @@
void**) {
if (base::CaseInsensitiveEqual(name, "source_geq")) {
*fn = [](sqlite3_context* ctx, int, sqlite3_value**) {
- sqlite3_result_error(ctx, "Should not be called.", -1);
+ return sqlite::result::Error(ctx, "Should not be called.");
};
return kSourceGeqOpCode;
}
@@ -297,7 +297,7 @@
// affect the span join computation. Similarily, source_geq constraints
// explicitly request that they are passed as geq constraints to the source
// tables.
- if (col_name == kTsColumnName && !sqlite_utils::IsOpLe(cs.op) &&
+ if (col_name == kTsColumnName && !sqlite::utils::IsOpLe(cs.op) &&
cs.op != kSourceGeqOpCode)
continue;
@@ -332,7 +332,7 @@
}
std::vector<SqliteTable::Column> cols;
- RETURN_IF_ERROR(sqlite_utils::GetColumnsForTable(
+ RETURN_IF_ERROR(sqlite::utils::GetColumnsForTable(
engine_->sqlite_engine()->db(), desc.name, cols));
uint32_t required_columns_found = 0;
@@ -558,14 +558,14 @@
switch (N) {
case Column::kTimestamp: {
auto max_ts = std::max(t1_.ts(), t2_.ts());
- sqlite3_result_int64(context, static_cast<sqlite3_int64>(max_ts));
+ sqlite::result::Long(context, static_cast<sqlite3_int64>(max_ts));
break;
}
case Column::kDuration: {
auto max_start = std::max(t1_.ts(), t2_.ts());
auto min_end = std::min(t1_.raw_ts_end(), t2_.raw_ts_end());
auto dur = min_end - max_start;
- sqlite3_result_int64(context, static_cast<sqlite3_int64>(dur));
+ sqlite::result::Long(context, static_cast<sqlite3_int64>(dur));
break;
}
case Column::kPartition: {
@@ -576,7 +576,7 @@
} else {
partition = t1_.IsReal() ? t1_.partition() : t2_.partition();
}
- sqlite3_result_int64(context, static_cast<sqlite3_int64>(partition));
+ sqlite::result::Long(context, static_cast<sqlite3_int64>(partition));
break;
}
PERFETTO_FALLTHROUGH;
@@ -803,33 +803,29 @@
void SpanJoinOperatorTable::Query::ReportSqliteResult(sqlite3_context* context,
size_t index) {
- const auto kSqliteTransient = reinterpret_cast<sqlite3_destructor_type>(-1);
if (state_ != State::kReal) {
- sqlite3_result_null(context);
- return;
+ return sqlite::result::Null(context);
}
sqlite3_stmt* stmt = stmt_->sqlite_stmt();
int idx = static_cast<int>(index);
switch (sqlite3_column_type(stmt, idx)) {
case SQLITE_INTEGER:
- sqlite3_result_int64(context, sqlite3_column_int64(stmt, idx));
- break;
+ return sqlite::result::Long(context, sqlite3_column_int64(stmt, idx));
case SQLITE_FLOAT:
- sqlite3_result_double(context, sqlite3_column_double(stmt, idx));
- break;
+ return sqlite::result::Double(context, sqlite3_column_double(stmt, idx));
case SQLITE_TEXT: {
// TODO(lalitm): note for future optimizations: if we knew the addresses
// of the string intern pool, we could check if the string returned here
// comes from the pool, and pass it as non-transient.
- auto ptr = reinterpret_cast<const char*>(sqlite3_column_text(stmt, idx));
- sqlite3_result_text(context, ptr, -1, kSqliteTransient);
- break;
+ const auto* ptr =
+ reinterpret_cast<const char*>(sqlite3_column_text(stmt, idx));
+ return sqlite::result::TransientString(context, ptr);
}
case SQLITE_BLOB: {
- sqlite3_result_blob(context, sqlite3_column_blob(stmt, idx),
- sqlite3_column_bytes(stmt, idx), kSqliteTransient);
- break;
+ return sqlite::result::TransientBytes(context,
+ sqlite3_column_blob(stmt, idx),
+ sqlite3_column_bytes(stmt, idx));
}
}
}
diff --git a/src/trace_processor/perfetto_sql/intrinsics/operators/window_operator.cc b/src/trace_processor/perfetto_sql/intrinsics/operators/window_operator.cc
index ba591a9..41c2841 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/operators/window_operator.cc
+++ b/src/trace_processor/perfetto_sql/intrinsics/operators/window_operator.cc
@@ -17,15 +17,12 @@
#include "src/trace_processor/perfetto_sql/intrinsics/operators/window_operator.h"
#include "perfetto/base/status.h"
+#include "src/trace_processor/sqlite/sqlite_result.h"
#include "src/trace_processor/sqlite/sqlite_utils.h"
namespace perfetto {
namespace trace_processor {
-namespace {
-using namespace sqlite_utils;
-} // namespace
-
WindowOperatorTable::WindowOperatorTable(sqlite3*, const TraceStorage*) {}
WindowOperatorTable::~WindowOperatorTable() = default;
@@ -114,7 +111,7 @@
// return the first row.
bool return_first = qc.constraints().size() == 1 &&
qc.constraints()[0].column == Column::kRowId &&
- IsOpEq(qc.constraints()[0].op) &&
+ sqlite::utils::IsOpEq(qc.constraints()[0].op) &&
sqlite3_value_int(argv[0]) == 0;
if (return_first) {
filter_type_ = FilterType::kReturnFirst;
@@ -128,33 +125,33 @@
int N) {
switch (N) {
case Column::kQuantum: {
- sqlite3_result_int64(context,
+ sqlite::result::Long(context,
static_cast<sqlite_int64>(table_->quantum_));
break;
}
case Column::kWindowStart: {
- sqlite3_result_int64(context,
+ sqlite::result::Long(context,
static_cast<sqlite_int64>(table_->window_start_));
break;
}
case Column::kWindowDur: {
- sqlite3_result_int(context, static_cast<int>(table_->window_dur_));
+ sqlite::result::Long(context, static_cast<int>(table_->window_dur_));
break;
}
case Column::kTs: {
- sqlite3_result_int64(context, static_cast<sqlite_int64>(current_ts_));
+ sqlite::result::Long(context, static_cast<sqlite_int64>(current_ts_));
break;
}
case Column::kDuration: {
- sqlite3_result_int64(context, static_cast<sqlite_int64>(step_size_));
+ sqlite::result::Long(context, static_cast<sqlite_int64>(step_size_));
break;
}
case Column::kQuantumTs: {
- sqlite3_result_int64(context, static_cast<sqlite_int64>(quantum_ts_));
+ sqlite::result::Long(context, static_cast<sqlite_int64>(quantum_ts_));
break;
}
case Column::kRowId: {
- sqlite3_result_int64(context, static_cast<sqlite_int64>(row_id_));
+ sqlite::result::Long(context, static_cast<sqlite_int64>(row_id_));
break;
}
default: {
diff --git a/src/trace_processor/perfetto_sql/stdlib/sched/thread_executing_span.sql b/src/trace_processor/perfetto_sql/stdlib/sched/thread_executing_span.sql
index 19f68c2b..348d261 100644
--- a/src/trace_processor/perfetto_sql/stdlib/sched/thread_executing_span.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/sched/thread_executing_span.sql
@@ -41,10 +41,13 @@
thread_state.dur,
thread_state.state,
thread_state.utid,
+ thread_state.waker_id,
thread_state.waker_utid
FROM thread_state
-WHERE thread_state.dur != -1 AND thread_state.waker_utid IS NOT NULL
- AND (thread_state.irq_context = 0 OR thread_state.irq_context IS NULL);
+WHERE
+ thread_state.dur != -1
+ AND thread_state.waker_utid IS NOT NULL
+ AND (thread_state.irq_context = 0 OR thread_state.irq_context IS NULL);
-- Similar to |_runnable_state| but finds the first runnable state at thread.
CREATE PERFETTO VIEW _first_runnable_state
@@ -62,10 +65,15 @@
thread_state.dur,
thread_state.state,
thread_state.utid,
+ thread_state.waker_id,
thread_state.waker_utid
FROM thread_state
-JOIN first_state USING (id)
-WHERE thread_state.dur != -1 AND thread_state.state = 'R' AND (thread_state.irq_context = 0 OR thread_state.irq_context IS NULL);
+JOIN first_state
+ USING (id)
+WHERE
+ thread_state.dur != -1
+ AND thread_state.state = 'R'
+ AND (thread_state.irq_context = 0 OR thread_state.irq_context IS NULL);
--
-- Finds all sleep states including interruptible (S) and uninterruptible (D).
@@ -125,82 +133,71 @@
--
-- We define the following markers in this table:
--
--- prev_start_id = R0_id.
--- prev_start_ts = R0_ts.
--- prev_start_dur = R0_dur.
--- prev_start_state = 'R'.
+-- prev_id = R0_id.
--
--- prev_end_id = S0_id.
-- prev_end_ts = S0_ts.
--- prev_end_dur = S0_dur.
--- prev_end_state = 'S' or 'D'.
+-- state = 'S' or 'D'.
+-- blocked_function = <kernel blocking function>
--
--- start_id = R1_id.
--- start_ts = R1_ts.
--- start_dur = R1_dur.
--- start_state = 'R'.
+-- id = R1_id.
+-- ts = R1_ts.
--
--- end_id = S1_id.
-- end_ts = S1_ts.
--- end_dur = S1_dur.
--- end_state = 'S' or 'D'.
-CREATE TABLE _wakeup AS
- SELECT
- LAG(r.id, 1) OVER (PARTITION BY r.utid ORDER BY r.ts) AS prev_start_id,
- LAG(r.ts, 1) OVER (PARTITION BY r.utid ORDER BY r.ts) AS prev_start_ts,
- LAG(r.dur, 1) OVER (PARTITION BY r.utid ORDER BY r.ts) AS prev_start_dur,
- LAG(r.state, 1) OVER (PARTITION BY r.utid ORDER BY r.ts) AS prev_start_state,
- s.id AS prev_end_id,
- s.ts AS prev_end_ts,
- s.dur AS prev_end_dur,
- s.state AS prev_end_state,
- s.blocked_function AS prev_blocked_function,
- r.id AS start_id,
- r.ts AS start_ts,
- r.dur AS start_dur,
- r.state AS start_state,
+CREATE PERFETTO TABLE _wakeup
+AS
+SELECT
+ s.state,
+ s.blocked_function,
+ r.id,
+ r.ts AS ts,
r.utid AS utid,
+ r.waker_id,
r.waker_utid,
- LEAD(s.id, 1) OVER (PARTITION BY r.utid ORDER BY r.ts) AS end_id,
- IFNULL(LEAD(s.ts, 1) OVER (PARTITION BY r.utid ORDER BY r.ts), thread_end.end_ts) AS end_ts,
- LEAD(s.dur, 1) OVER (PARTITION BY r.utid ORDER BY r.ts) AS end_dur,
- LEAD(s.state, 1) OVER (PARTITION BY r.utid ORDER BY r.ts) AS end_state,
- LEAD(s.blocked_function, 1) OVER (PARTITION BY r.utid ORDER BY r.ts) AS blocked_function
+ IFNULL(LEAD(s.ts) OVER (PARTITION BY r.utid ORDER BY r.ts), thread_end.end_ts) AS end_ts,
+ s.ts AS prev_end_ts,
+ LAG(r.id) OVER (PARTITION BY r.utid ORDER BY r.ts) AS prev_id
FROM _runnable_state r
JOIN _sleep_state s
ON s.utid = r.utid AND (s.ts + s.dur = r.ts)
-LEFT JOIN _thread_end_ts thread_end USING(utid)
+LEFT JOIN _thread_end_ts thread_end
+ USING (utid)
UNION ALL
- SELECT
- NULL AS prev_start_id,
- NULL AS prev_start_ts,
- NULL AS prev_start_dur,
- NULL AS prev_start_state,
- NULL AS prev_end_id,
- NULL AS prev_end_ts,
- NULL AS prev_end_dur,
- NULL AS prev_end_state,
- NULL AS prev_blocked_function,
- r.id AS start_id,
- r.ts AS start_ts,
- r.dur AS start_dur,
- r.state AS start_state,
+SELECT
+ NULL AS state,
+ NULL AS blocked_function,
+ r.id,
+ r.ts,
r.utid AS utid,
+ r.waker_id,
r.waker_utid,
- s.id AS end_id,
- IFNULL(s.ts, thread_end.end_ts) AS end_ts,
- s.dur AS end_dur,
- s.state AS end_state,
- s.blocked_function AS blocked_function
+ IFNULL(s.ts, thread_end.end_ts) AS end_ts,
+ NULL AS prev_end_ts,
+ NULL AS prev_id
FROM _first_runnable_state r
LEFT JOIN _first_sleep_state s
ON s.utid = r.utid
-LEFT JOIN _thread_end_ts thread_end USING(utid);
+LEFT JOIN _thread_end_ts thread_end
+ USING (utid);
--- Improves performance of |_wakeup_chain| computation.
-CREATE
- INDEX _wakeup_idx
-ON _wakeup(waker_utid, start_ts);
+-- Mapping from running thread state to runnable
+CREATE PERFETTO TABLE _waker_map
+AS
+WITH x AS (
+SELECT id, waker_id, utid, state FROM thread_state WHERE state = 'Running' AND dur != -1
+UNION ALL
+SELECT id, waker_id, utid, state FROM _first_runnable_state
+UNION ALL
+SELECT id, waker_id, utid, state FROM _runnable_state
+), y AS (
+ SELECT
+ id AS waker_id,
+ state,
+ max(id)
+ filter(WHERE state = 'R')
+ OVER (PARTITION BY utid ORDER BY id) AS id
+ FROM x
+ )
+SELECT id, waker_id FROM y WHERE state = 'Running' AND id IS NOT NULL ORDER BY waker_id;
--
-- Builds the parent-child chain from all thread_executing_spans. The parent is the waker and
@@ -209,14 +206,38 @@
-- Note that this doesn't include the roots. We'll compute the roots below.
-- This two step process improves performance because it's more efficient to scan
-- parent and find a child between than to scan child and find the parent it lies between.
-CREATE PERFETTO VIEW _wakeup_chain
+CREATE PERFETTO TABLE _wakeup_chain
AS
-SELECT parent.start_id AS parent_id, child.*
-FROM _wakeup parent
-JOIN _wakeup child
- ON (
- parent.utid = child.waker_utid
- AND child.start_ts BETWEEN parent.start_ts AND parent.end_ts);
+SELECT
+ _waker_map.id AS parent_id,
+ prev_id,
+ prev_end_ts,
+ _wakeup.id AS id,
+ _wakeup.ts AS ts,
+ _wakeup.end_ts,
+ IIF(_wakeup.state IS NULL OR _wakeup.state = 'S', 0, 1) AS is_kernel,
+ _wakeup.utid,
+ _wakeup.state,
+ _wakeup.blocked_function
+FROM _wakeup
+JOIN _waker_map USING(waker_id);
+
+-- The inverse of thread_executing_spans. All the sleeping periods between thread_executing_spans.
+CREATE PERFETTO TABLE _sleeping_span
+AS
+WITH
+ x AS (
+ SELECT
+ id,
+ ts,
+ lag(end_ts) OVER (PARTITION BY utid ORDER BY id) AS prev_end_ts,
+ utid
+ FROM _wakeup_chain
+ )
+SELECT
+ ts - prev_end_ts AS dur, prev_end_ts AS ts, id AS root_id, utid AS root_utid
+FROM x
+WHERE ts IS NOT NULL;
--
-- Finds the roots of the |_wakeup_chain|.
@@ -226,37 +247,56 @@
_wakeup_root_id AS (
SELECT DISTINCT parent_id AS id FROM _wakeup_chain
EXCEPT
- SELECT DISTINCT start_id AS id FROM _wakeup_chain
+ SELECT DISTINCT id FROM _wakeup_chain
)
SELECT NULL AS parent_id, _wakeup.*
FROM _wakeup
-JOIN _wakeup_root_id
- ON _wakeup_root_id.id = _wakeup.start_id;
+JOIN _wakeup_root_id USING(id);
--
-- Finds the leafs of the |_wakeup_chain|.
CREATE PERFETTO TABLE _wakeup_leaf AS
WITH
_wakeup_leaf_id AS (
- SELECT DISTINCT start_id AS id FROM _wakeup_chain
+ SELECT DISTINCT id AS id FROM _wakeup_chain
EXCEPT
SELECT DISTINCT parent_id AS id FROM _wakeup_chain
)
SELECT _wakeup_chain.*
FROM _wakeup_chain
-JOIN _wakeup_leaf_id
- ON _wakeup_leaf_id.id = _wakeup_chain.start_id;
+JOIN _wakeup_leaf_id USING(id);
--
-- Merges the roots, leafs and the rest of the chain.
CREATE TABLE _wakeup_graph
AS
-SELECT _wakeup_chain.*, 0 AS is_root, (_wakeup_leaf.start_id IS NOT NULL) AS is_leaf
+SELECT
+ _wakeup_chain.parent_id,
+ _wakeup_chain.id,
+ _wakeup_chain.ts,
+ _wakeup_chain.end_ts - _wakeup_chain.ts AS dur,
+ _wakeup_chain.utid,
+ _wakeup_chain.prev_end_ts,
+ _wakeup_chain.state,
+ _wakeup_chain.blocked_function,
+ 0 AS is_root,
+ (_wakeup_leaf.id IS NOT NULL) AS is_leaf
FROM _wakeup_chain
LEFT JOIN _wakeup_leaf
- USING (start_id)
+ USING (id)
UNION ALL
-SELECT *, 1 AS is_root, 0 AS is_leaf FROM _wakeup_root;
+SELECT
+ _wakeup_root.parent_id,
+ _wakeup_root.id,
+ _wakeup_root.ts,
+ _wakeup_root.end_ts - _wakeup_root.ts AS dur,
+ _wakeup_root.utid,
+ _wakeup_root.prev_end_ts,
+ _wakeup_root.state,
+ _wakeup_root.blocked_function,
+ 1 AS is_root,
+ 0 AS is_leaf
+FROM _wakeup_root;
-- Thread_executing_span graph of all wakeups across all processes.
--
@@ -266,7 +306,6 @@
-- @column ts Timestamp of first thread_state in thread_executing_span.
-- @column dur Duration of thread_executing_span.
-- @column utid Utid of thread with thread_state.
--- @column waker_utid Utid of thread that woke the first thread_state in thread_executing_span.
-- @column blocked_dur Duration of blocking thread state before waking up.
-- @column blocked_state Thread state ('D' or 'S') of blocked thread_state before waking up.
-- @column blocked_function Kernel blocked_function of thread state before waking up.
@@ -275,16 +314,15 @@
CREATE TABLE _thread_executing_span_graph AS
WITH roots AS (
SELECT
- start_id AS root_id,
+ id AS root_id,
parent_id,
- start_id AS id,
- start_ts AS ts,
- end_ts - start_ts AS dur,
+ id,
+ ts,
+ end_ts - ts AS dur,
utid,
- waker_utid,
- prev_end_dur AS blocked_dur,
- prev_end_state AS blocked_state,
- prev_blocked_function AS blocked_function,
+ ts - prev_end_ts AS blocked_dur,
+ state AS blocked_state,
+ blocked_function AS blocked_function,
1 AS is_root,
0 AS depth
FROM _wakeup_root
@@ -294,14 +332,13 @@
SELECT
chain.root_id,
graph.parent_id,
- graph.start_id AS id,
- graph.start_ts AS ts,
- graph.end_ts - graph.start_ts AS dur,
+ graph.id,
+ graph.ts,
+ graph.dur,
graph.utid,
- graph.waker_utid,
- graph.prev_end_dur AS blocked_dur,
- graph.prev_end_state AS blocked_state,
- graph.prev_blocked_function AS blocked_function,
+ graph.ts - graph.prev_end_ts AS blocked_dur,
+ graph.state AS blocked_state,
+ graph.blocked_function AS blocked_function,
0 AS is_root,
chain.depth + 1 AS depth
FROM _wakeup_graph graph
diff --git a/src/trace_processor/perfetto_sql/stdlib/time/conversion.sql b/src/trace_processor/perfetto_sql/stdlib/time/conversion.sql
index 9a284d0..0aa736d 100644
--- a/src/trace_processor/perfetto_sql/stdlib/time/conversion.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/time/conversion.sql
@@ -83,3 +83,75 @@
-- Time duration in nanoseconds.
RETURNS INT AS
SELECT $days * 24 * 60 * 60 * 1000 * 1000 * 1000;
+
+-- Returns the provided nanosecond duration, which is the default
+-- representation of time durations in trace processor. Provided for
+-- consistency with other functions.
+CREATE PERFETTO FUNCTION time_to_ns(
+ -- Time duration in nanoseconds.
+ nanos INT
+)
+-- Time duration in nanoseconds.
+RETURNS INT AS
+SELECT $nanos;
+
+-- Converts a duration in nanoseconds to microseconds. Nanoseconds is the default
+-- representation of time durations in trace processor.
+CREATE PERFETTO FUNCTION time_to_us(
+-- Time duration in nanoseconds.
+ nanos INT
+)
+-- Time duration in microseconds.
+RETURNS INT AS
+SELECT $nanos / 1000;
+
+-- Converts a duration in nanoseconds to millseconds. Nanoseconds is the default
+-- representation of time durations in trace processor.
+CREATE PERFETTO FUNCTION time_to_ms(
+ -- Time duration in nanoseconds.
+ nanos INT
+)
+-- Time duration in milliseconds.
+RETURNS INT AS
+SELECT $nanos / (1000 * 1000);
+
+-- Converts a duration in nanoseconds to seconds. Nanoseconds is the default
+-- representation of time durations in trace processor.
+CREATE PERFETTO FUNCTION time_to_s(
+ -- Time duration in nanoseconds.
+ nanos INT
+)
+-- Time duration in seconds.
+RETURNS INT AS
+SELECT $nanos / (1000 * 1000 * 1000);
+
+-- Converts a duration in nanoseconds to minutes. Nanoseconds is the default
+-- representation of time durations in trace processor.
+CREATE PERFETTO FUNCTION time_to_min(
+ -- Time duration in nanoseconds.
+ nanos INT
+)
+-- Time duration in minutes.
+RETURNS INT AS
+SELECT $nanos / (60 * 1000 * 1000 * 1000);
+
+-- Converts a duration in nanoseconds to hours. Nanoseconds is the default
+-- representation of time durations in trace processor.
+CREATE PERFETTO FUNCTION time_to_hours(
+ -- Time duration in nanoseconds.
+ nanos INT
+)
+-- Time duration in hours.
+RETURNS INT AS
+SELECT $nanos / (60 * 60 * 1000 * 1000 * 1000);
+
+-- Converts a duration in nanoseconds to days. Nanoseconds is the default
+-- representation of time durations in trace processor.
+CREATE PERFETTO FUNCTION time_to_days(
+ -- Time duration in nanoseconds.
+ nanos INT
+)
+-- Time duration in days.
+RETURNS INT AS
+SELECT $nanos / (24 * 60 * 60 * 1000 * 1000 * 1000);
+
diff --git a/src/trace_processor/sqlite/BUILD.gn b/src/trace_processor/sqlite/BUILD.gn
index e16e591..e82712d 100644
--- a/src/trace_processor/sqlite/BUILD.gn
+++ b/src/trace_processor/sqlite/BUILD.gn
@@ -28,6 +28,7 @@
"sql_stats_table.h",
"sqlite_engine.cc",
"sqlite_engine.h",
+ "sqlite_result.h",
"sqlite_table.cc",
"sqlite_table.h",
"sqlite_tokenizer.cc",
@@ -35,6 +36,7 @@
"sqlite_utils.cc",
"sqlite_utils.h",
"sqlite_utils.h",
+ "sqlite_window_function.h",
"stats_table.cc",
"stats_table.h",
]
diff --git a/src/trace_processor/sqlite/db_sqlite_table.cc b/src/trace_processor/sqlite/db_sqlite_table.cc
index 8d18365..b0b6678 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.cc
+++ b/src/trace_processor/sqlite/db_sqlite_table.cc
@@ -319,7 +319,7 @@
{
auto p = [&cs](const QueryConstraints::OrderBy& o) {
auto inner_p = [&o](const QueryConstraints::Constraint& c) {
- return c.column == o.iColumn && sqlite_utils::IsOpEq(c.op);
+ return c.column == o.iColumn && sqlite::utils::IsOpEq(c.op);
};
return std::any_of(cs->begin(), cs->end(), inner_p);
};
@@ -373,7 +373,7 @@
if (current_row_count < 2)
break;
const auto& col_schema = schema.columns[static_cast<uint32_t>(c.column)];
- if (sqlite_utils::IsOpEq(c.op) && col_schema.is_id) {
+ if (sqlite::utils::IsOpEq(c.op) && col_schema.is_id) {
// If we have an id equality constraint, we can very efficiently filter
// down to a single row in C++. However, if we're joining with another
// table, SQLite will do this once per row which can be extremely
@@ -382,7 +382,7 @@
// entire filter call is ~10x the cost of iterating a single row.
filter_cost += 10;
current_row_count = 1;
- } else if (sqlite_utils::IsOpEq(c.op)) {
+ } else if (sqlite::utils::IsOpEq(c.op)) {
// If there is only a single equality constraint, we have special logic
// to sort by that column and then binary search if we see the constraint
// set often. Model this by dividing by the log of the number of rows as
@@ -400,8 +400,8 @@
double estimated_rows = current_row_count / (2 * log2(current_row_count));
current_row_count = std::max(static_cast<uint32_t>(estimated_rows), 1u);
} else if (col_schema.is_sorted &&
- (sqlite_utils::IsOpLe(c.op) || sqlite_utils::IsOpLt(c.op) ||
- sqlite_utils::IsOpGt(c.op) || sqlite_utils::IsOpGe(c.op))) {
+ (sqlite::utils::IsOpLe(c.op) || sqlite::utils::IsOpLt(c.op) ||
+ sqlite::utils::IsOpGt(c.op) || sqlite::utils::IsOpGe(c.op))) {
// On a sorted column, if we see any partition constraints, we can do this
// filter very efficiently. Model this using the log of the number of
// rows as a good approximation.
@@ -506,7 +506,7 @@
// If the constraing is not an equality constraint, there's little
// benefit to caching
const auto& c = qc.constraints().front();
- if (!sqlite_utils::IsOpEq(c.op))
+ if (!sqlite::utils::IsOpEq(c.op))
return;
// If the column is already sorted, we don't need to cache at all.
diff --git a/src/trace_processor/sqlite/db_sqlite_table.h b/src/trace_processor/sqlite/db_sqlite_table.h
index 45bc124..82993ca 100644
--- a/src/trace_processor/sqlite/db_sqlite_table.h
+++ b/src/trace_processor/sqlite/db_sqlite_table.h
@@ -128,8 +128,8 @@
// long as we don't call Next(). However, that only happens when Next() is
// called on the Cursor itself, at which point SQLite no longer cares
// about the bytes pointer.
- sqlite_utils::ReportSqlValue(ctx, value, sqlite_utils::kSqliteStatic,
- sqlite_utils::kSqliteStatic);
+ sqlite::utils::ReportSqlValue(ctx, value, sqlite::utils::kSqliteStatic,
+ sqlite::utils::kSqliteStatic);
}
private:
diff --git a/src/trace_processor/sqlite/sql_stats_table.cc b/src/trace_processor/sqlite/sql_stats_table.cc
index e6cdf87..fb1d59c 100644
--- a/src/trace_processor/sqlite/sql_stats_table.cc
+++ b/src/trace_processor/sqlite/sql_stats_table.cc
@@ -83,17 +83,16 @@
const TraceStorage::SqlStats& stats = storage_->sql_stats();
switch (col) {
case Column::kQuery:
- sqlite3_result_text(context, stats.queries()[row_].c_str(), -1,
- sqlite_utils::kSqliteStatic);
+ sqlite::result::StaticString(context, stats.queries()[row_].c_str());
break;
case Column::kTimeStarted:
- sqlite3_result_int64(context, stats.times_started()[row_]);
+ sqlite::result::Long(context, stats.times_started()[row_]);
break;
case Column::kTimeFirstNext:
- sqlite3_result_int64(context, stats.times_first_next()[row_]);
+ sqlite::result::Long(context, stats.times_first_next()[row_]);
break;
case Column::kTimeEnded:
- sqlite3_result_int64(context, stats.times_ended()[row_]);
+ sqlite::result::Long(context, stats.times_ended()[row_]);
break;
}
return base::OkStatus();
diff --git a/src/trace_processor/sqlite/sqlite_engine.cc b/src/trace_processor/sqlite/sqlite_engine.cc
index 9c5da35..ec9c01d 100644
--- a/src/trace_processor/sqlite/sqlite_engine.cc
+++ b/src/trace_processor/sqlite/sqlite_engine.cc
@@ -199,6 +199,25 @@
return base::OkStatus();
}
+base::Status SqliteEngine::RegisterWindowFunction(const char* name,
+ int argc,
+ WindowFnStep* step,
+ WindowFnInverse* inverse,
+ WindowFnValue* value,
+ WindowFnFinal* final,
+ void* ctx,
+ FnCtxDestructor* destructor,
+ bool deterministic) {
+ int flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0);
+ int ret = sqlite3_create_window_function(
+ db_.get(), name, static_cast<int>(argc), flags, ctx, step, final, value,
+ inverse, destructor);
+ if (ret != SQLITE_OK) {
+ return base::ErrStatus("Unable to register function with name %s", name);
+ }
+ return base::OkStatus();
+}
+
base::Status SqliteEngine::UnregisterFunction(const char* name, int argc) {
int ret = sqlite3_create_function_v2(db_.get(), name, static_cast<int>(argc),
SQLITE_UTF8, nullptr, nullptr, nullptr,
diff --git a/src/trace_processor/sqlite/sqlite_engine.h b/src/trace_processor/sqlite/sqlite_engine.h
index 9af23fe..e46b9ee 100644
--- a/src/trace_processor/sqlite/sqlite_engine.h
+++ b/src/trace_processor/sqlite/sqlite_engine.h
@@ -51,6 +51,14 @@
class SqliteEngine {
public:
using Fn = void(sqlite3_context* ctx, int argc, sqlite3_value** argv);
+ using WindowFnStep = void(sqlite3_context* ctx,
+ int argc,
+ sqlite3_value** argv);
+ using WindowFnInverse = void(sqlite3_context* ctx,
+ int argc,
+ sqlite3_value** argv);
+ using WindowFnValue = void(sqlite3_context* ctx);
+ using WindowFnFinal = void(sqlite3_context* ctx);
using FnCtxDestructor = void(void*);
// Wrapper class for SQLite's |sqlite3_stmt| struct and associated functions.
@@ -90,6 +98,17 @@
FnCtxDestructor* ctx_destructor,
bool deterministic);
+ // Registers a C++ window function to be runnable from SQL.
+ base::Status RegisterWindowFunction(const char* name,
+ int argc,
+ WindowFnStep* step,
+ WindowFnInverse* inverse,
+ WindowFnValue* value,
+ WindowFnFinal* final,
+ void* ctx,
+ FnCtxDestructor* ctx_destructor,
+ bool deterministic);
+
// Unregisters a C++ function from SQL.
base::Status UnregisterFunction(const char* name, int argc);
diff --git a/src/trace_processor/sqlite/sqlite_result.h b/src/trace_processor/sqlite/sqlite_result.h
new file mode 100644
index 0000000..4030043
--- /dev/null
+++ b/src/trace_processor/sqlite/sqlite_result.h
@@ -0,0 +1,95 @@
+/*
+ * 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_SQLITE_SQLITE_RESULT_H_
+#define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_RESULT_H_
+
+#include <sqlite3.h>
+#include <cstdint>
+
+namespace perfetto::trace_processor::sqlite::result {
+
+// This file contains wraps the sqlite3_result_* functions which tell SQLite
+// about the result of executing a function or calling a xColumn on a virtual
+// table.
+
+const auto kSqliteStatic = reinterpret_cast<sqlite3_destructor_type>(0);
+const auto kSqliteTransient = reinterpret_cast<sqlite3_destructor_type>(-1);
+
+inline void Null(sqlite3_context* ctx) {
+ sqlite3_result_null(ctx);
+}
+
+inline void Long(sqlite3_context* ctx, int64_t res) {
+ sqlite3_result_int64(ctx, res);
+}
+
+inline void Double(sqlite3_context* ctx, double res) {
+ sqlite3_result_double(ctx, res);
+}
+
+inline void RawString(sqlite3_context* ctx,
+ const char* str,
+ int size,
+ sqlite3_destructor_type destructor) {
+ sqlite3_result_text(ctx, str, size, destructor);
+}
+inline void RawString(sqlite3_context* ctx,
+ const char* str,
+ sqlite3_destructor_type destructor) {
+ RawString(ctx, str, -1, destructor);
+}
+inline void StaticString(sqlite3_context* ctx, const char* str) {
+ RawString(ctx, str, kSqliteStatic);
+}
+inline void TransientString(sqlite3_context* ctx, const char* str) {
+ RawString(ctx, str, kSqliteTransient);
+}
+
+inline void RawBytes(sqlite3_context* ctx,
+ const void* bytes,
+ int size,
+ sqlite3_destructor_type destructor) {
+ sqlite3_result_blob(ctx, bytes, size, destructor);
+}
+inline void StaticBytes(sqlite3_context* ctx, const void* bytes, int size) {
+ RawBytes(ctx, bytes, size, kSqliteStatic);
+}
+inline void TransientBytes(sqlite3_context* ctx, const void* bytes, int size) {
+ RawBytes(ctx, bytes, size, kSqliteTransient);
+}
+
+inline void Error(sqlite3_context* ctx, const char* error) {
+ sqlite3_result_error(ctx, error, -1);
+}
+
+inline void Value(sqlite3_context* ctx, sqlite3_value* value) {
+ sqlite3_result_value(ctx, value);
+}
+
+inline void RawPointer(sqlite3_context* ctx,
+ void* ptr,
+ const char* name,
+ sqlite3_destructor_type destructor) {
+ sqlite3_result_pointer(ctx, ptr, name, destructor);
+}
+inline void StaticPointer(sqlite3_context* ctx, void* ptr, const char* name) {
+ RawPointer(ctx, ptr, name, nullptr);
+}
+
+} // namespace perfetto::trace_processor::sqlite::result
+
+#endif // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_RESULT_H_
diff --git a/src/trace_processor/sqlite/sqlite_utils.cc b/src/trace_processor/sqlite/sqlite_utils.cc
index 4165f2d..04ddf9c 100644
--- a/src/trace_processor/sqlite/sqlite_utils.cc
+++ b/src/trace_processor/sqlite/sqlite_utils.cc
@@ -15,15 +15,24 @@
*/
#include "src/trace_processor/sqlite/sqlite_utils.h"
-#include <bitset>
+
+#include <cstddef>
+#include <cstdint>
+#include <limits>
+#include <optional>
#include <sstream>
+#include <string>
+#include <vector>
+
+#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
+#include "perfetto/ext/base/status_or.h"
#include "perfetto/ext/base/string_utils.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/sqlite/scoped_db.h"
+#include "src/trace_processor/sqlite/sqlite_table.h"
-namespace perfetto {
-namespace trace_processor {
-namespace sqlite_utils {
+namespace perfetto::trace_processor::sqlite::utils {
namespace internal {
namespace {
std::string ToExpectedTypesString(ExpectedTypesSet expected_types) {
@@ -66,14 +75,12 @@
return MissingArgumentError(argument_name);
}
- SqlValue value = sqlite_utils::SqliteValueToSqlValue(argv[arg_index]);
-
+ SqlValue value = sqlite::utils::SqliteValueToSqlValue(argv[arg_index]);
if (!expected_types.test(value.type)) {
return InvalidArgumentTypeError(argument_name, arg_index, value.type,
expected_types);
}
-
- return std::move(value);
+ return value;
}
} // namespace internal
@@ -82,8 +89,7 @@
int len = sqlite3_value_bytes16(value);
PERFETTO_CHECK(len >= 0);
size_t count = static_cast<size_t>(len) / sizeof(wchar_t);
- return std::wstring(
- reinterpret_cast<const wchar_t*>(sqlite3_value_text16(value)), count);
+ return {reinterpret_cast<const wchar_t*>(sqlite3_value_text16(value)), count};
}
base::Status GetColumnsForTable(sqlite3* db,
@@ -244,7 +250,7 @@
SqlValue::Type expected_type,
const char* expected_type_str) {
SqlValue::Type actual_type =
- sqlite_utils::SqliteTypeToSqlValueType(sqlite3_value_type(value));
+ sqlite::utils::SqliteTypeToSqlValueType(sqlite3_value_type(value));
if (actual_type != SqlValue::Type::kNull && actual_type != expected_type) {
return base::ErrStatus(
"does not have expected type: expected %s, actual %s",
@@ -328,11 +334,9 @@
base::Status ToInvalidArgumentError(const char* argument_name,
size_t arg_index,
- const base::Status error) {
+ const base::Status& error) {
return base::ErrStatus("argument %s at pos %zu: %s", argument_name,
arg_index + 1, error.message().c_str());
}
-} // namespace sqlite_utils
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::sqlite::utils
diff --git a/src/trace_processor/sqlite/sqlite_utils.h b/src/trace_processor/sqlite/sqlite_utils.h
index 7ca61b2..7cdb1d1 100644
--- a/src/trace_processor/sqlite/sqlite_utils.h
+++ b/src/trace_processor/sqlite/sqlite_utils.h
@@ -17,27 +17,23 @@
#ifndef SRC_TRACE_PROCESSOR_SQLITE_SQLITE_UTILS_H_
#define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_UTILS_H_
-#include <math.h>
#include <sqlite3.h>
#include <bitset>
#include <cstddef>
+#include <cstdint>
#include <cstring>
#include <optional>
#include <string>
-#include <utility>
+#include <vector>
#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
#include "perfetto/ext/base/status_or.h"
-#include "perfetto/ext/base/string_utils.h"
-#include "perfetto/ext/base/string_view.h"
#include "perfetto/trace_processor/basic_types.h"
-#include "src/trace_processor/sqlite/scoped_db.h"
+#include "src/trace_processor/sqlite/sqlite_result.h"
#include "src/trace_processor/sqlite/sqlite_table.h"
-namespace perfetto {
-namespace trace_processor {
-namespace sqlite_utils {
+namespace perfetto::trace_processor::sqlite::utils {
const auto kSqliteStatic = reinterpret_cast<sqlite3_destructor_type>(0);
const auto kSqliteTransient = reinterpret_cast<sqlite3_destructor_type>(-1);
@@ -121,36 +117,36 @@
sqlite3_destructor_type bytes_destructor = kSqliteTransient) {
switch (value.type) {
case SqlValue::Type::kLong:
- sqlite3_result_int64(ctx, value.long_value);
+ sqlite::result::Long(ctx, value.long_value);
break;
case SqlValue::Type::kDouble:
- sqlite3_result_double(ctx, value.double_value);
+ sqlite::result::Double(ctx, value.double_value);
break;
case SqlValue::Type::kString: {
- sqlite3_result_text(ctx, value.string_value, -1, string_destructor);
+ sqlite::result::RawString(ctx, value.string_value, string_destructor);
break;
}
case SqlValue::Type::kBytes:
- sqlite3_result_blob(ctx, value.bytes_value,
- static_cast<int>(value.bytes_count),
- bytes_destructor);
+ sqlite::result::RawBytes(ctx, value.bytes_value,
+ static_cast<int>(value.bytes_count),
+ bytes_destructor);
break;
case SqlValue::Type::kNull:
- sqlite3_result_null(ctx);
+ sqlite::result::Null(ctx);
break;
}
}
-inline void SetSqliteError(sqlite3_context* ctx, const base::Status& status) {
+inline void SetError(sqlite3_context* ctx, const base::Status& status) {
PERFETTO_CHECK(!status.ok());
- sqlite3_result_error(ctx, status.c_message(), -1);
+ sqlite::result::Error(ctx, status.c_message());
}
-inline void SetSqliteError(sqlite3_context* ctx,
- const std::string& function_name,
- const base::Status& status) {
- SetSqliteError(ctx, base::ErrStatus("%s: %s", function_name.c_str(),
- status.c_message()));
+inline void SetError(sqlite3_context* ctx,
+ const std::string& function_name,
+ const base::Status& status) {
+ SetError(ctx, base::ErrStatus("%s: %s", function_name.c_str(),
+ status.c_message()));
}
// Exracts the given type from the SqlValue if |value| can fit
@@ -250,7 +246,7 @@
base::Status ToInvalidArgumentError(const char* argument_name,
size_t arg_index,
- const base::Status error);
+ const base::Status& error);
template <typename... args>
base::StatusOr<SqlValue> ExtractArgument(size_t argc,
@@ -264,8 +260,6 @@
internal::ToExpectedTypesSet(expected_type, expected_type_args...));
}
-} // namespace sqlite_utils
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::sqlite::utils
#endif // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_UTILS_H_
diff --git a/src/trace_processor/sqlite/sqlite_utils_unittest.cc b/src/trace_processor/sqlite/sqlite_utils_unittest.cc
index be28af1..4347317 100644
--- a/src/trace_processor/sqlite/sqlite_utils_unittest.cc
+++ b/src/trace_processor/sqlite/sqlite_utils_unittest.cc
@@ -16,11 +16,10 @@
#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/sqlite/scoped_db.h"
#include "test/gtest_and_gmock.h"
-namespace perfetto {
-namespace trace_processor {
-namespace sqlite_utils {
+namespace perfetto::trace_processor::sqlite::utils {
namespace {
@@ -54,7 +53,7 @@
TEST_F(GetColumnsForTableTest, ValidInput) {
RunStatement("CREATE TABLE foo (name STRING, ts INT, dur INT);");
std::vector<SqliteTable::Column> columns;
- auto status = sqlite_utils::GetColumnsForTable(*db_, "foo", columns);
+ auto status = sqlite::utils::GetColumnsForTable(*db_, "foo", columns);
ASSERT_TRUE(status.ok());
}
@@ -64,13 +63,14 @@
// crashing.
RunStatement("CREATE TABLE foo (name NUM, ts INT, dur INT);");
std::vector<SqliteTable::Column> columns;
- auto status = sqlite_utils::GetColumnsForTable(*db_, "foo", columns);
+ auto status = sqlite::utils::GetColumnsForTable(*db_, "foo", columns);
ASSERT_FALSE(status.ok());
}
TEST_F(GetColumnsForTableTest, UnknownTableName) {
std::vector<SqliteTable::Column> columns;
- auto status = sqlite_utils::GetColumnsForTable(*db_, "unknowntable", columns);
+ auto status =
+ sqlite::utils::GetColumnsForTable(*db_, "unknowntable", columns);
ASSERT_FALSE(status.ok());
}
@@ -178,6 +178,4 @@
}
} // namespace
-} // namespace sqlite_utils
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor::sqlite::utils
diff --git a/src/trace_processor/sqlite/sqlite_vtable_benchmark.cc b/src/trace_processor/sqlite/sqlite_vtable_benchmark.cc
index f231abf..c2ca5d6 100644
--- a/src/trace_processor/sqlite/sqlite_vtable_benchmark.cc
+++ b/src/trace_processor/sqlite/sqlite_vtable_benchmark.cc
@@ -19,13 +19,18 @@
// in a buffer. This is to have a fair estimate w.r.t. cache-misses and pointer
// chasing of what an upper-bound can be for a virtual table implementation.
-#include <array>
+#include <cstddef>
+#include <cstdint>
+#include <cstdlib>
#include <random>
+#include <string>
+#include <vector>
#include <benchmark/benchmark.h>
#include <sqlite3.h>
#include "perfetto/base/compiler.h"
+#include "perfetto/base/logging.h"
#include "src/trace_processor/sqlite/scoped_db.h"
namespace {
@@ -76,7 +81,7 @@
}
PERFETTO_NO_INLINE int Next();
PERFETTO_NO_INLINE int Column(sqlite3_context* ctx, int);
- PERFETTO_NO_INLINE int Eof();
+ PERFETTO_NO_INLINE int Eof() const;
void RandomFill();
private:
@@ -113,7 +118,7 @@
return SQLITE_OK;
}
-int BenchmarkCursor::Eof() {
+int BenchmarkCursor::Eof() const {
return eof_;
}
@@ -202,9 +207,9 @@
return db;
}
-static void BM_SqliteStepAndResult(benchmark::State& state) {
- size_t batch_size = static_cast<size_t>(state.range(0));
- size_t num_cols = static_cast<size_t>(state.range(1));
+void BM_SqliteStepAndResult(benchmark::State& state) {
+ auto batch_size = static_cast<size_t>(state.range(0));
+ auto num_cols = static_cast<size_t>(state.range(1));
// Make sure the module outlives the ScopedDb. SQLite calls xDisconnect in
// the database close function and so this struct needs to be available then.
@@ -236,8 +241,8 @@
BENCHMARK(BM_SqliteStepAndResult)->Apply(BenchmarkArgs);
-static void BM_SqliteCountOne(benchmark::State& state) {
- size_t batch_size = static_cast<size_t>(state.range(0));
+void BM_SqliteCountOne(benchmark::State& state) {
+ auto batch_size = static_cast<size_t>(state.range(0));
// Make sure the module outlives the ScopedDb. SQLite calls xDisconnect in
// the database close function and so this struct needs to be available then.
diff --git a/src/trace_processor/sqlite/sqlite_window_function.h b/src/trace_processor/sqlite/sqlite_window_function.h
new file mode 100644
index 0000000..ac61c4f
--- /dev/null
+++ b/src/trace_processor/sqlite/sqlite_window_function.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2023 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_SQLITE_SQLITE_WINDOW_FUNCTION_H_
+#define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_WINDOW_FUNCTION_H_
+
+struct sqlite3_context;
+struct sqlite3_value;
+
+namespace perfetto::trace_processor {
+
+// Prototype for a window function which can be registered with SQLite.
+//
+// See https://www.sqlite.org/windowfunctions.html#udfwinfunc for details on how
+// to implement the methods of this class.
+class SqliteWindowFunction {
+ public:
+ // The type of the context object which will be passed to the function.
+ // Can be redefined in any sub-classes to override the context.
+ using Context = void;
+
+ // The xStep function which will be executed by SQLite to add a row of values
+ // to the current window.
+ //
+ // Implementations MUST define this function themselves; this function is
+ // declared but *not* defined so linker errors will be thrown if not defined.
+ static void Step(sqlite3_context*, int argc, sqlite3_value** argv);
+
+ // The xStep function which will be executed by SQLite to remove a row of
+ // values from the current window.
+ //
+ // Implementations MUST define this function themselves; this function is
+ // declared but *not* defined so linker errors will be thrown if not defined.
+ static void Inverse(sqlite3_context* ctx, int argc, sqlite3_value** argv);
+
+ // The xValue function which will be executed by SQLite to obtain the current
+ // value of the aggregate.
+ //
+ // Implementations MUST define this function themselves; this function is
+ // declared but *not* defined so linker errors will be thrown if not defined.
+ static void Value(sqlite3_context* ctx);
+
+ // The xInverse function which will be executed by SQLite to obtain the
+ // current value of the aggregate *and* free all resources allocated by
+ // previous calls to Step, Inverse and Value.
+ //
+ // Implementations MUST define this function themselves; this function is
+ // declared but *not* defined so linker errors will be thrown if not defined.
+ static void Final(sqlite3_context* ctx);
+};
+
+} // namespace perfetto::trace_processor
+
+#endif // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_WINDOW_FUNCTION_H_
diff --git a/src/trace_processor/sqlite/stats_table.cc b/src/trace_processor/sqlite/stats_table.cc
index 296a2f5..d93057d 100644
--- a/src/trace_processor/sqlite/stats_table.cc
+++ b/src/trace_processor/sqlite/stats_table.cc
@@ -16,18 +16,25 @@
#include "src/trace_processor/sqlite/stats_table.h"
-#include "perfetto/base/status.h"
-#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include <memory>
-namespace perfetto {
-namespace trace_processor {
+#include "perfetto/base/status.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "src/trace_processor/sqlite/query_constraints.h"
+#include "src/trace_processor/sqlite/sqlite_result.h"
+#include "src/trace_processor/sqlite/sqlite_table.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/storage/stats.h"
+#include "src/trace_processor/storage/trace_storage.h"
+
+namespace perfetto::trace_processor {
StatsTable::StatsTable(sqlite3*, const TraceStorage* storage)
: storage_(storage) {}
StatsTable::~StatsTable() = default;
-util::Status StatsTable::Init(int, const char* const*, Schema* schema) {
+base::Status StatsTable::Init(int, const char* const*, Schema* schema) {
*schema = Schema(
{
SqliteTable::Column(Column::kName, "name", SqlValue::Type::kString),
@@ -42,7 +49,7 @@
SqlValue::Type::kString),
},
{Column::kName});
- return util::OkStatus();
+ return base::OkStatus();
}
std::unique_ptr<SqliteTable::BaseCursor> StatsTable::CreateCursor() {
@@ -68,50 +75,49 @@
}
base::Status StatsTable::Cursor::Column(sqlite3_context* ctx, int N) {
- const auto kSqliteStatic = sqlite_utils::kSqliteStatic;
switch (N) {
case Column::kName:
- sqlite3_result_text(ctx, stats::kNames[key_], -1, kSqliteStatic);
+ sqlite::result::StaticString(ctx, stats::kNames[key_]);
break;
case Column::kIndex:
if (stats::kTypes[key_] == stats::kIndexed) {
- sqlite3_result_int(ctx, index_->first);
+ sqlite::result::Long(ctx, index_->first);
} else {
- sqlite3_result_null(ctx);
+ sqlite::result::Null(ctx);
}
break;
case Column::kSeverity:
switch (stats::kSeverities[key_]) {
case stats::kInfo:
- sqlite3_result_text(ctx, "info", -1, kSqliteStatic);
+ sqlite::result::StaticString(ctx, "info");
break;
case stats::kDataLoss:
- sqlite3_result_text(ctx, "data_loss", -1, kSqliteStatic);
+ sqlite::result::StaticString(ctx, "data_loss");
break;
case stats::kError:
- sqlite3_result_text(ctx, "error", -1, kSqliteStatic);
+ sqlite::result::StaticString(ctx, "error");
break;
}
break;
case Column::kSource:
switch (stats::kSources[key_]) {
case stats::kTrace:
- sqlite3_result_text(ctx, "trace", -1, kSqliteStatic);
+ sqlite::result::StaticString(ctx, "trace");
break;
case stats::kAnalysis:
- sqlite3_result_text(ctx, "analysis", -1, kSqliteStatic);
+ sqlite::result::StaticString(ctx, "analysis");
break;
}
break;
case Column::kValue:
if (stats::kTypes[key_] == stats::kIndexed) {
- sqlite3_result_int64(ctx, index_->second);
+ sqlite::result::Long(ctx, index_->second);
} else {
- sqlite3_result_int64(ctx, storage_->stats()[key_].value);
+ sqlite::result::Long(ctx, storage_->stats()[key_].value);
}
break;
case Column::kDescription:
- sqlite3_result_text(ctx, stats::kDescriptions[key_], -1, kSqliteStatic);
+ sqlite::result::StaticString(ctx, stats::kDescriptions[key_]);
break;
default:
PERFETTO_FATAL("Unknown column %d", N);
@@ -144,5 +150,4 @@
return key_ >= stats::kNumKeys;
}
-} // namespace trace_processor
-} // namespace perfetto
+} // namespace perfetto::trace_processor
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index d0d335f..9ac4a5c 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -17,20 +17,32 @@
#include "src/trace_processor/trace_processor_impl.h"
#include <algorithm>
+#include <chrono>
+#include <cinttypes>
#include <cstddef>
#include <cstdint>
+#include <limits>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
+#include <vector>
#include "perfetto/base/logging.h"
#include "perfetto/base/status.h"
#include "perfetto/base/time.h"
#include "perfetto/ext/base/flat_hash_map.h"
+#include "perfetto/ext/base/small_vector.h"
+#include "perfetto/ext/base/status_or.h"
#include "perfetto/ext/base/string_splitter.h"
#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/protozero/scattered_heap_buffer.h"
+#include "perfetto/public/compiler.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "perfetto/trace_processor/iterator.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
+#include "perfetto/trace_processor/trace_processor.h"
+#include "sqlite/sqlite_utils.h"
#include "src/trace_processor/importers/android_bugreport/android_bugreport_parser.h"
#include "src/trace_processor/importers/common/clock_tracker.h"
#include "src/trace_processor/importers/common/metadata_tracker.h"
@@ -88,10 +100,14 @@
#include "src/trace_processor/sqlite/sql_stats_table.h"
#include "src/trace_processor/sqlite/sqlite_table.h"
#include "src/trace_processor/sqlite/stats_table.h"
+#include "src/trace_processor/storage/metadata.h"
+#include "src/trace_processor/storage/trace_storage.h"
#include "src/trace_processor/tp_metatrace.h"
+#include "src/trace_processor/trace_processor_storage_impl.h"
#include "src/trace_processor/types/trace_processor_context.h"
#include "src/trace_processor/types/variadic.h"
#include "src/trace_processor/util/descriptors.h"
+#include "src/trace_processor/util/gzip_utils.h"
#include "src/trace_processor/util/protozero_to_json.h"
#include "src/trace_processor/util/protozero_to_text.h"
#include "src/trace_processor/util/regex.h"
@@ -103,6 +119,7 @@
#include "protos/perfetto/trace/perfetto/perfetto_metatrace.pbzero.h"
#include "protos/perfetto/trace/trace.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"
+#include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
namespace perfetto::trace_processor {
namespace {
@@ -130,8 +147,8 @@
std::replace(fn_name.begin(), fn_name.end(), '.', '_');
RegisterFunction<metrics::BuildProto>(
engine, fn_name.c_str(), -1,
- std::unique_ptr<metrics::BuildProto::Context>(
- new metrics::BuildProto::Context{tp, pool, i}));
+ std::make_unique<metrics::BuildProto::Context>(
+ metrics::BuildProto::Context{tp, pool, i}));
}
}
@@ -169,24 +186,22 @@
// Note that sqlite3_aggregate_context zeros the memory for us so all the
// variables of the struct should be zero.
- ValueAtMaxTsContext* fn_ctx = reinterpret_cast<ValueAtMaxTsContext*>(
+ auto* fn_ctx = reinterpret_cast<ValueAtMaxTsContext*>(
sqlite3_aggregate_context(ctx, sizeof(ValueAtMaxTsContext)));
// For performance reasons, we only do the check for the type of ts and value
// on the first call of the function.
if (PERFETTO_UNLIKELY(!fn_ctx->initialized)) {
if (sqlite3_value_type(ts) != SQLITE_INTEGER) {
- sqlite3_result_error(ctx, "VALUE_AT_MAX_TS: ts passed was not an integer",
- -1);
- return;
+ return sqlite::result::Error(
+ ctx, "VALUE_AT_MAX_TS: ts passed was not an integer");
}
fn_ctx->value_type = sqlite3_value_type(value);
if (fn_ctx->value_type != SQLITE_INTEGER &&
fn_ctx->value_type != SQLITE_FLOAT) {
- sqlite3_result_error(
- ctx, "VALUE_AT_MAX_TS: value passed was not an integer or float", -1);
- return;
+ return sqlite::result::Error(
+ ctx, "VALUE_AT_MAX_TS: value passed was not an integer or float");
}
fn_ctx->max_ts = std::numeric_limits<int64_t>::min();
@@ -196,14 +211,12 @@
// On dcheck builds however, we check every passed ts and value.
#if PERFETTO_DCHECK_IS_ON()
if (sqlite3_value_type(ts) != SQLITE_INTEGER) {
- sqlite3_result_error(ctx, "VALUE_AT_MAX_TS: ts passed was not an integer",
- -1);
- return;
+ return sqlite::result::Error(
+ ctx, "VALUE_AT_MAX_TS: ts passed was not an integer");
}
if (sqlite3_value_type(value) != fn_ctx->value_type) {
- sqlite3_result_error(ctx, "VALUE_AT_MAX_TS: value type is inconsistent",
- -1);
- return;
+ return sqlite::result::Error(ctx,
+ "VALUE_AT_MAX_TS: value type is inconsistent");
}
#endif
@@ -223,13 +236,13 @@
ValueAtMaxTsContext* fn_ctx =
reinterpret_cast<ValueAtMaxTsContext*>(sqlite3_aggregate_context(ctx, 0));
if (!fn_ctx) {
- sqlite3_result_null(ctx);
+ sqlite::result::Null(ctx);
return;
}
if (fn_ctx->value_type == SQLITE_INTEGER) {
- sqlite3_result_int64(ctx, fn_ctx->int_value_at_max_ts);
+ sqlite::result::Long(ctx, fn_ctx->int_value_at_max_ts);
} else {
- sqlite3_result_double(ctx, fn_ctx->double_value_at_max_ts);
+ sqlite::result::Double(ctx, fn_ctx->double_value_at_max_ts);
}
}
@@ -318,27 +331,33 @@
TraceProcessorImpl::TraceProcessorImpl(const Config& cfg)
: TraceProcessorStorageImpl(cfg), config_(cfg) {
- context_.fuchsia_trace_tokenizer.reset(new FuchsiaTraceTokenizer(&context_));
- context_.fuchsia_trace_parser.reset(new FuchsiaTraceParser(&context_));
- context_.ninja_log_parser.reset(new NinjaLogParser(&context_));
- context_.systrace_trace_parser.reset(new SystraceTraceParser(&context_));
- context_.perf_data_trace_tokenizer.reset(
- new perf_importer::PerfDataTokenizer(&context_));
- context_.perf_data_parser.reset(new perf_importer::PerfDataParser(&context_));
+ context_.fuchsia_trace_tokenizer =
+ std::make_unique<FuchsiaTraceTokenizer>(&context_);
+ context_.fuchsia_trace_parser =
+ std::make_unique<FuchsiaTraceParser>(&context_);
+ context_.ninja_log_parser = std::make_unique<NinjaLogParser>(&context_);
+ context_.systrace_trace_parser =
+ std::make_unique<SystraceTraceParser>(&context_);
+ context_.perf_data_trace_tokenizer =
+ std::make_unique<perf_importer::PerfDataTokenizer>(&context_);
+ context_.perf_data_parser =
+ std::make_unique<perf_importer::PerfDataParser>(&context_);
if (util::IsGzipSupported()) {
- context_.gzip_trace_parser.reset(new GzipTraceParser(&context_));
- context_.android_bugreport_parser.reset(
- new AndroidBugreportParser(&context_));
+ context_.gzip_trace_parser = std::make_unique<GzipTraceParser>(&context_);
+ context_.android_bugreport_parser =
+ std::make_unique<AndroidBugreportParser>(&context_);
}
if (json::IsJsonSupported()) {
- context_.json_trace_tokenizer.reset(new JsonTraceTokenizer(&context_));
- context_.json_trace_parser.reset(new JsonTraceParser(&context_));
+ context_.json_trace_tokenizer =
+ std::make_unique<JsonTraceTokenizer>(&context_);
+ context_.json_trace_parser = std::make_unique<JsonTraceParser>(&context_);
}
if (context_.config.analyze_trace_proto_content) {
- context_.content_analyzer.reset(new ProtoContentAnalyzer(&context_));
+ context_.content_analyzer =
+ std::make_unique<ProtoContentAnalyzer>(&context_);
}
// Add metrics to descriptor pool
@@ -480,7 +499,8 @@
pool_.FindDescriptorIdx(".perfetto.protos.TraceMetrics");
if (!desc_idx.has_value())
return false;
- auto field_idx = pool_.descriptors()[*desc_idx].FindFieldByName(metric_name);
+ const auto* field_idx =
+ pool_.descriptors()[*desc_idx].FindFieldByName(metric_name);
return field_idx != nullptr;
}
@@ -661,10 +681,10 @@
1, engine_.get());
RegisterFunction<Import>(
engine_.get(), "IMPORT", 1,
- std::unique_ptr<Import::Context>(new Import::Context{engine_.get()}));
+ std::make_unique<Import::Context>(Import::Context{engine_.get()}));
RegisterFunction<ToFtrace>(
engine_.get(), "TO_FTRACE", 1,
- std::unique_ptr<ToFtrace::Context>(new ToFtrace::Context{
+ std::make_unique<ToFtrace::Context>(ToFtrace::Context{
context_.storage.get(), SystraceSerializer(&context_)}));
if constexpr (regex::IsRegexSupported()) {
@@ -673,9 +693,13 @@
// Old style function registration.
// TODO(lalitm): migrate this over to using RegisterFunction once aggregate
// functions are supported.
- RegisterLastNonNullFunction(db);
RegisterValueAtMaxTsFunction(db);
{
+ base::Status status = RegisterLastNonNullFunction(*engine_);
+ if (!status.ok())
+ PERFETTO_ELOG("%s", status.c_message());
+ }
+ {
base::Status status = RegisterStackFunctions(engine_.get(), &context_);
if (!status.ok())
PERFETTO_ELOG("%s", status.c_message());
@@ -686,17 +710,17 @@
PERFETTO_ELOG("%s", status.c_message());
}
{
- base::Status status = LayoutFunctions::Register(db, &context_);
+ base::Status status = RegisterLayoutFunctions(*engine_);
if (!status.ok())
PERFETTO_ELOG("%s", status.c_message());
}
{
- base::Status status = RegisterMathFunctions(*engine_.get());
+ base::Status status = RegisterMathFunctions(*engine_);
if (!status.ok())
PERFETTO_ELOG("%s", status.c_message());
}
{
- base::Status status = RegisterBase64Functions(*engine_.get());
+ base::Status status = RegisterBase64Functions(*engine_);
if (!status.ok())
PERFETTO_ELOG("%s", status.c_message());
}
@@ -744,8 +768,8 @@
"UNWRAP_METRIC_PROTO", 2);
RegisterFunction<metrics::RunMetric>(
engine_.get(), "RUN_METRIC", -1,
- std::unique_ptr<metrics::RunMetric::Context>(
- new metrics::RunMetric::Context{engine_.get(), &sql_metrics_}));
+ std::make_unique<metrics::RunMetric::Context>(
+ metrics::RunMetric::Context{engine_.get(), &sql_metrics_}));
// Legacy tables.
engine_->sqlite_engine()->RegisterVirtualTableModule<SqlStatsTable>(
@@ -855,42 +879,37 @@
RegisterStaticTable(storage->experimental_missing_chrome_processes_table());
// Tables dynamically generated at query time.
- engine_->RegisterStaticTableFunction(std::unique_ptr<ExperimentalFlamegraph>(
- new ExperimentalFlamegraph(&context_)));
- engine_->RegisterStaticTableFunction(std::unique_ptr<ExperimentalCounterDur>(
- new ExperimentalCounterDur(storage->counter_table())));
- engine_->RegisterStaticTableFunction(std::unique_ptr<ExperimentalSliceLayout>(
- new ExperimentalSliceLayout(context_.storage.get()->mutable_string_pool(),
- &storage->slice_table())));
- engine_->RegisterStaticTableFunction(std::unique_ptr<TableInfo>(new TableInfo(
- context_.storage.get()->mutable_string_pool(), engine_.get())));
- engine_->RegisterStaticTableFunction(std::unique_ptr<Ancestor>(
- new Ancestor(Ancestor::Type::kSlice, context_.storage.get())));
- engine_->RegisterStaticTableFunction(std::unique_ptr<Ancestor>(new Ancestor(
- Ancestor::Type::kStackProfileCallsite, context_.storage.get())));
- engine_->RegisterStaticTableFunction(std::unique_ptr<Ancestor>(
- new Ancestor(Ancestor::Type::kSliceByStack, context_.storage.get())));
- engine_->RegisterStaticTableFunction(std::unique_ptr<Descendant>(
- new Descendant(Descendant::Type::kSlice, context_.storage.get())));
- engine_->RegisterStaticTableFunction(std::unique_ptr<Descendant>(
- new Descendant(Descendant::Type::kSliceByStack, context_.storage.get())));
- engine_->RegisterStaticTableFunction(std::unique_ptr<ConnectedFlow>(
- new ConnectedFlow(ConnectedFlow::Mode::kDirectlyConnectedFlow,
- context_.storage.get())));
engine_->RegisterStaticTableFunction(
- std::unique_ptr<ConnectedFlow>(new ConnectedFlow(
- ConnectedFlow::Mode::kPrecedingFlow, context_.storage.get())));
+ std::make_unique<ExperimentalFlamegraph>(&context_));
engine_->RegisterStaticTableFunction(
- std::unique_ptr<ConnectedFlow>(new ConnectedFlow(
- ConnectedFlow::Mode::kFollowingFlow, context_.storage.get())));
+ std::make_unique<ExperimentalCounterDur>(storage->counter_table()));
engine_->RegisterStaticTableFunction(
- std::unique_ptr<ExperimentalSchedUpid>(new ExperimentalSchedUpid(
- storage->sched_slice_table(), storage->thread_table())));
+ std::make_unique<ExperimentalSliceLayout>(
+ context_.storage->mutable_string_pool(), &storage->slice_table()));
+ engine_->RegisterStaticTableFunction(std::make_unique<TableInfo>(
+ context_.storage->mutable_string_pool(), engine_.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<Ancestor>(
+ Ancestor::Type::kSlice, context_.storage.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<Ancestor>(
+ Ancestor::Type::kStackProfileCallsite, context_.storage.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<Ancestor>(
+ Ancestor::Type::kSliceByStack, context_.storage.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<Descendant>(
+ Descendant::Type::kSlice, context_.storage.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<Descendant>(
+ Descendant::Type::kSliceByStack, context_.storage.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<ConnectedFlow>(
+ ConnectedFlow::Mode::kDirectlyConnectedFlow, context_.storage.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<ConnectedFlow>(
+ ConnectedFlow::Mode::kPrecedingFlow, context_.storage.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<ConnectedFlow>(
+ ConnectedFlow::Mode::kFollowingFlow, context_.storage.get()));
+ engine_->RegisterStaticTableFunction(std::make_unique<ExperimentalSchedUpid>(
+ storage->sched_slice_table(), storage->thread_table()));
engine_->RegisterStaticTableFunction(
- std::unique_ptr<ExperimentalAnnotatedStack>(
- new ExperimentalAnnotatedStack(&context_)));
- engine_->RegisterStaticTableFunction(std::unique_ptr<ExperimentalFlatSlice>(
- new ExperimentalFlatSlice(&context_)));
+ std::make_unique<ExperimentalAnnotatedStack>(&context_));
+ engine_->RegisterStaticTableFunction(
+ std::make_unique<ExperimentalFlatSlice>(&context_));
engine_->RegisterStaticTableFunction(
std::make_unique<DominatorTree>(context_.storage->mutable_string_pool()));
engine_->RegisterStaticTableFunction(std::make_unique<IntervalIntersect>(
@@ -982,7 +1001,7 @@
base::FlatHashMap<std::string, uint64_t> interned_strings;
metatrace::DisableAndReadBuffer([&trace, &interned_strings](
metatrace::Record* record) {
- auto packet = trace->add_packet();
+ auto* packet = trace->add_packet();
packet->set_timestamp(record->timestamp_ns);
auto* evt = packet->set_perfetto_metatrace();
diff --git a/src/trace_processor/trace_processor_impl.h b/src/trace_processor/trace_processor_impl.h
index 4c08f23..249ceb9 100644
--- a/src/trace_processor/trace_processor_impl.h
+++ b/src/trace_processor/trace_processor_impl.h
@@ -29,7 +29,9 @@
#include "perfetto/base/status.h"
#include "perfetto/trace_processor/basic_types.h"
+#include "perfetto/trace_processor/trace_blob_view.h"
#include "perfetto/trace_processor/trace_processor.h"
+#include "src/trace_processor/iterator_impl.h"
#include "src/trace_processor/metrics/metrics.h"
#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
#include "src/trace_processor/perfetto_sql/intrinsics/functions/create_function.h"
diff --git a/test/trace_processor/diff_tests/tables/tests_sched.py b/test/trace_processor/diff_tests/tables/tests_sched.py
index 46ff428..71ca6ab 100644
--- a/test/trace_processor/diff_tests/tables/tests_sched.py
+++ b/test/trace_processor/diff_tests/tables/tests_sched.py
@@ -152,7 +152,6 @@
ts,
dur,
utid,
- waker_utid,
blocked_dur,
blocked_state,
blocked_function,
@@ -164,17 +163,17 @@
LIMIT 10
""",
out=Csv("""
- "root_id","parent_id","id","ts","dur","utid","waker_utid","blocked_dur","blocked_state","blocked_function","is_root","depth"
- 357,377,380,1735842234188,283571,46,427,351402620,"I","worker_thread",0,5
- 394,402,405,1735843726296,8545303,46,427,1208537,"I","worker_thread",0,3
- 357,419,432,1735850643698,16245,95,1465,154087,"I","worker_thread",0,4
- 357,443,446,1735851953029,554638012,95,427,1103252,"I","worker_thread",0,6
- 357,500,503,1735886367018,191863,46,427,34095419,"I","worker_thread",0,10
- 357,446,667,1736125372478,52493,46,95,238813597,"I","worker_thread",0,7
- 357,835,838,1736405409972,278036,46,427,279985001,"I","worker_thread",0,12
- 357,862,865,1736406817672,7959441,46,427,1129664,"I","worker_thread",0,10
- 357,882,889,1736413734042,25870,95,1467,7143001,"I","worker_thread",0,11
- 357,882,894,1736413763072,31692550,11,1467,4413060,"I","rcu_gp_fqs_loop",0,11
+ "root_id","parent_id","id","ts","dur","utid","blocked_dur","blocked_state","blocked_function","is_root","depth"
+ 357,377,380,1735842234188,283571,46,351402620,"I","worker_thread",0,5
+ 394,402,405,1735843726296,8545303,46,1208537,"I","worker_thread",0,3
+ 357,419,432,1735850643698,16245,95,154087,"I","worker_thread",0,4
+ 357,443,446,1735851953029,554638012,95,1103252,"I","worker_thread",0,6
+ 357,500,503,1735886367018,191863,46,34095419,"I","worker_thread",0,10
+ 357,446,667,1736125372478,52493,46,238813597,"I","worker_thread",0,7
+ 357,835,838,1736405409972,278036,46,279985001,"I","worker_thread",0,12
+ 357,862,865,1736406817672,7959441,46,1129664,"I","worker_thread",0,10
+ 357,882,889,1736413734042,25870,95,7143001,"I","worker_thread",0,11
+ 357,882,894,1736413763072,31692550,11,4413060,"I","rcu_gp_fqs_loop",0,11
"""))
def test_thread_executing_span_graph_contains_forked_states(self):
@@ -189,7 +188,6 @@
ts,
dur,
utid,
- waker_utid,
blocked_dur,
blocked_state,
blocked_function,
@@ -199,8 +197,8 @@
WHERE ts = 1735842081507 AND dur = 293868
""",
out=Csv("""
- "root_id","parent_id","id","ts","dur","utid","waker_utid","blocked_dur","blocked_state","blocked_function","is_root","depth"
- 357,369,376,1735842081507,293868,1465,230,"[NULL]","[NULL]","[NULL]",0,4
+ "root_id","parent_id","id","ts","dur","utid","blocked_dur","blocked_state","blocked_function","is_root","depth"
+ 357,369,376,1735842081507,293868,1465,"[NULL]","[NULL]","[NULL]",0,4
"""))
def test_thread_executing_span_runnable_state_has_no_running(self):
diff --git a/tools/check_sql_modules.py b/tools/check_sql_modules.py
index ff21b4f..935bf9e 100755
--- a/tools/check_sql_modules.py
+++ b/tools/check_sql_modules.py
@@ -44,10 +44,8 @@
'_chrome_mojo_slices', '_chrome_java_views', '_chrome_scheduler_tasks',
'_chrome_tasks'
],
- '/sched/thread_executing_span.sql': [
- '_wakeup', '_thread_executing_span_graph', '_critical_path',
- '_wakeup_graph', '_thread_executing_span_graph'
- ],
+ '/sched/thread_executing_span.sql': ['_wakeup_graph', '_thread_executing_span_graph',
+ '_critical_path'],
'/slices/flat_slices.sql': ['_slice_flattened']
}
diff --git a/tools/gen_android_bp b/tools/gen_android_bp
index 561657d..ba5320c 100755
--- a/tools/gen_android_bp
+++ b/tools/gen_android_bp
@@ -245,10 +245,6 @@
('test_suites', {'general-tests'}),
('test_config', 'PerfettoIntegrationTests.xml'),
],
- 'traced_probes': [('required', {
- 'libperfetto_android_internal', 'trigger_perfetto', 'traced_perf',
- 'mm_events'
- }),],
'libperfetto_android_internal': [('static_libs', {'libhealthhalutils'}),],
'trace_processor_shell': [
('strip', {