Merge "[metrics] Add pid and tids to android_monitor_contention metric"
diff --git a/Android.bp b/Android.bp
index 2196b71..91b7f78 100644
--- a/Android.bp
+++ b/Android.bp
@@ -10038,6 +10038,7 @@
"src/trace_processor/metrics/sql/android/java_heap_histogram.sql",
"src/trace_processor/metrics/sql/android/java_heap_stats.sql",
"src/trace_processor/metrics/sql/android/mem_stats_priority_breakdown.sql",
+ "src/trace_processor/metrics/sql/android/network_activity_template.sql",
"src/trace_processor/metrics/sql/android/p_state.sql",
"src/trace_processor/metrics/sql/android/power_drain_in_watts.sql",
"src/trace_processor/metrics/sql/android/power_profile_data.sql",
diff --git a/BUILD b/BUILD
index 0f0551b..195292f 100644
--- a/BUILD
+++ b/BUILD
@@ -1787,6 +1787,7 @@
"src/trace_processor/metrics/sql/android/java_heap_histogram.sql",
"src/trace_processor/metrics/sql/android/java_heap_stats.sql",
"src/trace_processor/metrics/sql/android/mem_stats_priority_breakdown.sql",
+ "src/trace_processor/metrics/sql/android/network_activity_template.sql",
"src/trace_processor/metrics/sql/android/p_state.sql",
"src/trace_processor/metrics/sql/android/power_drain_in_watts.sql",
"src/trace_processor/metrics/sql/android/power_profile_data.sql",
diff --git a/docs/quickstart/chrome-tracing.md b/docs/quickstart/chrome-tracing.md
index 4e17172..6786b4d 100644
--- a/docs/quickstart/chrome-tracing.md
+++ b/docs/quickstart/chrome-tracing.md
@@ -4,6 +4,8 @@
> To record traces from Chrome on Android, follow the [instructions for recording Android system traces](/docs/quickstart/android-tracing.md) and enable the Chrome probe.
+>> If you are using [user build of Android](https://source.android.com/docs/setup/build/building#lunch), you'll have to enable integration with system Perfetto by switching chrome://flags#enable-perfetto-system-tracing to "Enabled" and restarting Chrome.
+
## Recording a trace
1. Navigate to [ui.perfetto.dev](https://ui.perfetto.dev/) and select **"Record new trace"** from the left menu.
diff --git a/include/perfetto/protozero/proto_decoder.h b/include/perfetto/protozero/proto_decoder.h
index 2210532..c27fcad 100644
--- a/include/perfetto/protozero/proto_decoder.h
+++ b/include/perfetto/protozero/proto_decoder.h
@@ -340,7 +340,8 @@
uint32_t field_id,
bool* parse_error_location) const {
const Field& field = Get(field_id);
- if (field.valid()) {
+ if (field.valid() &&
+ field.type() == proto_utils::ProtoWireType::kLengthDelimited) {
return PackedRepeatedFieldIterator<wire_type, cpp_type>(
field.data(), field.size(), parse_error_location);
}
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index aa107e2..e886311 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -11344,7 +11344,7 @@
// Deliberate empty message. See comment on StatsdAtom#atom below.
message Atom {}
-// One or more statsd atoms. Ideally this should continue to match:
+// One or more statsd atoms. This must continue to match:
// perfetto/protos/third_party/statsd/shell_data.proto
// So that we can efficiently add data from statsd directly to the
// trace.
diff --git a/protos/perfetto/trace/statsd/statsd_atom.proto b/protos/perfetto/trace/statsd/statsd_atom.proto
index 026766d..62ca960 100644
--- a/protos/perfetto/trace/statsd/statsd_atom.proto
+++ b/protos/perfetto/trace/statsd/statsd_atom.proto
@@ -20,7 +20,7 @@
// Deliberate empty message. See comment on StatsdAtom#atom below.
message Atom {}
-// One or more statsd atoms. Ideally this should continue to match:
+// One or more statsd atoms. This must continue to match:
// perfetto/protos/third_party/statsd/shell_data.proto
// So that we can efficiently add data from statsd directly to the
// trace.
diff --git a/protos/third_party/chromium/chrome_track_event.proto b/protos/third_party/chromium/chrome_track_event.proto
index 1f5a211..cce5e76 100644
--- a/protos/third_party/chromium/chrome_track_event.proto
+++ b/protos/third_party/chromium/chrome_track_event.proto
@@ -513,7 +513,10 @@
optional int32 browsing_instance_id = 1;
// The ID of the CoopRelatedGroup that the BrowsingContextState belongs to.
- optional int32 coop_related_group_id = 2;
+ optional int32 coop_related_group_id = 2 [deprecated = true];
+
+ // The token of the CoopRelatedGroup that the BrowsingContextState belongs to.
+ optional string coop_related_group_token = 3;
// Additional untyped debug information associated with this
// FrameTreeNode, populated via TracedProto::AddDebugAnnotations API.
diff --git a/protos/third_party/statsd/shell_data.proto b/protos/third_party/statsd/shell_data.proto
index e4c31bd..64551ea 100644
--- a/protos/third_party/statsd/shell_data.proto
+++ b/protos/third_party/statsd/shell_data.proto
@@ -20,8 +20,8 @@
// This is a manual import of ShellData:
// https://cs.android.com/android/platform/superproject/+/master:packages/modules/StatsD/statsd/src/shell/shell_data.proto;l=27;drc=d2e51ecdf08753688fb889b657dcba60adb994f3
-
+// This must exactly match perfetto.protos.StatsdAtom.
message ShellData {
repeated bytes atom = 1;
- repeated int64 timestamp_nanos = 2 [packed = true];
+ repeated int64 timestamp_nanos = 2;
}
diff --git a/src/protozero/proto_decoder_unittest.cc b/src/protozero/proto_decoder_unittest.cc
index 0991f88..1e962d7 100644
--- a/src/protozero/proto_decoder_unittest.cc
+++ b/src/protozero/proto_decoder_unittest.cc
@@ -592,5 +592,26 @@
ASSERT_FALSE(field.valid());
}
+// Check what happens when trying to parse packed repeated field and finding a
+// mismatching wire type instead. A compliant protobuf decoder should accept it,
+// but protozero doesn't handle that. At least it shouldn't crash.
+TEST(ProtoDecoderTest, PacketRepeatedWireTypeMismatch) {
+ protozero::HeapBuffered<pbtest::PackedRepeatedFields> message;
+ // A proper packed encoding should have a length delimited wire type. Use a
+ // var int wire type instead.
+ constexpr int kFieldId = pbtest::PackedRepeatedFields::kFieldInt32FieldNumber;
+ message->AppendTinyVarInt(kFieldId, 5);
+ auto data = message.SerializeAsArray();
+
+ pbtest::PackedRepeatedFields::Decoder decoder(data.data(), data.size());
+ bool parse_error = false;
+ auto it = decoder.field_int32(&parse_error);
+ // The decoder doesn't return a parse error (maybe it should, but that has
+ // been the behavior since the beginning).
+ ASSERT_FALSE(parse_error);
+ // But the iterator returns 0 elements.
+ EXPECT_FALSE(it);
+}
+
} // namespace
} // namespace protozero
diff --git a/src/tools/ftrace_proto_gen/ftrace_proto_gen.cc b/src/tools/ftrace_proto_gen/ftrace_proto_gen.cc
index f692373..712e3d1 100644
--- a/src/tools/ftrace_proto_gen/ftrace_proto_gen.cc
+++ b/src/tools/ftrace_proto_gen/ftrace_proto_gen.cc
@@ -191,6 +191,11 @@
// configurations)
if (group == "ftrace" && proto.event_name == "print" && field->name == "ip")
continue;
+ // Ignore the "nid" field. On new kernels, this field has a type that we
+ // don't know how to parse. See b/281660544
+ if (group == "f2fs" && proto.event_name == "f2fs_truncate_partial_nodes" &&
+ field->name == "nid")
+ continue;
s += "{";
s += "kUnsetOffset, ";
s += "kUnsetSize, ";
diff --git a/src/trace_processor/db/sorting_overlay.h b/src/trace_processor/db/sorting_overlay.h
index 4d490e3..7b536a1 100644
--- a/src/trace_processor/db/sorting_overlay.h
+++ b/src/trace_processor/db/sorting_overlay.h
@@ -31,8 +31,8 @@
class SortingOverlay : public ColumnOverlay {
public:
explicit SortingOverlay(ColumnOverlay* ancestor);
- void Filter(FilterOp, SqlValue, RowMap&) override;
- void StableSort(uint32_t* rows_order, uint32_t rows_size) override;
+ void Filter(FilterOp, SqlValue, RowMap&) const override;
+ void StableSort(uint32_t* rows_order, uint32_t rows_size) const override;
private:
std::unique_ptr<ColumnOverlay> inner_;
diff --git a/src/trace_processor/metrics/sql/android/BUILD.gn b/src/trace_processor/metrics/sql/android/BUILD.gn
index bf54d44..a566661 100644
--- a/src/trace_processor/metrics/sql/android/BUILD.gn
+++ b/src/trace_processor/metrics/sql/android/BUILD.gn
@@ -82,6 +82,7 @@
"java_heap_histogram.sql",
"java_heap_stats.sql",
"mem_stats_priority_breakdown.sql",
+ "network_activity_template.sql",
"p_state.sql",
"power_drain_in_watts.sql",
"power_profile_data.sql",
diff --git a/src/trace_processor/metrics/sql/android/network_activity_template.sql b/src/trace_processor/metrics/sql/android/network_activity_template.sql
new file mode 100644
index 0000000..2dcfa31
--- /dev/null
+++ b/src/trace_processor/metrics/sql/android/network_activity_template.sql
@@ -0,0 +1,74 @@
+--
+-- Copyright 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
+--
+-- https://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.
+
+SELECT IMPORT('android.network_packets');
+
+-- Creates a view of aggregated network activity. It is common among networking
+-- to have the interface active for some time after network use. For example, in
+-- mobile networking, it is common to have the cellular interface active for 10
+-- or more seconds after the last packet was sent or received. This view takes
+-- raw packet timing and aggregates it into something that approximates the
+-- activity of the underlying interface.
+--
+-- @arg view_name The name of the output view.
+-- @arg group_by Expression to group by (set to 'null' for no grouping).
+-- @arg filter Expression on `android_network_packets` to filter by.
+-- @arg idle_ns The amount of time before considering the network idle.
+-- @arg quant_ns Quantization value, to group rows before the heavy
+-- part of the query. This should be smaller than idle_ns.
+--
+-- @column group_by The group_by columns are all present in the output.
+-- @column ts The timestamp indicating the start of the segment.
+-- @column dur The duration of the current segment.
+-- @column packet_count The total number of packets in this segment.
+-- @column packet_length The total number of bytes for packets in this segment.
+CREATE VIEW {{view_name}} AS
+WITH quantized AS (
+ SELECT
+ {{group_by}},
+ MIN(ts) AS ts,
+ MAX(ts+dur)-MIN(ts) AS dur,
+ SUM(packet_count) AS packet_count,
+ SUM(packet_length) AS packet_length
+ FROM android_network_packets
+ WHERE {{filter}}
+ GROUP BY CAST(ts / {{quant_ns}} AS INT64), {{group_by}}
+),
+with_last AS (
+ SELECT
+ *,
+ LAG(ts) OVER (
+ PARTITION BY {{group_by}}
+ ORDER BY ts
+ ) AS last_ts
+ FROM quantized
+),
+with_group AS (
+ SELECT
+ *,
+ COUNT(IIF(ts-last_ts>{{idle_ns}}, 1, null)) OVER (
+ PARTITION BY {{group_by}}
+ ORDER BY ts
+ ) AS group_id
+ FROM with_last
+)
+SELECT
+ {{group_by}},
+ MIN(ts) AS ts,
+ MAX(ts+dur)-MIN(ts)+{{idle_ns}} AS dur,
+ SUM(packet_count) AS packet_count,
+ SUM(packet_length) AS packet_length
+FROM with_group
+GROUP BY group_id, {{group_by}}
diff --git a/src/trace_processor/prelude/functions/utils.h b/src/trace_processor/prelude/functions/utils.h
index 21fed04..ac848d0 100644
--- a/src/trace_processor/prelude/functions/utils.h
+++ b/src/trace_processor/prelude/functions/utils.h
@@ -19,6 +19,7 @@
#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"
@@ -26,9 +27,9 @@
#include "src/trace_processor/export_json.h"
#include "src/trace_processor/importers/common/clock_tracker.h"
#include "src/trace_processor/prelude/functions/create_function_internal.h"
-#include "src/trace_processor/util/status_macros.h"
-
#include "src/trace_processor/prelude/functions/sql_function.h"
+#include "src/trace_processor/sqlite/sqlite_utils.h"
+#include "src/trace_processor/util/status_macros.h"
namespace perfetto {
namespace trace_processor {
diff --git a/src/trace_processor/sqlite/sqlite_engine.h b/src/trace_processor/sqlite/sqlite_engine.h
index 2ec82e0..2af8b81 100644
--- a/src/trace_processor/sqlite/sqlite_engine.h
+++ b/src/trace_processor/sqlite/sqlite_engine.h
@@ -130,11 +130,11 @@
private:
struct FnHasher {
- uint64_t operator()(const std::pair<std::string, int>& x) const {
+ size_t operator()(const std::pair<std::string, int>& x) const {
base::Hasher hasher;
hasher.Update(x.first);
hasher.Update(x.second);
- return hasher.digest();
+ return static_cast<size_t>(hasher.digest());
}
};
diff --git a/src/trace_processor/stdlib/android/battery_stats.sql b/src/trace_processor/stdlib/android/battery_stats.sql
index 753fd61..2507cb1 100644
--- a/src/trace_processor/stdlib/android/battery_stats.sql
+++ b/src/trace_processor/stdlib/android/battery_stats.sql
@@ -21,7 +21,7 @@
-- @arg value LONG The counter value.
-- @ret STRING The human-readable name for the counter value.
SELECT CREATE_FUNCTION(
- 'BATTERY_STATS_COUNTER_TO_STRING(track STRING, value LONG)',
+ 'BATTERY_STATS_COUNTER_TO_STRING(track STRING, value FLOAT)',
'STRING',
'
SELECT
@@ -125,16 +125,16 @@
--
-- @column ts Timestamp in nanoseconds.
-- @column dur The duration the state was active.
--- @column name The name of the counter track.
+-- @column track_name The name of the counter track.
-- @column value The counter value as a number.
-- @column value_name The counter value as a human-readable string.
CREATE VIEW android_battery_stats_state AS
SELECT
ts,
- name,
- value,
- BATTERY_STATS_VALUE_TO_STRING(name, value) AS value_name,
- LEAD(ts, 1, TRACE_END()) OVER (PARTITION BY track_id ORDER BY ts) - ts AS dur
+ name AS track_name,
+ CAST(value AS INT64) AS value,
+ BATTERY_STATS_COUNTER_TO_STRING(name, value) AS value_name,
+ IFNULL(LEAD(ts) OVER (PARTITION BY track_id ORDER BY ts) - ts, -1) AS dur
FROM counter
JOIN counter_track
ON counter.track_id = counter_track.id
diff --git a/src/trace_processor/stdlib/android/process_metadata.sql b/src/trace_processor/stdlib/android/process_metadata.sql
index 20fb82e..6154f00 100644
--- a/src/trace_processor/stdlib/android/process_metadata.sql
+++ b/src/trace_processor/stdlib/android/process_metadata.sql
@@ -50,11 +50,19 @@
LEFT JOIN internal_uid_package_count ON process.android_appid = internal_uid_package_count.uid
LEFT JOIN package_list plist
ON (
- process.android_appid = plist.uid
- AND internal_uid_package_count.uid = plist.uid
- AND (
- -- unique match
- internal_uid_package_count.cnt = 1
- -- or process name starts with the package name
- OR process.name GLOB plist.package_name || '*')
+ (
+ process.android_appid = plist.uid
+ AND internal_uid_package_count.uid = plist.uid
+ AND (
+ -- unique match
+ internal_uid_package_count.cnt = 1
+ -- or process name starts with the package name
+ OR process.name GLOB plist.package_name || '*')
+ )
+ OR
+ (
+ -- isolated processes can only be matched based on the name prefix
+ process.android_appid >= 90000 AND process.android_appid < 100000
+ AND STR_SPLIT(process.name, ':', 0) GLOB plist.package_name || '*'
+ )
);
diff --git a/src/trace_processor/trace_processor_impl.cc b/src/trace_processor/trace_processor_impl.cc
index f00c7fa..f64b1c1 100644
--- a/src/trace_processor/trace_processor_impl.cc
+++ b/src/trace_processor/trace_processor_impl.cc
@@ -596,7 +596,7 @@
// Legacy tables.
engine_.RegisterVirtualTableModule<SqlStatsTable>(
- "sql_stats", storage, SqliteTable::TableType::kEponymousOnly, false);
+ "sqlstats", storage, SqliteTable::TableType::kEponymousOnly, false);
engine_.RegisterVirtualTableModule<StatsTable>(
"stats", storage, SqliteTable::TableType::kEponymousOnly, false);
diff --git a/src/traced/probes/ftrace/cpu_reader_unittest.cc b/src/traced/probes/ftrace/cpu_reader_unittest.cc
index 459b640..859cc8b 100644
--- a/src/traced/probes/ftrace/cpu_reader_unittest.cc
+++ b/src/traced/probes/ftrace/cpu_reader_unittest.cc
@@ -34,6 +34,7 @@
#include "test/gtest_and_gmock.h"
#include "protos/perfetto/trace/ftrace/dpu.gen.h"
+#include "protos/perfetto/trace/ftrace/f2fs.gen.h"
#include "protos/perfetto/trace/ftrace/ftrace.gen.h"
#include "protos/perfetto/trace/ftrace/ftrace_event.gen.h"
#include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
@@ -62,6 +63,7 @@
using testing::Pair;
using testing::Property;
using testing::Return;
+using testing::SizeIs;
using testing::StartsWith;
namespace perfetto {
@@ -3303,5 +3305,113 @@
EXPECT_THAT(AllTracePackets(), IsEmpty());
}
+// Kernel code:
+// trace_f2fs_truncate_partial_nodes(... nid = {1,2,3}, depth = 4, err = 0)
+//
+// After kernel commit 0b04d4c0542e("f2fs: Fix
+// f2fs_truncate_partial_nodes ftrace event")
+static ExamplePage g_f2fs_truncate_partial_nodes_new{
+ "b281660544_new",
+ R"(
+00000000: 1555 c3e4 cb07 0000 3c00 0000 0000 0000 .U......<.......
+00000010: 3e33 0b87 2700 0000 0c00 0000 7d02 0000 >3..'.......}...
+00000020: c638 0000 3900 e00f 0000 0000 b165 0000 .8..9........e..
+00000030: 0000 0000 0100 0000 0200 0000 0300 0000 ................
+00000040: 0400 0000 0000 0000 0000 0000 0000 0000 ................
+ )",
+};
+
+TEST_F(CpuReaderParsePagePayloadTest, F2fsTruncatePartialNodesNew) {
+ const ExamplePage* test_case = &g_f2fs_truncate_partial_nodes_new;
+
+ ProtoTranslationTable* table = GetTable(test_case->name);
+ auto page = PageFromXxd(test_case->data);
+
+ FtraceDataSourceConfig ds_config = EmptyConfig();
+ ds_config.event_filter.AddEnabledEvent(table->EventToFtraceId(
+ GroupAndName("f2fs", "f2fs_truncate_partial_nodes")));
+
+ const uint8_t* parse_pos = page.get();
+ std::optional<CpuReader::PageHeader> page_header =
+ CpuReader::ParsePageHeader(&parse_pos, table->page_header_size_len());
+
+ const uint8_t* page_end = page.get() + base::kPageSize;
+ ASSERT_TRUE(page_header.has_value());
+ EXPECT_FALSE(page_header->lost_events);
+ EXPECT_LE(parse_pos + page_header->size, page_end);
+
+ size_t evt_bytes = CpuReader::ParsePagePayload(
+ parse_pos, &page_header.value(), table, &ds_config,
+ CreateBundler(ds_config), &metadata_);
+
+ EXPECT_LT(0u, evt_bytes);
+
+ auto bundle = GetBundle();
+ ASSERT_THAT(bundle.event(), SizeIs(1));
+ auto& event = bundle.event()[0];
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().dev(), 65081u);
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().ino(), 26033u);
+ // This field is disabled in ftrace_proto_gen.cc
+ EXPECT_FALSE(event.f2fs_truncate_partial_nodes().has_nid());
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().depth(), 4);
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().err(), 0);
+}
+
+// Kernel code:
+// trace_f2fs_truncate_partial_nodes(... nid = {1,2,3}, depth = 4, err = 0)
+//
+// Before kernel commit 0b04d4c0542e("f2fs: Fix
+// f2fs_truncate_partial_nodes ftrace event")
+static ExamplePage g_f2fs_truncate_partial_nodes_old{
+ "b281660544_old",
+ R"(
+00000000: 8f90 aa0d 9e00 0000 3c00 0000 0000 0000 ........<.......
+00000010: 3e97 0295 0e01 0000 0c00 0000 7d02 0000 >...........}...
+00000020: 8021 0000 3900 e00f 0000 0000 0d66 0000 .!..9........f..
+00000030: 0000 0000 0100 0000 0200 0000 0300 0000 ................
+00000040: 0400 0000 0000 0000 0000 0000 0000 0000 ................
+ )",
+};
+
+TEST_F(CpuReaderParsePagePayloadTest, F2fsTruncatePartialNodesOld) {
+ const ExamplePage* test_case = &g_f2fs_truncate_partial_nodes_old;
+
+ ProtoTranslationTable* table = GetTable(test_case->name);
+ auto page = PageFromXxd(test_case->data);
+
+ FtraceDataSourceConfig ds_config = EmptyConfig();
+ auto id = table->EventToFtraceId(
+ GroupAndName("f2fs", "f2fs_truncate_partial_nodes"));
+ PERFETTO_LOG("Enabling: %zu", id);
+ ds_config.event_filter.AddEnabledEvent(id);
+
+ const uint8_t* parse_pos = page.get();
+ std::optional<CpuReader::PageHeader> page_header =
+ CpuReader::ParsePageHeader(&parse_pos, table->page_header_size_len());
+
+ const uint8_t* page_end = page.get() + base::kPageSize;
+ ASSERT_TRUE(page_header.has_value());
+ EXPECT_FALSE(page_header->lost_events);
+ EXPECT_LE(parse_pos + page_header->size, page_end);
+
+ size_t evt_bytes = CpuReader::ParsePagePayload(
+ parse_pos, &page_header.value(), table, &ds_config,
+ CreateBundler(ds_config), &metadata_);
+
+ EXPECT_LT(0u, evt_bytes);
+
+ auto bundle = GetBundle();
+ ASSERT_THAT(bundle.event(), SizeIs(1));
+ auto& event = bundle.event()[0];
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().dev(), 65081u);
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().ino(), 26125u);
+ // This field is disabled in ftrace_proto_gen.cc
+ EXPECT_FALSE(event.f2fs_truncate_partial_nodes().has_nid());
+ // Due to a kernel bug, nid[1] is parsed as depth.
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().depth(), 2);
+ // Due to a kernel bug, nid[2] is parsed as err.
+ EXPECT_EQ(event.f2fs_truncate_partial_nodes().err(), 3);
+}
+
} // namespace
} // namespace perfetto
diff --git a/src/traced/probes/ftrace/event_info.cc b/src/traced/probes/ftrace/event_info.cc
index f17f6b6..6a8cca3 100644
--- a/src/traced/probes/ftrace/event_info.cc
+++ b/src/traced/probes/ftrace/event_info.cc
@@ -4266,9 +4266,6 @@
"ino", 2, ProtoSchemaType::kUint64,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
- "nid", 3, ProtoSchemaType::kUint32,
- TranslationStrategy::kInvalidTranslationStrategy},
- {kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
"depth", 4, ProtoSchemaType::kInt32,
TranslationStrategy::kInvalidTranslationStrategy},
{kUnsetOffset, kUnsetSize, FtraceFieldType::kInvalidFtraceFieldType,
diff --git a/src/traced/probes/ftrace/test/data/b281660544_new/available_events b/src/traced/probes/ftrace/test/data/b281660544_new/available_events
new file mode 100644
index 0000000..5588a96
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_new/available_events
@@ -0,0 +1 @@
+f2fs:f2fs_truncate_partial_nodes
diff --git a/src/traced/probes/ftrace/test/data/b281660544_new/events/f2fs/f2fs_truncate_partial_nodes/format b/src/traced/probes/ftrace/test/data/b281660544_new/events/f2fs/f2fs_truncate_partial_nodes/format
new file mode 100644
index 0000000..2f5a8ab
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_new/events/f2fs/f2fs_truncate_partial_nodes/format
@@ -0,0 +1,15 @@
+name: f2fs_truncate_partial_nodes
+ID: 637
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:dev_t dev; offset:8; size:4; signed:0;
+ field:ino_t ino; offset:16; size:8; signed:0;
+ field:nid_t nid[3]; offset:24; size:12; signed:0;
+ field:int depth; offset:36; size:4; signed:1;
+ field:int err; offset:40; size:4; signed:1;
+
+print fmt: "dev = (%d,%d), ino = %lu, nid[0] = %u, nid[1] = %u, nid[2] = %u, depth = %d, err = %d", ((unsigned int) ((REC->dev) >> 20)), ((unsigned int) ((REC->dev) & ((1U << 20) - 1))), (unsigned long)REC->ino, (unsigned int)REC->nid[0], (unsigned int)REC->nid[1], (unsigned int)REC->nid[2], REC->depth, REC->err
diff --git a/src/traced/probes/ftrace/test/data/b281660544_new/events/header_page b/src/traced/probes/ftrace/test/data/b281660544_new/events/header_page
new file mode 100644
index 0000000..276dce9
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_new/events/header_page
@@ -0,0 +1,4 @@
+ field: u64 timestamp; offset:0; size:8; signed:0;
+ field: local_t commit; offset:8; size:8; signed:1;
+ field: int overwrite; offset:8; size:1; signed:1;
+ field: char data; offset:16; size:4080; signed:1;
diff --git a/src/traced/probes/ftrace/test/data/b281660544_old/available_events b/src/traced/probes/ftrace/test/data/b281660544_old/available_events
new file mode 100644
index 0000000..5588a96
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_old/available_events
@@ -0,0 +1 @@
+f2fs:f2fs_truncate_partial_nodes
diff --git a/src/traced/probes/ftrace/test/data/b281660544_old/events/f2fs/f2fs_truncate_partial_nodes/format b/src/traced/probes/ftrace/test/data/b281660544_old/events/f2fs/f2fs_truncate_partial_nodes/format
new file mode 100644
index 0000000..15f6a64
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_old/events/f2fs/f2fs_truncate_partial_nodes/format
@@ -0,0 +1,15 @@
+name: f2fs_truncate_partial_nodes
+ID: 637
+format:
+ field:unsigned short common_type; offset:0; size:2; signed:0;
+ field:unsigned char common_flags; offset:2; size:1; signed:0;
+ field:unsigned char common_preempt_count; offset:3; size:1; signed:0;
+ field:int common_pid; offset:4; size:4; signed:1;
+
+ field:dev_t dev; offset:8; size:4; signed:0;
+ field:ino_t ino; offset:16; size:8; signed:0;
+ field:nid_t nid[3]; offset:24; size:4; signed:0;
+ field:int depth; offset:28; size:4; signed:1;
+ field:int err; offset:32; size:4; signed:1;
+
+print fmt: "dev = (%d,%d), ino = %lu, nid[0] = %u, nid[1] = %u, nid[2] = %u, depth = %d, err = %d", ((unsigned int) ((REC->dev) >> 20)), ((unsigned int) ((REC->dev) & ((1U << 20) - 1))), (unsigned long)REC->ino, (unsigned int)REC->nid[0], (unsigned int)REC->nid[1], (unsigned int)REC->nid[2], REC->depth, REC->err
diff --git a/src/traced/probes/ftrace/test/data/b281660544_old/events/header_page b/src/traced/probes/ftrace/test/data/b281660544_old/events/header_page
new file mode 100644
index 0000000..276dce9
--- /dev/null
+++ b/src/traced/probes/ftrace/test/data/b281660544_old/events/header_page
@@ -0,0 +1,4 @@
+ field: u64 timestamp; offset:0; size:8; signed:0;
+ field: local_t commit; offset:8; size:8; signed:1;
+ field: int overwrite; offset:8; size:1; signed:1;
+ field: char data; offset:16; size:4080; signed:1;
diff --git a/src/traced/probes/statsd_client/statsd_binder_data_source.cc b/src/traced/probes/statsd_client/statsd_binder_data_source.cc
index 627d4bc..9d3d7f7 100644
--- a/src/traced/probes/statsd_client/statsd_binder_data_source.cc
+++ b/src/traced/probes/statsd_client/statsd_binder_data_source.cc
@@ -242,30 +242,20 @@
const uint8_t* data,
size_t sz) {
ShellDataDecoder message(data, sz);
+ if (message.has_atom()) {
+ TraceWriter::TracePacketHandle packet = writer_->NewTracePacket();
- bool parse_error = false;
- auto timestamps_it = message.timestamp_nanos(&parse_error);
- std::vector<int64_t> timestamps;
- if (!parse_error) {
- for (; timestamps_it; ++timestamps_it) {
- timestamps.push_back(*timestamps_it);
- }
+ // The root packet gets the timestamp of *now* to aid in
+ // a) Packet sorting in trace_processor
+ // b) So we have some useful record of timestamp in case the statsd
+ // one gets broken in some exciting way.
+ packet->set_timestamp(static_cast<uint64_t>(base::GetBootTimeNs().count()));
- TraceWriter::TracePacketHandle packet;
- size_t i = 0;
- for (auto it = message.atom(); it; ++it) {
- packet = writer_->NewTracePacket();
- if (i < timestamps.size()) {
- packet->set_timestamp(static_cast<uint64_t>(timestamps[i++]));
- } else {
- packet->set_timestamp(
- static_cast<uint64_t>(base::GetBootTimeNs().count()));
- }
- auto* statsd_atom = packet->set_statsd_atom();
- auto* atom = statsd_atom->add_atom();
- atom->AppendRawProtoBytes(it->data(), it->size());
- packet->Finalize();
- }
+ // Now put all the data. We rely on ShellData and StatsdAtom
+ // matching format exactly.
+ packet->AppendBytes(protos::pbzero::TracePacket::kStatsdAtomFieldNumber,
+ message.begin(),
+ static_cast<size_t>(message.end() - message.begin()));
}
// If we have the pending flush in progress resolve that:
diff --git a/src/tracing/core/tracing_service_impl.cc b/src/tracing/core/tracing_service_impl.cc
index f04f67f..b32a658 100644
--- a/src/tracing/core/tracing_service_impl.cc
+++ b/src/tracing/core/tracing_service_impl.cc
@@ -3637,6 +3637,7 @@
cloned_session->flushes_requested = src->flushes_requested;
cloned_session->flushes_succeeded = src->flushes_succeeded;
cloned_session->flushes_failed = src->flushes_failed;
+ cloned_session->compress_deflate = src->compress_deflate;
if (src->trace_filter) {
// Copy the trace filter.
cloned_session->trace_filter.reset(
diff --git a/src/tracing/core/tracing_service_impl_unittest.cc b/src/tracing/core/tracing_service_impl_unittest.cc
index c6d7384..fb175e9 100644
--- a/src/tracing/core/tracing_service_impl_unittest.cc
+++ b/src/tracing/core/tracing_service_impl_unittest.cc
@@ -1922,6 +1922,74 @@
&protos::gen::TracePacket::for_testing,
Property(&protos::gen::TestEvent::str, Eq("payload-2")))));
}
+
+TEST_F(TracingServiceImplTest, CloneSessionWithCompression) {
+ TracingService::InitOpts init_opts;
+ init_opts.compressor_fn = ZlibCompressFn;
+ InitializeSvcWithOpts(init_opts);
+
+ // The consumer the creates the initial tracing session.
+ std::unique_ptr<MockConsumer> consumer = CreateMockConsumer();
+ consumer->Connect(svc.get());
+
+ // The consumer that clones it and reads back the data.
+ std::unique_ptr<MockConsumer> consumer2 = CreateMockConsumer();
+ consumer2->Connect(svc.get());
+
+ std::unique_ptr<MockProducer> producer = CreateMockProducer();
+ producer->Connect(svc.get(), "mock_producer");
+
+ producer->RegisterDataSource("ds_1");
+
+ TraceConfig trace_config;
+ trace_config.add_buffers()->set_size_kb(32);
+ auto* ds_cfg = trace_config.add_data_sources()->mutable_config();
+ ds_cfg->set_name("ds_1");
+ trace_config.set_compression_type(TraceConfig::COMPRESSION_TYPE_DEFLATE);
+
+ consumer->EnableTracing(trace_config);
+ producer->WaitForTracingSetup();
+
+ producer->WaitForDataSourceSetup("ds_1");
+
+ producer->WaitForDataSourceStart("ds_1");
+
+ std::unique_ptr<TraceWriter> writer = producer->CreateTraceWriter("ds_1");
+
+ // Add some data.
+ static constexpr size_t kNumTestPackets = 20;
+ for (size_t i = 0; i < kNumTestPackets; i++) {
+ auto tp = writer->NewTracePacket();
+ std::string payload("payload" + std::to_string(i));
+ tp->set_for_testing()->set_str(payload.c_str(), payload.size());
+ tp->set_timestamp(static_cast<uint64_t>(i));
+ }
+
+ auto clone_done = task_runner.CreateCheckpoint("clone_done");
+ EXPECT_CALL(*consumer2, OnSessionCloned(_))
+ .WillOnce(Invoke([clone_done](const Consumer::OnSessionClonedArgs&) {
+ clone_done();
+ }));
+ consumer2->CloneSession(1);
+ // CloneSession() will implicitly issue a flush. Linearize with that.
+ producer->WaitForFlush(std::vector<TraceWriter*>{writer.get()});
+ task_runner.RunUntilCheckpoint("clone_done");
+
+ // Delete the initial tracing session.
+ consumer->DisableTracing();
+ consumer->FreeBuffers();
+ producer->WaitForDataSourceStop("ds_1");
+ consumer->WaitForTracingDisabled();
+
+ // Read back the cloned trace and check that it's compressed
+ std::vector<protos::gen::TracePacket> compressed_packets =
+ consumer2->ReadBuffers();
+ EXPECT_THAT(compressed_packets, Not(IsEmpty()));
+ EXPECT_THAT(compressed_packets,
+ Each(Property(&protos::gen::TracePacket::compressed_packets,
+ Not(IsEmpty()))));
+}
+
#endif // PERFETTO_BUILDFLAG(PERFETTO_ZLIB)
// Note: file_write_period_ms is set to a large enough to have exactly one flush
diff --git a/test/trace_processor/diff_tests/android/android_battery_stats_state.out b/test/trace_processor/diff_tests/android/android_battery_stats_state.out
new file mode 100644
index 0000000..04ea953
--- /dev/null
+++ b/test/trace_processor/diff_tests/android/android_battery_stats_state.out
@@ -0,0 +1,4 @@
+"ts","track_name","value","value_name","dur"
+1000,"battery_stats.audio",1,"active",-1
+1000,"battery_stats.data_conn",13,"lte",3000
+4000,"battery_stats.data_conn",20,"nr",-1
diff --git a/test/trace_processor/diff_tests/android/android_network_activity.out b/test/trace_processor/diff_tests/android/android_network_activity.out
new file mode 100644
index 0000000..14418e4
--- /dev/null
+++ b/test/trace_processor/diff_tests/android/android_network_activity.out
@@ -0,0 +1,4 @@
+"package_name","ts","dur","packet_count","packet_length"
+"uid=123",1000,1010,2,100
+"uid=123",3000,2500,4,200
+"uid=456",1005,1010,2,300
diff --git a/test/trace_processor/diff_tests/android/tests.py b/test/trace_processor/diff_tests/android/tests.py
index cec98ae..84bafc1 100644
--- a/test/trace_processor/diff_tests/android/tests.py
+++ b/test/trace_processor/diff_tests/android/tests.py
@@ -159,6 +159,109 @@
""",
out=Path('android_battery_stats_event_slices.out'))
+ def test_android_battery_stats_counters(self):
+ return DiffTestBlueprint(
+ trace=TextProto(r"""
+ packet {
+ ftrace_events {
+ cpu: 1
+ event {
+ timestamp: 1000
+ pid: 1
+ print {
+ buf: "C|1000|battery_stats.data_conn|13\n"
+ }
+ }
+ event {
+ timestamp: 4000
+ pid: 1
+ print {
+ buf: "C|1000|battery_stats.data_conn|20\n"
+ }
+ }
+ event {
+ timestamp: 1000
+ pid: 1
+ print {
+ buf: "C|1000|battery_stats.audio|1\n"
+ }
+ }
+ }
+ }
+ """),
+ query="""
+ SELECT IMPORT('android.battery_stats');
+ SELECT * FROM android_battery_stats_state
+ ORDER BY ts, track_name;
+ """,
+ out=Path('android_battery_stats_state.out'))
+
+ def test_android_network_activity(self):
+ # The following should have three activity regions:
+ # * uid=123 from 1000 to 2010 (note: end is max(ts)+idle_ns)
+ # * uid=456 from 1005 to 2015 (note: doesn't group with above due to name)
+ # * uid=123 from 3000 to 5500 (note: gap between 1010 to 3000 > idle_ns)
+ # Note: packet_timestamps are delta encoded from the base timestamp.
+ return DiffTestBlueprint(
+ trace=TextProto(r"""
+ packet {
+ timestamp: 0
+ network_packet_bundle {
+ ctx {
+ direction: DIR_EGRESS
+ interface: "wlan"
+ uid: 123
+ }
+ packet_timestamps: [
+ 1000, 1010,
+ 3000, 3050, 4000, 4500
+ ],
+ packet_lengths: [
+ 50, 50,
+ 50, 50, 50, 50
+ ],
+ }
+ }
+ packet {
+ timestamp: 0
+ network_packet_bundle {
+ ctx {
+ direction: DIR_EGRESS
+ interface: "wlan"
+ uid: 456
+ }
+ packet_timestamps: [1005, 1015]
+ packet_lengths: [100, 200]
+ }
+ }
+ packet {
+ timestamp: 0
+ network_packet_bundle {
+ ctx {
+ direction: DIR_INGRESS
+ interface: "loopback"
+ uid: 123
+ }
+ packet_timestamps: [6000]
+ packet_lengths: [100]
+ }
+ }
+ """),
+ query="""
+ SELECT RUN_METRIC(
+ 'android/network_activity_template.sql',
+ 'view_name', 'android_network_activity',
+ 'group_by', 'package_name',
+ 'filter', 'iface = "wlan"',
+ 'idle_ns', '1000',
+ 'quant_ns', '100'
+ );
+
+ SELECT * FROM android_network_activity
+ ORDER BY package_name, ts;
+ """,
+ out=Path('android_network_activity.out'))
+
def test_binder_sync_binder_metrics(self):
return DiffTestBlueprint(
trace=DataPath('android_binder_metric_trace.atr'),