Merge "Create new sql function __instrinsic_strip_hex in perfetto sql" into main
diff --git a/Android.bp b/Android.bp
index 580c441..80b292a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -13680,6 +13680,7 @@
"src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.cc",
"src/trace_processor/perfetto_sql/intrinsics/functions/math.cc",
"src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc",
+ "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc",
"src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc",
"src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc",
"src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.cc",
diff --git a/BUILD b/BUILD
index 673451d..bcb91ef 100644
--- a/BUILD
+++ b/BUILD
@@ -2826,6 +2826,8 @@
"src/trace_processor/perfetto_sql/intrinsics/functions/math.h",
"src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.cc",
"src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.h",
+ "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc",
+ "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h",
"src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.cc",
"src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.h",
"src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.cc",
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn b/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
index 58d1ae6..2e6584d 100644
--- a/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/BUILD.gn
@@ -44,6 +44,8 @@
"math.h",
"pprof_functions.cc",
"pprof_functions.h",
+ "replace_numbers_function.cc",
+ "replace_numbers_function.h",
"sqlite3_str_split.cc",
"sqlite3_str_split.h",
"stack_functions.cc",
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc b/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc
new file mode 100644
index 0000000..5f79174
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2025 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.
+ */
+
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h"
+
+#include <stdlib.h>
+#include <cctype>
+#include <cstdint>
+#include <cstring>
+#include <string_view>
+
+#include "perfetto/base/status.h"
+#include "perfetto/trace_processor/basic_types.h"
+#include "protos/perfetto/trace_processor/stack.pbzero.h"
+#include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/sql_function.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/storage/trace_storage.h"
+#include "src/trace_processor/types/trace_processor_context.h"
+#include "src/trace_processor/util/status_macros.h"
+
+namespace perfetto {
+namespace trace_processor {
+namespace {
+
+// __instrinsic_strip_hex(name STRING, min_repeated_digits LONG)
+//
+// Replaces hexadecimal sequences (with at least one digit) in a string with
+// "<num>" based on specified criteria.
+struct StripHexFunction : public SqlFunction {
+ static constexpr char kFunctionName[] = "__instrinsic_strip_hex";
+
+ using Context = void;
+
+ static base::Status Run(void* cxt,
+ size_t argc,
+ sqlite3_value** argv,
+ SqlValue& out,
+ Destructors& destructors) {
+ base::Status status = RunImpl(cxt, argc, argv, out, destructors);
+ if (!status.ok()) {
+ return base::ErrStatus("%s: %s", kFunctionName, status.message().c_str());
+ }
+ return status;
+ }
+
+ static base::Status RunImpl(void*,
+ size_t argc,
+ sqlite3_value** argv,
+ SqlValue& out,
+ Destructors& destructors) {
+ if (argc != 2) {
+ return base::ErrStatus(
+ "%s; Invalid number of arguments: expected 2, actual %zu",
+ kFunctionName, argc);
+ }
+ std::optional<std::string> first_arg = sqlite::utils::SqlValueToString(
+ sqlite::utils::SqliteValueToSqlValue(argv[0]));
+ if (!first_arg.has_value()) {
+ return base::ErrStatus("Invalid name argument for %s expected string",
+ kFunctionName);
+ }
+ const std::string& input = first_arg.value();
+
+ SqlValue second_arg = sqlite::utils::SqliteValueToSqlValue(argv[1]);
+ if (second_arg.type != SqlValue::Type::kLong) {
+ return base::ErrStatus(
+ "Invalid min_repeated_digits argument for %s expected integer",
+ kFunctionName);
+ }
+
+ const int64_t min_repeated_digits = second_arg.AsLong();
+ if (min_repeated_digits < 0) {
+ return base::ErrStatus(
+ "Invalid min_repeated_digits argument for %s expected positive "
+ "integer",
+ kFunctionName);
+ }
+
+ base::StringView inputView = base::StringView(input);
+ constexpr std::array<const char*, 2> special_prefixes = {"0x", "0X"};
+ std::string result;
+ result.reserve(input.length());
+ for (size_t i = 0; i < input.length();) {
+ size_t prefix_len = 0;
+ for (const auto& special_prefix : special_prefixes) {
+ if (inputView.substr(i, strlen(special_prefix)) == special_prefix) {
+ prefix_len = strlen(special_prefix);
+ break;
+ }
+ }
+ if (prefix_len == 0 && !isalnum(input[i])) {
+ // Treat the current character as a prefix if no defined prefix was
+ // found and the character is non-alphanumeric.
+ prefix_len = 1;
+ }
+ if (prefix_len == 0) {
+ result += input[i++];
+ continue;
+ }
+ result += input.substr(i, prefix_len);
+
+ i += prefix_len;
+ size_t hex_start = i;
+ bool digit_found = false;
+ for (; i < input.length() && isxdigit(input[i]); i++) {
+ if (isdigit(input[i])) {
+ digit_found = true;
+ }
+ }
+ result += digit_found && (i - hex_start >=
+ static_cast<size_t>(min_repeated_digits))
+ ? "<num>"
+ : input.substr(hex_start, i - hex_start);
+ }
+ char* result_cstr = static_cast<char*>(malloc(result.length() + 1));
+ memcpy(result_cstr, result.c_str(), result.length() + 1);
+ out = SqlValue::String(result_cstr);
+ destructors.string_destructor = free;
+ return base::OkStatus();
+ }
+};
+
+} // namespace
+
+base::Status RegisterReplaceNumbersFunction(PerfettoSqlEngine* engine,
+ TraceProcessorContext* context) {
+ return engine->RegisterStaticFunction<StripHexFunction>(
+ StripHexFunction::kFunctionName, 2, context->storage.get());
+}
+
+} // namespace trace_processor
+} // namespace perfetto
diff --git a/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h b/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h
new file mode 100644
index 0000000..32964ee
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2025 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_PERFETTO_SQL_INTRINSICS_FUNCTIONS_REPLACE_NUMBERS_FUNCTION_H_
+#define SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_REPLACE_NUMBERS_FUNCTION_H_
+
+#include <sqlite3.h>
+
+#include "perfetto/base/status.h"
+
+namespace perfetto {
+namespace trace_processor {
+
+class PerfettoSqlEngine;
+class TraceProcessorContext;
+
+// Registers the following functions:
+//
+// __instrinsic_strip_hex(name STRING, min_repeated_digits LONG)
+//
+// Description:
+// Replaces hexadecimal sequences (with at least one digit) in a string with
+// "<num>" based on specified criteria.
+//
+// Parameters:
+// name STRING: The input string.
+// min_repeated_digits LONG: MINIMUM consecutive hex characters for
+// replacement.
+//
+// Replacement Criteria:
+// - Replaces hex/num sequences [0-9a-fA-F] with at least one occurrence of a
+// digit preceded by:
+// - Defined prefix ("0x", "0X")
+// - Non-alphanumeric character
+// - Whitespace character
+// - Replaces only sequences with length >= 'min_repeated_digits'.
+//
+// Return Value:
+// The string with replaced hex sequences.
+base::Status RegisterReplaceNumbersFunction(PerfettoSqlEngine* engine,
+ TraceProcessorContext* context);
+
+} // namespace trace_processor
+} // namespace perfetto
+
+#endif // SRC_TRACE_PROCESSOR_PERFETTO_SQL_INTRINSICS_FUNCTIONS_REPLACE_NUMBERS_FUNCTION_H_
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/slices.sql b/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
index ecd9884..b288512 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/slices.sql
@@ -225,7 +225,7 @@
-- E.g. +job=1234:"com.google.android.apps.internal.betterbug"
-- To +job=<...>:"com.google.android.apps.internal.betterbug"
WHEN $name GLOB "[+-a-z]*=[0-9]*:*" OR $name GLOB "[a-z]*=[0-9]*:*"
- THEN substr($name, 1, instr($name, "=")) || "=<...>:" || substr($name, instr($name, ":") + 1)
+ THEN substr($name, 1, instr($name, "=")) || "<...>:" || substr($name, instr($name, ":") + 1)
-- E.g. InputConsumer processing on ea6145 NotificationShade (0xb000000000000000)
-- To InputConsumer processing on <...> NotificationShade (<...>)
-- E.g. InputConsumer processing on [Gesture Monitor] swipe-up (0xb000000000000000)
@@ -258,7 +258,7 @@
THEN CASE
WHEN $name GLOB "Transaction (Thread-*, *)"
THEN substr($name, 1, instr($name, "(")) || "Thread-<...>," || substr($name, instr($name, ","), length($name))
- ELSE substr($name, 1, instr($name, ",") + 1) || " <...>)"
+ ELSE substr($name, 1, instr($name, ",") + 1) || "<...>)"
END
-- E.g. FrameBuffer-201#invokeListeners-non-direct
-- To: FrameBuffer-<...>#invokeListeners-non-direct
@@ -281,5 +281,7 @@
-- To: Handler: android.os.AsyncTask
WHEN $name GLOB "*.*$*: #*"
THEN "Handler: " || _remove_lambda_name($name)
- ELSE $name
+ WHEN $name GLOB "deliverInputEvent*"
+ THEN "deliverInputEvent <...>"
+ ELSE __instrinsic_strip_hex($name, 3)
END;
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index 94b1cd0..0020280 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -96,6 +96,7 @@
#include "src/trace_processor/perfetto_sql/intrinsics/functions/layout_functions.h"
#include "src/trace_processor/perfetto_sql/intrinsics/functions/math.h"
#include "src/trace_processor/perfetto_sql/intrinsics/functions/pprof_functions.h"
+#include "src/trace_processor/perfetto_sql/intrinsics/functions/replace_numbers_function.h"
#include "src/trace_processor/perfetto_sql/intrinsics/functions/sqlite3_str_split.h"
#include "src/trace_processor/perfetto_sql/intrinsics/functions/stack_functions.h"
#include "src/trace_processor/perfetto_sql/intrinsics/functions/structural_tree_partition.h"
@@ -985,6 +986,12 @@
PERFETTO_FATAL("%s", status.c_message());
}
{
+ base::Status status =
+ RegisterReplaceNumbersFunction(engine_.get(), &context_);
+ if (!status.ok())
+ PERFETTO_FATAL("%s", status.c_message());
+ }
+ {
base::Status status = PprofFunctions::Register(*engine_, &context_);
if (!status.ok())
PERFETTO_FATAL("%s", status.c_message());
diff --git a/test/trace_processor/diff_tests/stdlib/android/android_slice_standardization.py b/test/trace_processor/diff_tests/stdlib/android/android_slice_standardization.py
index aaa1bd3..f081464 100644
--- a/test/trace_processor/diff_tests/stdlib/android/android_slice_standardization.py
+++ b/test/trace_processor/diff_tests/stdlib/android/android_slice_standardization.py
@@ -36,10 +36,8 @@
"LoadApkAssetsFd({ParcelFileDescriptor: java.io.FileDescriptor@340019d})",
"relayoutWindow#first=false/resize=false/vis=true/params=true/force=false",
"android.os.Handler: kotlinx.coroutines.CancellableContinuationImpl",
- "Choreographer#doFrame 122932914",
- "DrawFrames 122921845",
- "/data/app/.../base.apk",
- "OpenDexFilesFromOat(/data/app/.../base.apk)",
+ "Choreographer#doFrame 122932914", "DrawFrames 122921845",
+ "/data/app/.../base.apk", "OpenDexFilesFromOat(/data/app/.../base.apk)",
"Open oat file /data/misc/apexdata/com.android.art/dalvik-cache/boot.oat",
"android.os.Handler: kotlinx.coroutines.internal.DispatchedContinuation",
"GC: Wait For Completion Alloc",
@@ -48,6 +46,17 @@
'android.os.Handler: com.android.systemui.broadcast.ActionReceiver$1$1',
'com.android.keyguard.KeyguardUpdateMonitor$13: #302',
'android.os.Handler: com.android.systemui.qs.TileServiceManager$1',
+ 'FrameBuffer-201#invokeListeners-non-direct',
+ 'Transaction (ptz-fgd-1-LOCAL_MEDIA_REMOVE_DELETED_ITEMS_SYNC, 11910)',
+ 'InputConsumer processing on ClientState{e1d234a mUid=1234 mPid=1234 '
+ 'mSelfReportedDisplayId=0} (0xb000000000000000)',
+ 'InputConsumer processing on [Gesture Monitor] swipe-up '
+ '(0xb000000000000000)',
+ '+job=1234:"com.google.android.apps.internal.betterbug"',
+ 'Looper.dispatch: android.app.ActivityThread$H(runnable@a9f7a84'
+ '(android.app.ActivityThread@1d57743,40))', 'Not changed at ALL 01',
+ 'Three digits to replace 123 1234', 'kworker/1d57743',
+ 'ImageDecoder#decodeDrawable'
]
for name in slices_to_standardize:
diff --git a/test/trace_processor/diff_tests/stdlib/android/tests.py b/test/trace_processor/diff_tests/stdlib/android/tests.py
index 1e66136..62dd43a 100644
--- a/test/trace_processor/diff_tests/stdlib/android/tests.py
+++ b/test/trace_processor/diff_tests/stdlib/android/tests.py
@@ -249,6 +249,16 @@
"Handler: com.android.systemui.broadcast.ActionReceiver"
"Handler: com.android.keyguard.KeyguardUpdateMonitor"
"Handler: com.android.systemui.qs.TileServiceManager"
+ "FrameBuffer-<...>#invokeListeners-non-direct"
+ "Transaction (ptz-fgd-1-LOCAL_MEDIA_REMOVE_DELETED_ITEMS_SYNC, <...>)"
+ "InputConsumer processing on ClientState{<...>} (<...>)"
+ "InputConsumer processing on [Gesture Monitor] swipe-up (<...>)"
+ "+job=<...>:"com.google.android.apps.internal.betterbug""
+ "Looper.dispatch: android.app.ActivityThread$H(runnable@<num>(android.app.ActivityThread@<num>,40))"
+ "Not changed at ALL 01"
+ "Three digits to replace <num> <num>"
+ "kworker/<num>"
+ "ImageDecoder#decodeDrawable"
"""))
def test_monitor_contention_extraction(self):