Merge changes Icbf2f808,I973cd662 into main
* changes:
Trace Redaction - Use Three Stage Pattern In Collect Primitive
Trace Redaction - Clean up "find package uid" primitive
diff --git a/Android.bp b/Android.bp
index 43d2027..40484c4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12380,6 +12380,7 @@
"src/trace_processor/perfetto_sql/stdlib/android/dvfs.sql",
"src/trace_processor/perfetto_sql/stdlib/android/frames/per_frame_metrics.sql",
"src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql",
"src/trace_processor/perfetto_sql/stdlib/android/freezer.sql",
"src/trace_processor/perfetto_sql/stdlib/android/garbage_collection.sql",
"src/trace_processor/perfetto_sql/stdlib/android/input.sql",
diff --git a/BUILD b/BUILD
index 2b53c16..4e316ed 100644
--- a/BUILD
+++ b/BUILD
@@ -2392,6 +2392,7 @@
srcs = [
"src/trace_processor/perfetto_sql/stdlib/android/frames/per_frame_metrics.sql",
"src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql",
+ "src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql",
],
)
diff --git a/protos/perfetto/metrics/android/java_heap_stats.proto b/protos/perfetto/metrics/android/java_heap_stats.proto
index 10a0b8b..5163f41 100644
--- a/protos/perfetto/metrics/android/java_heap_stats.proto
+++ b/protos/perfetto/metrics/android/java_heap_stats.proto
@@ -26,7 +26,7 @@
optional int64 obj_count = 3;
}
- // Next id: 11
+ // Next id: 12
message Sample {
optional int64 ts = 1;
// Size of the Java heap in bytes
@@ -47,6 +47,8 @@
repeated HeapRoots roots = 7;
// OOM adjustment score
optional int64 oom_score_adj = 10;
+ // Process uptime in millis at the time of the heap dump
+ optional int64 process_uptime_ms = 11;
}
// Heap stats per process. One sample per dump (can be > 1 if continuous
diff --git a/protos/perfetto/metrics/perfetto_merged_metrics.proto b/protos/perfetto/metrics/perfetto_merged_metrics.proto
index 14a2847..6b7a611 100644
--- a/protos/perfetto/metrics/perfetto_merged_metrics.proto
+++ b/protos/perfetto/metrics/perfetto_merged_metrics.proto
@@ -1417,7 +1417,7 @@
optional int64 obj_count = 3;
}
- // Next id: 11
+ // Next id: 12
message Sample {
optional int64 ts = 1;
// Size of the Java heap in bytes
@@ -1438,6 +1438,8 @@
repeated HeapRoots roots = 7;
// OOM adjustment score
optional int64 oom_score_adj = 10;
+ // Process uptime in millis at the time of the heap dump
+ optional int64 process_uptime_ms = 11;
}
// Heap stats per process. One sample per dump (can be > 1 if continuous
diff --git a/python/generators/diff_tests/runner.py b/python/generators/diff_tests/runner.py
index b3c9fe9..7c77d54 100644
--- a/python/generators/diff_tests/runner.py
+++ b/python/generators/diff_tests/runner.py
@@ -28,7 +28,8 @@
from python.generators.diff_tests.testing import TestCase, TestType, BinaryProto
from python.generators.diff_tests.utils import (
ColorFormatter, create_message_factory, get_env, get_trace_descriptor_path,
- read_all_tests, serialize_python_trace, serialize_textproto_trace)
+ read_all_tests, serialize_python_trace, serialize_textproto_trace,
+ modify_trace)
ROOT_DIR = os.path.dirname(
os.path.dirname(
@@ -327,6 +328,19 @@
with open(gen_trace_file.name, 'w') as trace_file:
trace_file.write(self.test.blueprint.trace.contents)
+ if self.test.blueprint.trace_modifier is not None:
+ if gen_trace_file:
+ # Overwrite |gen_trace_file|.
+ modify_trace(self.trace_descriptor_path, extension_descriptor_paths,
+ gen_trace_file.name, gen_trace_file.name,
+ self.test.blueprint.trace_modifier)
+ else:
+ # Create |gen_trace_file| to save the modified trace.
+ gen_trace_file = tempfile.NamedTemporaryFile(delete=False)
+ modify_trace(self.trace_descriptor_path, extension_descriptor_paths,
+ self.test.trace_path, gen_trace_file.name,
+ self.test.blueprint.trace_modifier)
+
if gen_trace_file:
trace_path = os.path.realpath(gen_trace_file.name)
else:
diff --git a/python/generators/diff_tests/testing.py b/python/generators/diff_tests/testing.py
index 8a4f45e..515f956 100644
--- a/python/generators/diff_tests/testing.py
+++ b/python/generators/diff_tests/testing.py
@@ -16,7 +16,7 @@
import inspect
import os
from dataclasses import dataclass
-from typing import List, Union, Callable
+from typing import Any, Dict, List, Union, Callable
from enum import Enum
import re
@@ -72,6 +72,42 @@
contents: str
+class TraceInjector:
+ '''Injects fields into trace packets before test starts.
+
+ TraceInjector can be used within a DiffTestBlueprint to selectively inject
+ fields to trace packets containing specific data types. For example:
+
+ DiffTestBlueprint(
+ trace=...,
+ trace_modifier=TraceInjector('ftrace_events',
+ 'sys_stats',
+ 'process_tree',
+ {'machine_id': 1001},
+ trusted_uid=123)
+ query=...,
+ out=...)
+
+ packet_data_types: Data types to target for injection ('ftrace_events',
+ 'sys_stats', 'process_tree')
+ injected_fields: Fields and their values to inject into matching packets
+ ({'machine_id': 1001}, trusted_uid=123).
+ '''
+
+ def __init__(self, packet_data_types: List[str], injected_fields: Dict[str,
+ Any]):
+ self.packet_data_types = packet_data_types
+ self.injected_fields = injected_fields
+
+ def inject(self, proto):
+ for p in proto.packet:
+ for f in self.packet_data_types:
+ if p.HasField(f):
+ for k, v, in self.injected_fields.items():
+ setattr(p, k, v)
+ continue
+
+
class TestType(Enum):
QUERY = 1
METRIC = 2
@@ -86,6 +122,7 @@
trace: Union[Path, DataPath, Json, Systrace, TextProto]
query: Union[str, Path, DataPath, Metric]
out: Union[Path, DataPath, Json, Csv, TextProto, BinaryProto]
+ trace_modifier: Union[TraceInjector, None] = None
def is_trace_file(self):
return isinstance(self.trace, Path)
diff --git a/python/generators/diff_tests/utils.py b/python/generators/diff_tests/utils.py
index cb447fd..3101637 100644
--- a/python/generators/diff_tests/utils.py
+++ b/python/generators/diff_tests/utils.py
@@ -149,6 +149,23 @@
return trace_descriptor_path
+def modify_trace(trace_descriptor_path, extension_descriptor_paths,
+ in_trace_path, out_trace_path, modifier):
+ trace_proto = create_message_factory([trace_descriptor_path] +
+ extension_descriptor_paths,
+ 'perfetto.protos.Trace')()
+
+ with open(in_trace_path, "rb") as f:
+ # This may raise DecodeError when |in_trace_path| isn't protobuf.
+ trace_proto.ParseFromString(f.read())
+ # Modify the trace proto object with the provided modifier function.
+ modifier.inject(trace_proto)
+
+ with open(out_trace_path, "wb") as f:
+ f.write(trace_proto.SerializeToString())
+ f.flush()
+
+
def read_all_tests(name_filter: str, root_dir: str) -> List[testing.TestCase]:
# Import
INCLUDE_PATH = os.path.join(root_dir, 'test', 'trace_processor', 'diff_tests')
diff --git a/python/perfetto/trace_processor/metrics.descriptor b/python/perfetto/trace_processor/metrics.descriptor
index 6a137a9..cc4850f 100644
--- a/python/perfetto/trace_processor/metrics.descriptor
+++ b/python/perfetto/trace_processor/metrics.descriptor
Binary files differ
diff --git a/src/trace_processor/importers/perf/perf_data_parser.cc b/src/trace_processor/importers/perf/perf_data_parser.cc
index 71912f2..83f8800 100644
--- a/src/trace_processor/importers/perf/perf_data_parser.cc
+++ b/src/trace_processor/importers/perf/perf_data_parser.cc
@@ -43,7 +43,7 @@
base::StatusOr<PerfDataTracker::PerfSample> PerfDataParser::ParseSample(
TraceBlobView tbv) {
- perf_importer::Reader reader(std::move(tbv));
+ perf_importer::PerfDataReader reader(std::move(tbv));
return tracker_->ParseSample(reader);
}
diff --git a/src/trace_processor/importers/perf/perf_data_reader.cc b/src/trace_processor/importers/perf/perf_data_reader.cc
index a2c7691..e061826 100644
--- a/src/trace_processor/importers/perf/perf_data_reader.cc
+++ b/src/trace_processor/importers/perf/perf_data_reader.cc
@@ -25,7 +25,7 @@
namespace perfetto {
namespace trace_processor {
namespace perf_importer {
-void Reader::SkipSlow(size_t bytes_to_skip) {
+void PerfDataReader::SkipSlow(size_t bytes_to_skip) {
size_t bytes_in_buffer = BytesInBuffer();
// Size fits in buffer.
@@ -40,7 +40,7 @@
blob_offset_ += bytes_to_skip - bytes_in_buffer;
}
-void Reader::PeekSlow(uint8_t* obj_data, size_t size) const {
+void PerfDataReader::PeekSlow(uint8_t* obj_data, size_t size) const {
size_t bytes_in_buffer = BytesInBuffer();
// Read from buffer.
@@ -55,7 +55,7 @@
size - bytes_in_buffer);
}
-TraceBlobView Reader::PeekTraceBlobViewSlow(size_t size) const {
+TraceBlobView PerfDataReader::PeekTraceBlobViewSlow(size_t size) const {
auto blob = TraceBlob::Allocate(size);
size_t bytes_in_buffer = BytesInBuffer();
diff --git a/src/trace_processor/importers/perf/perf_data_reader.h b/src/trace_processor/importers/perf/perf_data_reader.h
index 86f1c6b..acf07d1 100644
--- a/src/trace_processor/importers/perf/perf_data_reader.h
+++ b/src/trace_processor/importers/perf/perf_data_reader.h
@@ -35,10 +35,10 @@
// it's design is not related to perf. Responsible for hiding away the
// complexity of reading values from TraceBlobView and glueing the tbvs together
// in case there is data between many of them.
-class Reader {
+class PerfDataReader {
public:
- Reader() = default;
- explicit Reader(TraceBlobView tbv) : tbv_(std::move(tbv)) {}
+ PerfDataReader() = default;
+ explicit PerfDataReader(TraceBlobView tbv) : tbv_(std::move(tbv)) {}
// Updates old TraceBlobView with new one. If there is data left in the old
// one, it will be saved in the buffer.
diff --git a/src/trace_processor/importers/perf/perf_data_reader_unittest.cc b/src/trace_processor/importers/perf/perf_data_reader_unittest.cc
index 61c866c..5bf3081 100644
--- a/src/trace_processor/importers/perf/perf_data_reader_unittest.cc
+++ b/src/trace_processor/importers/perf/perf_data_reader_unittest.cc
@@ -37,7 +37,7 @@
TEST(PerfDataReaderUnittest, AppendToEmpty) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{1, 2, 3});
- Reader reader;
+ PerfDataReader reader;
EXPECT_FALSE(reader.CanReadSize(1));
reader.Append(std::move(tbv));
EXPECT_TRUE(reader.CanReadSize(sizeof(uint64_t) * 2));
@@ -45,7 +45,7 @@
TEST(PerfDataReaderUnittest, Append) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{1, 2, 3});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
EXPECT_TRUE(reader.CanReadSize(sizeof(uint64_t) * 3));
EXPECT_FALSE(reader.CanReadSize(sizeof(uint64_t) * 3 + 1));
@@ -56,7 +56,7 @@
TEST(PerfDataReaderUnittest, Read) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 8});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
uint64_t val;
reader.Read(val);
EXPECT_EQ(val, 2u);
@@ -64,7 +64,7 @@
TEST(PerfDataReaderUnittest, ReadFromBuffer) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 6});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Append(TraceBlobViewFromVector(std::vector<uint64_t>{1, 3}));
// Now the first vector should be in the buffer.
@@ -75,7 +75,7 @@
TEST(PerfDataReaderUnittest, ReadBetweenBufferAndBlob) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Append(TraceBlobViewFromVector(std::vector<uint64_t>{1, 3, 5}));
struct Nums {
@@ -94,7 +94,7 @@
TEST(PerfDataReaderUnittest, ReadOptional) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 8});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
std::optional<uint64_t> val;
reader.ReadOptional(val);
EXPECT_EQ(val, 2u);
@@ -103,7 +103,7 @@
TEST(PerfDataReaderUnittest, ReadVector) {
TraceBlobView tbv =
TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 8, 16, 32});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
std::vector<uint64_t> res(3);
reader.ReadVector(res);
@@ -114,7 +114,7 @@
TEST(PerfDataReaderUnittest, Skip) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 8});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Skip<uint64_t>();
@@ -125,7 +125,7 @@
TEST(PerfDataReaderUnittest, SkipInBuffer) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Append(TraceBlobViewFromVector(std::vector<uint64_t>{1, 3, 5}));
reader.Skip<uint64_t>();
@@ -134,7 +134,7 @@
TEST(PerfDataReaderUnittest, SkipBetweenBufferAndBlob) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Append(TraceBlobViewFromVector(std::vector<uint64_t>{1, 3, 5}));
struct Nums {
@@ -149,7 +149,7 @@
TEST(PerfDataReaderUnittest, Peek) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 8});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
uint64_t peek_val;
reader.Peek(peek_val);
@@ -161,7 +161,7 @@
TEST(PerfDataReaderUnittest, PeekFromBuffer) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 6});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Append(TraceBlobViewFromVector(std::vector<uint64_t>{1, 3}));
uint64_t val;
@@ -171,7 +171,7 @@
TEST(PerfDataReaderUnittest, PeekBetweenBufferAndBlob) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Append(TraceBlobViewFromVector(std::vector<uint64_t>{1, 3, 5}));
struct Nums {
@@ -190,40 +190,40 @@
TEST(PerfDataReaderUnittest, GetTraceBlobView) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 8});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
EXPECT_TRUE(reader.CanReadSize(sizeof(uint64_t) * 3));
TraceBlobView new_tbv = reader.PeekTraceBlobView(sizeof(uint64_t) * 2);
- Reader new_reader(std::move(new_tbv));
+ PerfDataReader new_reader(std::move(new_tbv));
EXPECT_TRUE(new_reader.CanReadSize(sizeof(uint64_t) * 2));
EXPECT_FALSE(new_reader.CanReadSize(sizeof(uint64_t) * 3));
}
TEST(PerfDataReaderUnittest, GetTraceBlobViewFromBuffer) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Append(TraceBlobViewFromVector(std::vector<uint64_t>{1, 3, 5}));
TraceBlobView new_tbv = reader.PeekTraceBlobView(sizeof(uint64_t) * 2);
- Reader new_reader(std::move(new_tbv));
+ PerfDataReader new_reader(std::move(new_tbv));
EXPECT_TRUE(new_reader.CanReadSize(sizeof(uint64_t) * 2));
EXPECT_FALSE(new_reader.CanReadSize(sizeof(uint64_t) * 3));
}
TEST(PerfDataReaderUnittest, GetTraceBlobViewFromBetweenBufferAndBlob) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
reader.Append(TraceBlobViewFromVector(std::vector<uint64_t>{1, 3, 5}));
TraceBlobView new_tbv = reader.PeekTraceBlobView(sizeof(uint64_t) * 3);
- Reader new_reader(std::move(new_tbv));
+ PerfDataReader new_reader(std::move(new_tbv));
EXPECT_TRUE(new_reader.CanReadSize(sizeof(uint64_t) * 3));
EXPECT_FALSE(new_reader.CanReadSize(sizeof(uint64_t) * 4));
}
TEST(PerfDataReaderUnittest, CanAccessFileRange) {
TraceBlobView tbv = TraceBlobViewFromVector(std::vector<uint64_t>{2, 4, 8});
- Reader reader(std::move(tbv));
+ PerfDataReader reader(std::move(tbv));
EXPECT_TRUE(reader.CanAccessFileRange(2, sizeof(uint64_t) * 3));
EXPECT_FALSE(reader.CanAccessFileRange(2, sizeof(uint64_t) * 3 + 10));
}
diff --git a/src/trace_processor/importers/perf/perf_data_tokenizer.h b/src/trace_processor/importers/perf/perf_data_tokenizer.h
index 1fa4277..7a54088 100644
--- a/src/trace_processor/importers/perf/perf_data_tokenizer.h
+++ b/src/trace_processor/importers/perf/perf_data_tokenizer.h
@@ -100,7 +100,7 @@
uint64_t ids_end_ = 0;
std::vector<uint8_t> after_header_buffer_;
- perf_importer::Reader reader_;
+ perf_importer::PerfDataReader reader_;
};
} // namespace perf_importer
diff --git a/src/trace_processor/importers/perf/perf_data_tracker.cc b/src/trace_processor/importers/perf/perf_data_tracker.cc
index c670258..8b3bc47 100644
--- a/src/trace_processor/importers/perf/perf_data_tracker.cc
+++ b/src/trace_processor/importers/perf/perf_data_tracker.cc
@@ -101,7 +101,7 @@
}
base::StatusOr<PerfDataTracker::PerfSample> PerfDataTracker::ParseSample(
- perfetto::trace_processor::perf_importer::Reader& reader) {
+ perfetto::trace_processor::perf_importer::PerfDataReader& reader) {
uint64_t sample_type = common_sample_type();
PerfDataTracker::PerfSample sample;
diff --git a/src/trace_processor/importers/perf/perf_data_tracker.h b/src/trace_processor/importers/perf/perf_data_tracker.h
index 11258ed..c96b08d 100644
--- a/src/trace_processor/importers/perf/perf_data_tracker.h
+++ b/src/trace_processor/importers/perf/perf_data_tracker.h
@@ -98,7 +98,7 @@
uint64_t common_sample_type() { return common_sample_type_; }
base::StatusOr<PerfSample> ParseSample(
- perfetto::trace_processor::perf_importer::Reader&);
+ perfetto::trace_processor::perf_importer::PerfDataReader&);
private:
const perf_event_attr* FindAttrWithId(uint64_t id) const;
diff --git a/src/trace_processor/importers/perf/perf_data_tracker_unittest.cc b/src/trace_processor/importers/perf/perf_data_tracker_unittest.cc
index 129271c..923473f 100644
--- a/src/trace_processor/importers/perf/perf_data_tracker_unittest.cc
+++ b/src/trace_processor/importers/perf/perf_data_tracker_unittest.cc
@@ -121,7 +121,7 @@
TraceBlob blob =
TraceBlob::CopyFrom(static_cast<const void*>(&ts), sizeof(uint64_t));
- Reader reader(TraceBlobView(std::move(blob)));
+ PerfDataReader reader(TraceBlobView(std::move(blob)));
auto parsed_sample = tracker->ParseSample(reader);
EXPECT_TRUE(parsed_sample.ok());
@@ -149,7 +149,7 @@
memcpy(blob.data(), &sample.callchain_size, sizeof(uint64_t));
memcpy(blob.data() + sizeof(uint64_t), sample.callchain.data(),
sizeof(uint64_t) * 3);
- Reader reader(TraceBlobView(std::move(blob)));
+ PerfDataReader reader(TraceBlobView(std::move(blob)));
auto parsed_sample = tracker->ParseSample(reader);
EXPECT_TRUE(parsed_sample.ok());
@@ -185,7 +185,7 @@
memcpy(blob.data(), &sample, sizeof(Sample));
memcpy(blob.data() + sizeof(Sample), callchain.data(), sizeof(uint64_t) * 3);
- Reader reader(TraceBlobView(std::move(blob)));
+ PerfDataReader reader(TraceBlobView(std::move(blob)));
EXPECT_TRUE(reader.CanReadSize(sizeof(Sample)));
auto parsed_sample = tracker->ParseSample(reader);
@@ -229,7 +229,7 @@
memcpy(blob.data(), &sample, sizeof(Sample));
memcpy(blob.data() + sizeof(Sample), callchain.data(), sizeof(uint64_t) * 3);
- Reader reader(TraceBlobView(std::move(blob)));
+ PerfDataReader reader(TraceBlobView(std::move(blob)));
auto parsed_sample = tracker->ParseSample(reader);
EXPECT_TRUE(parsed_sample.ok());
diff --git a/src/trace_processor/metrics/sql/android/java_heap_stats.sql b/src/trace_processor/metrics/sql/android/java_heap_stats.sql
index dd2b7b6..1a4d534 100644
--- a/src/trace_processor/metrics/sql/android/java_heap_stats.sql
+++ b/src/trace_processor/metrics/sql/android/java_heap_stats.sql
@@ -109,6 +109,11 @@
base_stats.upid,
RepeatedField(JavaHeapStats_Sample(
'ts', graph_sample_ts,
+ 'process_uptime_ms',
+ CASE WHEN process.start_ts IS NOT NULL
+ THEN (graph_sample_ts - process.start_ts) / 1000000
+ ELSE NULL
+ END,
'heap_size', total_size,
'heap_native_size', total_native_size,
'obj_count', total_obj_count,
@@ -120,6 +125,7 @@
'oom_score_adj', closest_anon_swap_oom.oom_score_val
)) AS sample_protos
FROM base_stats
+ JOIN process USING (upid)
LEFT JOIN closest_anon_swap_oom USING (upid, graph_sample_ts)
GROUP BY 1
)
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/frames/BUILD.gn b/src/trace_processor/perfetto_sql/stdlib/android/frames/BUILD.gn
index bc434d5..306758a 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/frames/BUILD.gn
+++ b/src/trace_processor/perfetto_sql/stdlib/android/frames/BUILD.gn
@@ -18,5 +18,6 @@
sources = [
"per_frame_metrics.sql",
"timeline.sql",
+ "timeline_maxsdk28.sql",
]
}
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql b/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql
index b492bb3..3d29281 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline.sql
@@ -13,6 +13,9 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
+INCLUDE PERFETTO MODULE slices.with_context;
+INCLUDE PERFETTO MODULE android.frames.timeline_maxsdk28;
+
-- Parses the slice name to fetch `frame_id` from `slice` table.
-- Use with caution. Slice names are a flaky source of ids and the resulting
-- table might require some further operations.
@@ -23,13 +26,16 @@
-- `slice.id` of the frame slice.
id INT,
-- Parsed frame id.
- frame_id INT
+ frame_id INT,
+ -- Utid.
+ utid INT
) AS
WITH all_found AS (
SELECT
id,
- cast_int!(STR_SPLIT(name, ' ', 1)) AS frame_id
- FROM slice
+ cast_int!(STR_SPLIT(name, ' ', 1)) AS frame_id,
+ utid
+ FROM thread_slice
WHERE name GLOB $glob_str
)
SELECT *
@@ -47,11 +53,10 @@
ui_thread_utid INT
) AS
SELECT
- c.*,
- thread_track.utid AS ui_thread_utid
-FROM _get_frame_table_with_id('Choreographer#doFrame*') c
-JOIN slice USING (id)
-JOIN thread_track ON (thread_track.id = slice.track_id);
+ id,
+ frame_id,
+ utid AS ui_thread_utid
+FROM _get_frame_table_with_id('Choreographer#doFrame*');
-- All of the `DrawFrame` slices with their frame id and render thread.
-- There might be multiple DrawFrames slices for a single vsync (frame id).
@@ -66,11 +71,10 @@
render_thread_utid INT
) AS
SELECT
- d.*,
- thread_track.utid AS render_thread_utid
-FROM _get_frame_table_with_id('DrawFrame*') d
-JOIN slice USING (id)
-JOIN thread_track ON (thread_track.id = slice.track_id);
+ id,
+ frame_id,
+ utid AS render_thread_utid
+FROM _get_frame_table_with_id('DrawFrame*');
-- `actual_frame_timeline_slice` returns the same slice on different tracks.
-- We are getting the first slice with one frame id.
@@ -119,21 +123,47 @@
-- `utid` of the UI thread.
ui_thread_utid INT
) AS
+WITH frames_sdk_after_28 AS (
SELECT
frame_id,
ts,
dur,
do_frame.id AS do_frame_id,
draw_frame.id AS draw_frame_id,
- act.id AS actual_frame_timeline_id,
- exp.id AS expected_frame_timeline_id,
draw_frame.render_thread_utid,
- do_frame.ui_thread_utid
+ do_frame.ui_thread_utid,
+ "after_28" AS sdk,
+ act.id AS actual_frame_timeline_id,
+ exp.id AS expected_frame_timeline_id
FROM android_frames_choreographer_do_frame do_frame
JOIN android_frames_draw_frame draw_frame USING (frame_id)
JOIN _distinct_from_actual_timeline_slice act USING (frame_id)
JOIN _distinct_from_expected_timeline_slice exp USING (frame_id)
-ORDER BY frame_id;
+ORDER BY frame_id
+),
+all_frames AS (
+ SELECT * FROM frames_sdk_after_28
+ UNION
+ SELECT
+ *,
+ NULL AS actual_frame_timeline_id,
+ NULL AS expected_frame_timeline_id
+ FROM _frames_maxsdk_28
+)
+SELECT
+ frame_id,
+ ts,
+ dur,
+ do_frame_id,
+ draw_frame_id,
+ actual_frame_timeline_id,
+ expected_frame_timeline_id,
+ render_thread_utid,
+ ui_thread_utid
+FROM all_frames
+WHERE sdk = IIF(
+ (SELECT COUNT(1) FROM actual_frame_timeline_slice) > 0,
+ "after_28", "maxsdk28");
-- Returns first frame after the provided timestamp. The returning table has at
-- most one row.
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql b/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql
new file mode 100644
index 0000000..b8fad07
--- /dev/null
+++ b/src/trace_processor/perfetto_sql/stdlib/android/frames/timeline_maxsdk28.sql
@@ -0,0 +1,76 @@
+--
+-- Copyright 2024 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.
+
+INCLUDE PERFETTO MODULE slices.with_context;
+
+-- All slices related to one frame for max SDK 28. Aggregates
+-- "Choreographer#doFrame" and "DrawFrame". Tries to guess the `ts` and `dur`
+-- of the frame by first guessing which "DrawFrame" slices are related to which
+-- "Choreographer#doSlice".
+CREATE PERFETTO TABLE _frames_maxsdk_28(
+ -- Frame id. Created manually starting from 0.
+ frame_id INT,
+ -- Timestamp of the frame. Start of "Choreographer#doFrame" slice.
+ ts INT,
+ -- Duration of the frame, defined as the duration until the last
+ -- "DrawFrame" of this frame finishes.
+ dur INT,
+ -- `slice.id` of "Choreographer#doFrame" slice.
+ do_frame_id INT,
+ -- `slice.id` of "DrawFrame" slice. Fetched as one of the "DrawFrame"
+ -- slices that happen for the same process as "Choreographer#doFrame" slice
+ -- and start after it started and before the next "doFrame" started.
+ draw_frame_id INT,
+ -- `utid` of the render thread.
+ render_thread_utid INT,
+ -- `utid` of the UI thread.
+ ui_thread_utid INT,
+ -- "maxsdk28"
+ sdk STRING
+) AS
+WITH do_frames AS (
+ SELECT
+ id,
+ ts,
+ LEAD(ts, 1, TRACE_END()) OVER (PARTITION BY upid ORDER BY ts) AS next_do_frame,
+ utid,
+ upid
+ FROM thread_slice
+ WHERE name = 'Choreographer#doFrame' AND is_main_thread = 1
+ ORDER BY ts
+),
+draw_frames AS (
+ SELECT
+ id,
+ ts,
+ dur,
+ ts + dur AS ts_end,
+ utid,
+ upid
+ FROM thread_slice
+ WHERE name = 'DrawFrame'
+)
+SELECT
+ ROW_NUMBER() OVER () AS frame_id,
+ do.ts,
+ MAX(draw.ts_end) OVER (PARTITION BY do.id) - do.ts AS dur,
+ do.id AS do_frame_id,
+ draw.id AS draw_frame_id,
+ draw.utid AS render_thread_utid,
+ do.utid AS ui_thread_utid,
+ "maxsdk28" AS sdk
+FROM do_frames do
+JOIN draw_frames draw ON (do.upid = draw.upid AND draw.ts >= do.ts AND draw.ts < next_do_frame)
+ORDER BY do.ts;
\ No newline at end of file
diff --git a/src/trace_processor/perfetto_sql/stdlib/android/startup/startups_maxsdk28.sql b/src/trace_processor/perfetto_sql/stdlib/android/startup/startups_maxsdk28.sql
index 0a7fab2..5188b63 100644
--- a/src/trace_processor/perfetto_sql/stdlib/android/startup/startups_maxsdk28.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/android/startup/startups_maxsdk28.sql
@@ -13,17 +13,51 @@
-- See the License for the specific language governing permissions and
-- limitations under the License.
+INCLUDE PERFETTO MODULE slices.with_context;
INCLUDE PERFETTO MODULE android.startup.startup_events;
+INCLUDE PERFETTO MODULE android.frames.timeline;
CREATE PERFETTO TABLE _startups_maxsdk28 AS
+-- Warm and cold starts only are based on the launching slice
+WITH warm_and_cold AS (
+ SELECT
+ le.ts,
+ le.ts_end AS ts_end,
+ package_name AS package
+ FROM _startup_events le
+),
+-- Hot starts don’t have a launching slice so we use activityResume as a
+-- proxy.
+--
+-- Note that this implementation will also count warm and cold starts but
+-- we will remove those below.
+maybe_hot AS (
+ SELECT
+ sl.ts,
+ rs.ts + rs.dur AS ts_end,
+ -- We use the process name as the package as we have no better option.
+ process_name AS package
+ FROM thread_slice sl
+ JOIN android_first_frame_after(sl.ts) rs
+ WHERE name = 'activityResume'
+ -- Remove any launches here where the activityResume slices happens during
+ -- a warm/cold startup.
+ AND sl.ts NOT IN (SELECT ts FROM warm_and_cold)
+),
+cold_warm_hot AS (
+ SELECT * FROM warm_and_cold
+ UNION ALL
+ SELECT * FROM maybe_hot
+
+)
SELECT
- "maxsdk28" as sdk,
+ "maxsdk28" AS sdk,
ROW_NUMBER() OVER(ORDER BY ts) AS startup_id,
- le.ts,
- le.ts_end AS ts_end,
- le.ts_end - le.ts AS dur,
- package_name AS package,
+ ts,
+ ts_end,
+ ts_end - ts AS dur,
+ package,
NULL AS startup_type
-FROM _startup_events le
-ORDER BY ts;
+FROM cold_warm_hot;
+
diff --git a/src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql b/src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql
index 6e9ba0d..9430bd9 100644
--- a/src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql
+++ b/src/trace_processor/perfetto_sql/stdlib/slices/with_context.sql
@@ -36,8 +36,10 @@
thread_name STRING,
-- Alias for `thread.utid`.
utid INT,
- -- Alias for `thread.tid`
+ -- Alias for `thread.tid`.
tid INT,
+ -- Alias for `thread.is_main_thread`.
+ is_main_thread BOOL,
-- Alias for `process.name`.
process_name STRING,
-- Alias for `process.upid`.
@@ -67,6 +69,7 @@
thread.name AS thread_name,
thread.utid,
thread.tid,
+ thread.is_main_thread,
process.name AS process_name,
process.upid,
process.pid,
diff --git a/src/trace_processor/sqlite/sqlite_engine.cc b/src/trace_processor/sqlite/sqlite_engine.cc
index cfd73dc..fcd68e8 100644
--- a/src/trace_processor/sqlite/sqlite_engine.cc
+++ b/src/trace_processor/sqlite/sqlite_engine.cc
@@ -16,6 +16,7 @@
#include "src/trace_processor/sqlite/sqlite_engine.h"
+#include <sqlite3.h>
#include <cstdint>
#include <optional>
#include <string>
@@ -47,7 +48,15 @@
// sqlite3_initialize isn't actually thread-safe in standalone builds because
// we build with SQLITE_THREADSAFE=0. Ensure it's only called from a single
// thread.
- static bool init_once = [] { return sqlite3_initialize() == SQLITE_OK; }();
+ static bool init_once = [] {
+ // Enabling memstatus causes a lock to be taken on every malloc/free in
+ // SQLite to update the memory statistics. This can cause massive contention
+ // in trace processor when multiple instances are used in parallel.
+ // Fix this by disabling the memstatus API which we don't make use of in
+ // any case. See b/335019324 for more info on this.
+ PERFETTO_CHECK(sqlite3_config(SQLITE_CONFIG_MEMSTATUS, 0) == SQLITE_OK);
+ return sqlite3_initialize() == SQLITE_OK;
+ }();
PERFETTO_CHECK(init_once);
}
diff --git a/src/traced/probes/ftrace/atrace_wrapper.cc b/src/traced/probes/ftrace/atrace_wrapper.cc
index 1a64544..38f0200 100644
--- a/src/traced/probes/ftrace/atrace_wrapper.cc
+++ b/src/traced/probes/ftrace/atrace_wrapper.cc
@@ -187,18 +187,18 @@
#endif
}
-bool AtraceWrapperImpl::IsOldAtrace() {
+bool AtraceWrapperImpl::SupportsUserspaceOnly() {
#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && \
!PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
// Sideloaded case. We could be sideloaded on a modern device or an older one.
std::string str_value = base::GetAndroidProp("ro.build.version.sdk");
if (str_value.empty())
- return false;
+ return true;
auto opt_value = base::CStringToUInt32(str_value.c_str());
- return opt_value.has_value() && *opt_value < 28; // 28 == Android P.
+ return !opt_value.has_value() || *opt_value >= 28; // 28 == Android P.
#else
// In in-tree builds we know that atrace is current, no runtime checks needed.
- return false;
+ return true;
#endif
}
diff --git a/src/traced/probes/ftrace/atrace_wrapper.h b/src/traced/probes/ftrace/atrace_wrapper.h
index 5c6a148..18c3d2d 100644
--- a/src/traced/probes/ftrace/atrace_wrapper.h
+++ b/src/traced/probes/ftrace/atrace_wrapper.h
@@ -30,7 +30,7 @@
// - Just use atrace --async_start/stop, which will cause atrace to also
// poke at ftrace.
// - Suppress the checks for "somebody else enabled ftrace unexpectedly".
- virtual bool IsOldAtrace() = 0;
+ virtual bool SupportsUserspaceOnly() = 0;
virtual bool RunAtrace(const std::vector<std::string>& args,
std::string* atrace_errors) = 0;
};
@@ -38,7 +38,7 @@
class AtraceWrapperImpl : public AtraceWrapper {
public:
~AtraceWrapperImpl() override;
- bool IsOldAtrace() override;
+ bool SupportsUserspaceOnly() override;
bool RunAtrace(const std::vector<std::string>& args,
std::string* atrace_errors) override;
};
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.cc b/src/traced/probes/ftrace/ftrace_config_muxer.cc
index e4d8a19..f8a0eff 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.cc
@@ -656,7 +656,7 @@
"atrace_apps options as they affect global state");
return false;
}
- if (atrace_wrapper_->IsOldAtrace() && !ds_configs_.empty()) {
+ if (!atrace_wrapper_->SupportsUserspaceOnly() && !ds_configs_.empty()) {
PERFETTO_ELOG(
"Concurrent atrace sessions are not supported before Android P, "
"bailing out.");
@@ -1050,7 +1050,7 @@
std::vector<std::string> args;
args.push_back("atrace"); // argv0 for exec()
args.push_back("--async_start");
- if (!atrace_wrapper_->IsOldAtrace())
+ if (atrace_wrapper_->SupportsUserspaceOnly())
args.push_back("--only_userspace");
for (const auto& category : categories)
@@ -1078,7 +1078,7 @@
PERFETTO_DLOG("Stop atrace...");
std::vector<std::string> args{"atrace", "--async_stop"};
- if (!atrace_wrapper_->IsOldAtrace())
+ if (atrace_wrapper_->SupportsUserspaceOnly())
args.push_back("--only_userspace");
if (atrace_wrapper_->RunAtrace(args, /*atrace_errors=*/nullptr)) {
current_state_.atrace_categories.clear();
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc b/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
index 513d851..9e9ca5e 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer_unittest.cc
@@ -96,7 +96,7 @@
class MockAtraceWrapper : public AtraceWrapper {
public:
MOCK_METHOD(bool, RunAtrace, (const std::vector<std::string>&, std::string*));
- MOCK_METHOD(bool, IsOldAtrace, ());
+ MOCK_METHOD(bool, SupportsUserspaceOnly, ());
};
class MockProtoTranslationTable : public ProtoTranslationTable {
@@ -173,7 +173,7 @@
protected:
FtraceConfigMuxerTest() {
ON_CALL(atrace_wrapper_, RunAtrace).WillByDefault(Return(true));
- ON_CALL(atrace_wrapper_, IsOldAtrace).WillByDefault(Return(false));
+ ON_CALL(atrace_wrapper_, SupportsUserspaceOnly).WillByDefault(Return(true));
}
std::unique_ptr<MockProtoTranslationTable> GetMockTable() {
diff --git a/src/traced/probes/ftrace/ftrace_controller_unittest.cc b/src/traced/probes/ftrace/ftrace_controller_unittest.cc
index 1a3538e..bfcb516 100644
--- a/src/traced/probes/ftrace/ftrace_controller_unittest.cc
+++ b/src/traced/probes/ftrace/ftrace_controller_unittest.cc
@@ -205,7 +205,7 @@
class MockAtraceWrapper : public AtraceWrapper {
public:
MOCK_METHOD(bool, RunAtrace, (const std::vector<std::string>&, std::string*));
- MOCK_METHOD(bool, IsOldAtrace, ());
+ MOCK_METHOD(bool, SupportsUserspaceOnly, ());
};
} // namespace
diff --git a/test/data/api24_startup_cold.perfetto-trace.sha256 b/test/data/api24_startup_cold.perfetto-trace.sha256
new file mode 100644
index 0000000..dbc4e62
--- /dev/null
+++ b/test/data/api24_startup_cold.perfetto-trace.sha256
@@ -0,0 +1 @@
+ac006a3ec74fac70feb58c2cfad840c552af0ebd25f03bdfbf14d5f77148764b
\ No newline at end of file
diff --git a/test/data/api24_startup_hot.perfetto-trace.sha256 b/test/data/api24_startup_hot.perfetto-trace.sha256
new file mode 100644
index 0000000..6fa48c6
--- /dev/null
+++ b/test/data/api24_startup_hot.perfetto-trace.sha256
@@ -0,0 +1 @@
+0ec527c6392adf16e8580ba0fa3eaccf69eccba36c863377eca5c5618f00f3ea
\ No newline at end of file
diff --git a/test/data/api24_startup_warm.perfetto-trace.sha256 b/test/data/api24_startup_warm.perfetto-trace.sha256
new file mode 100644
index 0000000..04eca80
--- /dev/null
+++ b/test/data/api24_startup_warm.perfetto-trace.sha256
@@ -0,0 +1 @@
+59d1e84ddf6a492c10d7b6ecebf7b80813e6a0a2b3bef7d854d5ef3cf7210137
\ No newline at end of file
diff --git a/test/data/api31_startup_hot.perfetto-trace.sha256 b/test/data/api31_startup_hot.perfetto-trace.sha256
new file mode 100644
index 0000000..8cac597
--- /dev/null
+++ b/test/data/api31_startup_hot.perfetto-trace.sha256
@@ -0,0 +1 @@
+072802c0adf6968d0eb9c56fa13b33cad32f583398d019dc8a798981164333c5
\ No newline at end of file
diff --git a/test/data/api32_startup_warm.perfetto-trace.sha256 b/test/data/api32_startup_warm.perfetto-trace.sha256
new file mode 100644
index 0000000..f83dd34
--- /dev/null
+++ b/test/data/api32_startup_warm.perfetto-trace.sha256
@@ -0,0 +1 @@
+776122b5660c5d6e738950031fdb4992a64e3224e9e82bbaed474a0a281ed7e3
\ No newline at end of file
diff --git a/test/data/api34_startup_cold.perfetto-trace.sha256 b/test/data/api34_startup_cold.perfetto-trace.sha256
new file mode 100644
index 0000000..2a7a044
--- /dev/null
+++ b/test/data/api34_startup_cold.perfetto-trace.sha256
@@ -0,0 +1 @@
+1958521dc5128cd4eadd1df281e19987aded718750e6883f82ffd3b5eb529bd6
\ No newline at end of file
diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py
index 1f711b8..cb82c55 100644
--- a/test/trace_processor/diff_tests/include_index.py
+++ b/test/trace_processor/diff_tests/include_index.py
@@ -92,6 +92,7 @@
from diff_tests.parser.translated_args.tests import TranslatedArgs
from diff_tests.parser.ufs.tests import Ufs
from diff_tests.stdlib.android.frames_tests import Frames
+from diff_tests.stdlib.android.startups_tests import Startups
from diff_tests.stdlib.android.tests import AndroidStdlib
from diff_tests.stdlib.chrome.chrome_stdlib_testsuites import CHROME_STDLIB_TESTSUITES
from diff_tests.stdlib.common.tests import StdlibCommon
@@ -282,6 +283,7 @@
'StdlibIntervals').fetch(),
*IntervalsIntersect(index_path, 'stdlib/intervals',
'StdlibIntervalsIntersect').fetch(),
+ *Startups(index_path, 'stdlib/android', 'Startups').fetch(),
*Timestamps(index_path, 'stdlib/timestamps', 'Timestamps').fetch(),
*WattsonStdlib(index_path, 'stdlib/wattson', 'WattsonStdlib').fetch(),
] + chrome_stdlib_tests
diff --git a/test/trace_processor/diff_tests/parser/android/tests.py b/test/trace_processor/diff_tests/parser/android/tests.py
index 9fca28e..6a20f59 100644
--- a/test/trace_processor/diff_tests/parser/android/tests.py
+++ b/test/trace_processor/diff_tests/parser/android/tests.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric, Systrace
from python.generators.diff_tests.testing import Csv, Json, TextProto, BinaryProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
from python.generators.diff_tests.testing import PrintProfileProto
@@ -203,3 +203,54 @@
0
0
"""))
+
+ # Tests when counter_tack.machine_id is not null.
+ def test_android_system_property_counter_machine_id(self):
+ return DiffTestBlueprint(
+ trace=TextProto(r"""
+ packet {
+ timestamp: 1000
+ android_system_property {
+ values {
+ name: "debug.tracing.screen_state"
+ value: "2"
+ }
+ values {
+ name: "debug.tracing.device_state"
+ value: "some_state_from_sysprops"
+ }
+ }
+ machine_id: 1001
+ }
+ packet {
+ ftrace_events {
+ cpu: 1
+ event {
+ timestamp: 2000
+ pid: 1
+ print {
+ buf: "C|1000|ScreenState|1\n"
+ }
+ }
+ event {
+ timestamp: 3000
+ pid: 1
+ print {
+ buf: "N|1000|DeviceStateChanged|some_state_from_atrace\n"
+ }
+ }
+ }
+ machine_id: 1001
+ }
+ """),
+ query="""
+ SELECT t.type, t.name, c.id, c.ts, c.type, c.value
+ FROM counter_track t JOIN counter c ON t.id = c.track_id
+ WHERE name = 'ScreenState'
+ AND t.machine_id IS NOT NULL;
+ """,
+ out=Csv("""
+ "type","name","id","ts","type","value"
+ "counter_track","ScreenState",0,1000,"counter",2.000000
+ "counter_track","ScreenState",1,2000,"counter",1.000000
+ """))
diff --git a/test/trace_processor/diff_tests/parser/graphics/tests.py b/test/trace_processor/diff_tests/parser/graphics/tests.py
index 7fe4af1..0d5d8b5 100644
--- a/test/trace_processor/diff_tests/parser/graphics/tests.py
+++ b/test/trace_processor/diff_tests/parser/graphics/tests.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
@@ -296,3 +296,20 @@
# 751796307210,4313965,"mali_KCPU_FENCE_WAIT"
# 751800638997,0,"mali_KCPU_FENCE_SIGNAL"
# """))
+
+ # Tests gpu_track with machine_id ID.
+ def test_graphics_frame_events_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('graphics_frame_events.py'),
+ trace_modifier=TraceInjector(['graphics_frame_event'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT ts, gpu_track.name AS track_name, dur, frame_slice.name AS slice_name,
+ frame_number, layer_name
+ FROM gpu_track
+ LEFT JOIN frame_slice ON gpu_track.id = frame_slice.track_id
+ WHERE scope = 'graphics_frame_event'
+ AND gpu_track.machine_id IS NOT NULL
+ ORDER BY ts;
+ """,
+ out=Path('graphics_frame_events.out'))
diff --git a/test/trace_processor/diff_tests/parser/parsing/tests.py b/test/trace_processor/diff_tests/parser/parsing/tests.py
index 8619bc3..505bdf9 100644
--- a/test/trace_processor/diff_tests/parser/parsing/tests.py
+++ b/test/trace_processor/diff_tests/parser/parsing/tests.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
@@ -1354,3 +1354,58 @@
"name","severity","value"
"ftrace_abi_errors_skipped_zero_data_length","info",1
"""))
+
+ # CPU info
+ def test_cpu_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('cpu_info.textproto'),
+ trace_modifier=TraceInjector(['cpu_info'], {'machine_id': 1001}),
+ query="""
+ SELECT
+ id,
+ cluster_id,
+ processor
+ FROM cpu
+ WHERE machine_id is not NULL;
+ """,
+ out=Csv("""
+ "id","cluster_id","processor"
+ 0,0,"AArch64 Processor rev 13 (aarch64)"
+ 1,0,"AArch64 Processor rev 13 (aarch64)"
+ 2,0,"AArch64 Processor rev 13 (aarch64)"
+ 3,0,"AArch64 Processor rev 13 (aarch64)"
+ 4,0,"AArch64 Processor rev 13 (aarch64)"
+ 5,0,"AArch64 Processor rev 13 (aarch64)"
+ 6,1,"AArch64 Processor rev 13 (aarch64)"
+ 7,1,"AArch64 Processor rev 13 (aarch64)"
+ """))
+
+ def test_cpu_freq_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('cpu_info.textproto'),
+ trace_modifier=TraceInjector(['cpu_info'], {'machine_id': 1001}),
+ query="""
+ SELECT
+ freq,
+ GROUP_CONCAT(cpu_id) AS cpus
+ FROM cpu_freq
+ WHERE machine_id is not NULL
+ GROUP BY freq
+ ORDER BY freq;
+ """,
+ out=Path('cpu_freq.out'))
+
+ def test_sched_waking_instants_compact_sched_machine_id(self):
+ return DiffTestBlueprint(
+ trace=DataPath('compact_sched.pb'),
+ trace_modifier=TraceInjector(
+ ['ftrace_events', 'ftrace_stats', 'system_info'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT ts, thread.name, thread.tid
+ FROM thread_state
+ JOIN thread USING (utid)
+ WHERE state = 'R' AND thread_state.machine_id is not NULL
+ ORDER BY ts;
+ """,
+ out=Path('sched_waking_instants_compact_sched.out'))
diff --git a/test/trace_processor/diff_tests/parser/power/tests_energy_breakdown.py b/test/trace_processor/diff_tests/parser/power/tests_energy_breakdown.py
index f62ba2c..d678400 100644
--- a/test/trace_processor/diff_tests/parser/power/tests_energy_breakdown.py
+++ b/test/trace_processor/diff_tests/parser/power/tests_energy_breakdown.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
@@ -90,3 +90,35 @@
3,10190
3,10235
"""))
+
+ def test_energy_breakdown_uid_table_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('energy_breakdown_uid.textproto'),
+ trace_modifier=TraceInjector(['android_energy_estimation_breakdown'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT uid, name
+ FROM uid_counter_track
+ WHERE machine_id IS NOT NULL;
+ """,
+ out=Csv("""
+ "uid","name"
+ 10234,"GPU"
+ 10190,"GPU"
+ 10235,"GPU"
+ """))
+
+ def test_energy_breakdown_table_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('energy_breakdown.textproto'),
+ trace_modifier=TraceInjector(['android_energy_estimation_breakdown'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT consumer_id, name, consumer_type, ordinal
+ FROM energy_counter_track
+ WHERE machine_id IS NOT NULL;
+ """,
+ out=Csv("""
+ "consumer_id","name","consumer_type","ordinal"
+ 0,"CPUCL0","CPU_CLUSTER",0
+ """))
diff --git a/test/trace_processor/diff_tests/parser/process_tracking/tests.py b/test/trace_processor/diff_tests/parser/process_tracking/tests.py
index 9092541..b2a04a7 100644
--- a/test/trace_processor/diff_tests/parser/process_tracking/tests.py
+++ b/test/trace_processor/diff_tests/parser/process_tracking/tests.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
@@ -227,6 +227,36 @@
19999,"[NULL]","[NULL]","real_name"
"""))
+ def test_process_tracking_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('synth_process_tracking.py'),
+ trace_modifier=TraceInjector(['ftrace_events', 'process_tree'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT tid, pid, process.name AS pname, thread.name AS tname,
+ thread.machine_id as tmachine, process.machine_id as pmachine
+ FROM thread
+ LEFT JOIN process USING(upid)
+ WHERE tid > 0
+ ORDER BY tid;
+ """,
+ out=Csv("""
+ "tid","pid","pname","tname","tmachine","pmachine"
+ 10,10,"process1","p1-t0",1,1
+ 11,"[NULL]","[NULL]","p1-t1",1,"[NULL]"
+ 12,10,"process1","p1-t2",1,1
+ 20,20,"process_2","p2-t0",1,1
+ 21,20,"process_2","p2-t1",1,1
+ 22,20,"process_2","p2-t2",1,1
+ 30,30,"process_3","p3-t0",1,1
+ 31,30,"process_3","p3-t1",1,1
+ 31,40,"process_4","p4-t1",1,1
+ 32,30,"process_3","p3-t2",1,1
+ 33,30,"process_3","p3-t3",1,1
+ 34,30,"process_3","p3-t4",1,1
+ 40,40,"process_4","p4-t0",1,1
+ """))
+
def test_process_stats_process_runtime(self):
return DiffTestBlueprint(
trace=TextProto(r"""
diff --git a/test/trace_processor/diff_tests/parser/sched/tests.py b/test/trace_processor/diff_tests/parser/sched/tests.py
index ea04126..5568147 100644
--- a/test/trace_processor/diff_tests/parser/sched/tests.py
+++ b/test/trace_processor/diff_tests/parser/sched/tests.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
@@ -72,4 +72,39 @@
"Cpu 5 Util",13000,125.000000
"Cpu 5 Cap",13000,757.000000
"Cpu 5 Nr Running",13000,1.000000
- """))
\ No newline at end of file
+ """))
+
+ def test_sched_cpu_util_cfs_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('sched_cpu_util_cfs.textproto'),
+ trace_modifier=TraceInjector(['ftrace_events'], {'machine_id': 1001}),
+ query="""
+ SELECT
+ t.name,
+ c.ts,
+ c.value,
+ c.machine_id
+ FROM
+ counter AS c
+ LEFT JOIN
+ counter_track AS t
+ ON c.track_id = t.id
+ WHERE
+ name GLOB "Cpu ? Cap" OR name GLOB "Cpu ? Util" OR name GLOB "Cpu ? Nr Running"
+ ORDER BY ts;
+ """,
+ out=Csv("""
+ "name","ts","value","machine_id"
+ "Cpu 6 Util",10000,1.000000,1
+ "Cpu 6 Cap",10000,1004.000000,1
+ "Cpu 6 Nr Running",10000,0.000000,1
+ "Cpu 7 Util",11000,1.000000,1
+ "Cpu 7 Cap",11000,1007.000000,1
+ "Cpu 7 Nr Running",11000,0.000000,1
+ "Cpu 4 Util",12000,43.000000,1
+ "Cpu 4 Cap",12000,760.000000,1
+ "Cpu 4 Nr Running",12000,0.000000,1
+ "Cpu 5 Util",13000,125.000000,1
+ "Cpu 5 Cap",13000,757.000000,1
+ "Cpu 5 Nr Running",13000,1.000000,1
+ """))
diff --git a/test/trace_processor/diff_tests/parser/track_event/tests.py b/test/trace_processor/diff_tests/parser/track_event/tests.py
index 363b907..d71a2fa 100644
--- a/test/trace_processor/diff_tests/parser/track_event/tests.py
+++ b/test/trace_processor/diff_tests/parser/track_event/tests.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
@@ -692,3 +692,70 @@
12000,"slice3"
13000,"slice4"
"""))
+
+ def test_track_event_tracks_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('track_event_tracks.textproto'),
+ trace_modifier=TraceInjector(['track_descriptor', 'track_event'],
+ {'machine_id': 1001}),
+ query="""
+ WITH track_with_name AS (
+ SELECT
+ COALESCE(
+ t1.name,
+ 'thread=' || thread.name,
+ 'process=' || process.name,
+ 'tid=' || thread.tid,
+ 'pid=' || process.pid
+ ) AS full_name,
+ *
+ FROM track t1
+ LEFT JOIN thread_track t2 USING (id)
+ LEFT JOIN thread USING (utid)
+ LEFT JOIN process_track t3 USING (id)
+ LEFT JOIN process ON t3.upid = process.id
+ WHERE t1.machine_id IS NOT NULL
+ ORDER BY id
+ )
+ SELECT t1.full_name AS name, t2.full_name AS parent_name,
+ EXTRACT_ARG(t1.source_arg_set_id, 'has_first_packet_on_sequence')
+ AS has_first_packet_on_sequence
+ FROM track_with_name t1
+ LEFT JOIN track_with_name t2 ON t1.parent_id = t2.id
+ ORDER BY 1, 2;
+ """,
+ out=Csv("""
+ "name","parent_name","has_first_packet_on_sequence"
+ "Default Track","[NULL]","[NULL]"
+ "async","process=p1",1
+ "async2","process=p1",1
+ "async3","thread=t2",1
+ "event_and_track_async3","process=p1",1
+ "process=p1","[NULL]","[NULL]"
+ "process=p2","[NULL]","[NULL]"
+ "process=p2","[NULL]","[NULL]"
+ "thread=t1","process=p1",1
+ "thread=t2","process=p1",1
+ "thread=t3","process=p1",1
+ "thread=t4","process=p2","[NULL]"
+ "tid=1","[NULL]","[NULL]"
+ """))
+
+ # Tests thread_counter_track.machine_id is not null.
+ def test_track_event_counters_counters_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('track_event_counters.textproto'),
+ trace_modifier=TraceInjector(
+ ['track_descriptor', 'track_event', 'trace_packet_defaults'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT type, name, machine_id
+ FROM thread_counter_track
+ WHERE machine_id IS NOT NULL
+ """,
+ out=Csv("""
+ "type","name","machine_id"
+ "thread_counter_track","thread_time",1
+ "thread_counter_track","thread_time",1
+ "thread_counter_track","thread_instruction_count",1
+ """))
diff --git a/test/trace_processor/diff_tests/stdlib/android/startups_tests.py b/test/trace_processor/diff_tests/stdlib/android/startups_tests.py
new file mode 100644
index 0000000..14d002a
--- /dev/null
+++ b/test/trace_processor/diff_tests/stdlib/android/startups_tests.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python3
+# Copyright (C) 2024 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 a
+#
+# 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.
+
+from python.generators.diff_tests.testing import Path, DataPath
+from python.generators.diff_tests.testing import Csv, TextProto
+from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import TestSuite
+
+
+class Startups(TestSuite):
+
+ def test_hot_startups(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api31_startup_hot.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 1,186969441973689,186969489302704,47329015,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
+
+ def test_warm_startups(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api32_startup_warm.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 28,157479786566030,157479943081777,156515747,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
+
+ def test_cold_startups(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api34_startup_cold.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 61,17806781251694,17806891032171,109780477,"com.android.systemui.people","warm"
+ """))
+
+ def test_hot_startups_maxsdk28(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api24_startup_hot.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 1,779860286416,779893485322,33198906,"com.google.android.googlequicksearchbox","[NULL]"
+ 2,780778904571,780813944498,35039927,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
+
+ def test_warm_startups_maxsdk28(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api24_startup_warm.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 1,799979565075,800014194731,34629656,"com.google.android.googlequicksearchbox","[NULL]"
+ 2,800868511677,800981929562,113417885,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
+
+ def test_cold_startups_maxsdk28(self):
+ return DiffTestBlueprint(
+ trace=DataPath('api24_startup_cold.perfetto-trace'),
+ query="""
+ INCLUDE PERFETTO MODULE android.startup.startups;
+ SELECT * FROM android_startups;
+ """,
+ out=Csv("""
+ "startup_id","ts","ts_end","dur","package","startup_type"
+ 1,791231114368,791501060868,269946500,"androidx.benchmark.integration.macrobenchmark.target","[NULL]"
+ """))
diff --git a/test/trace_processor/diff_tests/tables/tests.py b/test/trace_processor/diff_tests/tables/tests.py
index eabf714..eef833c 100644
--- a/test/trace_processor/diff_tests/tables/tests.py
+++ b/test/trace_processor/diff_tests/tables/tests.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
@@ -414,3 +414,58 @@
"TO_REALTIME(0)"
420
"""))
+
+ # Test cpu_track with machine_id ID.
+ def test_cpu_track_table_machine_id(self):
+ return DiffTestBlueprint(
+ trace=TextProto(r"""
+ packet {
+ ftrace_events {
+ cpu: 1
+ event {
+ timestamp: 100001000000
+ pid: 10
+ irq_handler_entry {
+ irq: 100
+ name : "resource1"
+ }
+ }
+ event {
+ timestamp: 100002000000
+ pid: 10
+ irq_handler_exit {
+ irq: 100
+ ret: 1
+ }
+ }
+ }
+ machine_id: 1001
+ }
+ packet {
+ ftrace_events {
+ cpu: 0
+ event {
+ timestamp: 100003000000
+ pid: 15
+ irq_handler_entry {
+ irq: 100
+ name : "resource1"
+ }
+ }
+ }
+ machine_id: 1001
+ }
+ """),
+ query="""
+ SELECT
+ type,
+ cpu,
+ machine_id
+ FROM cpu_track
+ ORDER BY type, cpu
+ """,
+ out=Csv("""
+ "type","cpu","machine_id"
+ "cpu_track",0,1
+ "cpu_track",1,1
+ """))
diff --git a/test/trace_processor/diff_tests/tables/tests_counters.py b/test/trace_processor/diff_tests/tables/tests_counters.py
index 8ed753f..4cc79a0 100644
--- a/test/trace_processor/diff_tests/tables/tests_counters.py
+++ b/test/trace_processor/diff_tests/tables/tests_counters.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
@@ -125,3 +125,106 @@
73727335051,23522762
86726132752,24487554
"""))
+
+ def test_counter_dur_example_android_trace_30s_machine_id(self):
+ return DiffTestBlueprint(
+ trace=DataPath('example_android_trace_30s.pb'),
+ trace_modifier=TraceInjector(
+ ['ftrace_events', 'sys_stats', 'process_stats', 'process_tree'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT ts, dur, machine_id
+ FROM experimental_counter_dur
+ WHERE track_id IN (1, 2, 3)
+ ORDER BY dur LIMIT 10;
+ """,
+ out=Csv("""
+ "ts","dur","machine_id"
+ 100351738640,-1,1
+ 100351738640,-1,1
+ 100351738640,-1,1
+ 70731059648,19510835,1
+ 70731059648,19510835,1
+ 70731059648,19510835,1
+ 73727335051,23522762,1
+ 73727335051,23522762,1
+ 73727335051,23522762,1
+ 86726132752,24487554,1
+ """))
+
+ # Tests counter.machine_id and process_counter_track.machine.
+ def test_filter_row_vector_example_android_trace_30s_machine_id(self):
+ return DiffTestBlueprint(
+ trace=DataPath('example_android_trace_30s.pb'),
+ trace_modifier=TraceInjector(
+ ['ftrace_events', 'sys_stats', 'process_stats', 'process_tree'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT ts
+ FROM counter
+ WHERE
+ ts > 72563651549
+ AND track_id = (
+ SELECT t.id
+ FROM process_counter_track t
+ JOIN process p USING (upid)
+ WHERE
+ t.name = 'Heap size (KB)'
+ AND p.pid = 1204
+ AND t.machine_id is not NULL
+ )
+ AND value != 17952.000000
+ AND counter.machine_id is not NULL
+ LIMIT 20;
+ """,
+ out=Path('filter_row_vector_example_android_trace_30s.out'))
+
+ def test_counters_where_cpu_counters_where_cpu_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('counters_where_cpu.py'),
+ trace_modifier=TraceInjector(['ftrace_events'], {'machine_id': 1001}),
+ query="""
+ SELECT
+ ts,
+ lead(ts, 1, ts) OVER (PARTITION BY name ORDER BY ts) - ts AS dur,
+ value, c.machine_id
+ FROM counter c
+ JOIN cpu_counter_track t ON t.id = c.track_id
+ WHERE cpu = 1;
+ """,
+ out=Csv("""
+ "ts","dur","value","machine_id"
+ 1000,1,3000.000000,1
+ 1001,0,4000.000000,1
+ """))
+
+ def test_synth_1_filter_counter_machine_id(self):
+ return DiffTestBlueprint(
+ trace=Path('../common/synth_1.py'),
+ trace_modifier=TraceInjector(
+ ['ftrace_events', 'process_stats', 'process_tree'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT COUNT(*), machine_id
+ FROM counter
+ WHERE
+ track_id = 0;
+ """,
+ out=Csv("""
+ "COUNT(*)","machine_id"
+ 2,1
+ """))
+
+ def test_memory_counters_machine_id(self):
+ return DiffTestBlueprint(
+ trace=DataPath('memory_counters.pb'),
+ trace_modifier=TraceInjector(
+ ['ftrace_events', 'sys_stats', 'process_stats', 'process_tree'],
+ {'machine_id': 1001}),
+ query="""
+ SELECT count(*), machine_id FROM counters WHERE -1 < ts group by machine_id;
+ """,
+ out=Csv("""
+ "count(*)","machine_id"
+ 98688,1
+ """))
diff --git a/test/trace_processor/diff_tests/tables/tests_sched.py b/test/trace_processor/diff_tests/tables/tests_sched.py
index 306b8e8..ad23a5d 100644
--- a/test/trace_processor/diff_tests/tables/tests_sched.py
+++ b/test/trace_processor/diff_tests/tables/tests_sched.py
@@ -15,7 +15,7 @@
from python.generators.diff_tests.testing import Path, DataPath, Metric
from python.generators.diff_tests.testing import Csv, Json, TextProto, BinaryProto
-from python.generators.diff_tests.testing import DiffTestBlueprint
+from python.generators.diff_tests.testing import DiffTestBlueprint, TraceInjector
from python.generators.diff_tests.testing import TestSuite
from python.generators.diff_tests.testing import PrintProfileProto
@@ -675,3 +675,38 @@
thread_state: S (0x0)
critical path (0x0)
"""))
+
+ # Test machine_id ID of the sched table.
+ def test_android_sched_and_ps_machine_id(self):
+ return DiffTestBlueprint(
+ trace=DataPath('android_sched_and_ps.pb'),
+ trace_modifier=TraceInjector(['ftrace_events'], {'machine_id': 1001}),
+ query="""
+ SELECT ts, cpu, machine_id FROM sched WHERE ts >= 81473797418963 LIMIT 10;
+ """,
+ out=Csv("""
+ "ts","cpu","machine_id"
+ 81473797824982,3,1
+ 81473797942847,3,1
+ 81473798135399,0,1
+ 81473798786857,2,1
+ 81473798875451,3,1
+ 81473799019930,2,1
+ 81473799079982,0,1
+ 81473800089357,3,1
+ 81473800144461,3,1
+ 81473800441805,3,1
+ """))
+
+ # Test the support of machine_id ID of the raw table.
+ def test_raw_machine_id(self):
+ return DiffTestBlueprint(
+ trace=DataPath('android_sched_and_ps.pb'),
+ trace_modifier=TraceInjector(['ftrace_events'], {'machine_id': 1001}),
+ query="""
+ SELECT count(*) FROM raw WHERE machine_id is NULL;
+ """,
+ out=Csv("""
+ "count(*)"
+ 0
+ """))
diff --git a/ui/package.json b/ui/package.json
index e1807ce..9dea540 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -72,5 +72,8 @@
"build": "node build.js",
"test": "node build.js --run-unittests",
"lint": "npx eslint . --ext .js,.ts"
+ },
+ "jest": {
+ "setupFiles": ["jest-localstorage-mock"]
}
}
diff --git a/ui/src/frontend/base_counter_track.ts b/ui/src/frontend/base_counter_track.ts
index 202ad44..3fe5c71 100644
--- a/ui/src/frontend/base_counter_track.ts
+++ b/ui/src/frontend/base_counter_track.ts
@@ -891,6 +891,7 @@
if (maybeCachedCounters) {
this.countersKey = countersKey;
this.counters = maybeCachedCounters;
+ return;
}
const bucketNs = countersKey.bucketSize;
@@ -955,6 +956,7 @@
data.displayValueRange = [min, max];
this.cache.insert(countersKey, data);
+ this.countersKey = countersKey;
this.counters = data;
raf.scheduleRedraw();
diff --git a/ui/src/frontend/post_message_handler.ts b/ui/src/frontend/post_message_handler.ts
index 7a7addc..8220b44 100644
--- a/ui/src/frontend/post_message_handler.ts
+++ b/ui/src/frontend/post_message_handler.ts
@@ -35,7 +35,7 @@
// Returns whether incoming traces should be opened automatically or should
// instead require a user interaction.
-function isTrustedOrigin(origin: string): boolean {
+export function isTrustedOrigin(origin: string): boolean {
const TRUSTED_ORIGINS = [
'https://chrometto.googleplex.com',
'https://uma.googleplex.com',
@@ -46,8 +46,15 @@
if (isUserTrustedOrigin(origin)) return true;
const hostname = new URL(origin).hostname;
- if (hostname.endsWith('corp.google.com')) return true;
- if (hostname === 'localhost' || hostname === '127.0.0.1') return true;
+ if (hostname.endsWith('.corp.google.com')) return true;
+ if (hostname.endsWith('.c.googlers.com')) return true;
+ if (
+ hostname === 'localhost' ||
+ hostname === '127.0.0.1' ||
+ hostname === '[::1]'
+ ) {
+ return true;
+ }
return false;
}
diff --git a/ui/src/frontend/post_message_handler_unittest.ts b/ui/src/frontend/post_message_handler_unittest.ts
new file mode 100644
index 0000000..c18aff6
--- /dev/null
+++ b/ui/src/frontend/post_message_handler_unittest.ts
@@ -0,0 +1,53 @@
+// Copyright (C) 2024 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.
+
+import {isTrustedOrigin} from './post_message_handler';
+
+describe('postMessageHandler', () => {
+ test('baked-in trusted origins are trusted', () => {
+ expect(isTrustedOrigin('https://chrometto.googleplex.com')).toBeTruthy();
+ expect(isTrustedOrigin('https://uma.googleplex.com')).toBeTruthy();
+ expect(
+ isTrustedOrigin('https://android-build.googleplex.com'),
+ ).toBeTruthy();
+ expect(isTrustedOrigin('https://html5zombo.com')).toBeFalsy();
+ });
+
+ test('user trusted origins in local storage are trusted', () => {
+ try {
+ expect(isTrustedOrigin('https://html5zombo.com')).toBeFalsy();
+ window.localStorage['trustedOrigins'] = '["https://html5zombo.com"]';
+ expect(isTrustedOrigin('https://html5zombo.com')).toBeTruthy();
+ } finally {
+ window.localStorage.clear();
+ }
+ });
+
+ test('developer hostnames are trusted', () => {
+ expect(isTrustedOrigin('https://google.com')).toBeFalsy();
+ expect(isTrustedOrigin('https://broccoliman.corp.google.com')).toBeTruthy();
+ expect(isTrustedOrigin('http://broccoliman.corp.google.com')).toBeTruthy();
+ expect(isTrustedOrigin('https://broccoliman.c.googlers.com')).toBeTruthy();
+ expect(isTrustedOrigin('http://broccoliman.c.googlers.com')).toBeTruthy();
+ expect(isTrustedOrigin('https://broccolimancorp.google.com')).toBeFalsy();
+ expect(isTrustedOrigin('https://broccolimanc.googlers.com')).toBeFalsy();
+ expect(isTrustedOrigin('https://localhost')).toBeTruthy();
+ expect(isTrustedOrigin('http://localhost')).toBeTruthy();
+ expect(isTrustedOrigin('https://127.0.0.1')).toBeTruthy();
+ expect(isTrustedOrigin('http://127.0.0.1')).toBeTruthy();
+ // IPv6 localhost
+ expect(isTrustedOrigin('https://[::1]')).toBeTruthy();
+ expect(isTrustedOrigin('http://[::1]')).toBeTruthy();
+ });
+});
diff --git a/ui/src/tracks/android_log/index.ts b/ui/src/tracks/android_log/index.ts
index c35143e..7247376 100644
--- a/ui/src/tracks/android_log/index.ts
+++ b/ui/src/tracks/android_log/index.ts
@@ -15,11 +15,7 @@
import m from 'mithril';
import {LogFilteringCriteria, LogPanel} from './logs_panel';
-import {
- Plugin,
- PluginContextTrace,
- PluginDescriptor,
-} from '../../public';
+import {Plugin, PluginContextTrace, PluginDescriptor} from '../../public';
import {NUM} from '../../trace_processor/query_result';
import {AndroidLogTrack} from './logs_track';
diff --git a/ui/src/tracks/counter/index.ts b/ui/src/tracks/counter/index.ts
index 2ac64d6..a459c8a 100644
--- a/ui/src/tracks/counter/index.ts
+++ b/ui/src/tracks/counter/index.ts
@@ -133,19 +133,22 @@
onMouseClick({x}: {x: number}): boolean {
const {visibleTimeScale} = globals.timeline;
- const time = visibleTimeScale.pxToHpTime(x);
+ const time = visibleTimeScale.pxToHpTime(x).toTime('floor');
- const result = this.engine.query(`
-
- select
+ const query = `
+ SELECT
id,
ts as leftTs,
- max(ts) OVER (ROWS BETWEEN CURRENT ROW AND 1 FOLLOWING) as rightTs
- from
- ${this.rootTable}
- where track_id = ${this.trackId} and ts > ${time} limit 1`);
+ min(ts) OVER (ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) as rightTs
+ FROM ${this.rootTable}
+ WHERE
+ track_id = ${this.trackId} AND
+ ts < ${time}
+ ORDER BY ts DESC
+ LIMIT 1
+ `;
- result.then((result) => {
+ this.engine.query(query).then((result) => {
const it = result.iter({
id: NUM,
leftTs: LONG,