From e096209b43d7d8a4e765cc726143e590f4ba457a Mon Sep 17 00:00:00 2001 From: Rahul Dandamudi Date: Fri, 6 Oct 2023 10:28:32 -0400 Subject: [PATCH] Parsing android_fs_read events In this CL we re adding support to parse the android_fs events, one issue here is that a read start and read end events can happen on different thread we keep track of things by using a map with inode, offset and threadId to track the start and end events. Change-Id: I14fd317083ae3ac4c6bb39323ed88bb97837fab1 --- .../importers/ftrace/ftrace_parser.cc | 80 +++++++++++++++++-- .../importers/ftrace/ftrace_parser.h | 25 ++++++ .../diff_tests/android_fs/tests.py | 67 ++++++++++++++++ .../diff_tests/include_index.py | 2 + 4 files changed, 169 insertions(+), 5 deletions(-) create mode 100644 test/trace_processor/diff_tests/android_fs/tests.py diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.cc b/src/trace_processor/importers/ftrace/ftrace_parser.cc index 31a6c7e93b..dd5c7243dd 100644 --- a/src/trace_processor/importers/ftrace/ftrace_parser.cc +++ b/src/trace_processor/importers/ftrace/ftrace_parser.cc @@ -38,8 +38,8 @@ #include "src/trace_processor/storage/trace_storage.h" #include "src/trace_processor/types/softirq_action.h" #include "src/trace_processor/types/tcp_state.h" - #include "protos/perfetto/common/gpu_counter_descriptor.pbzero.h" +#include "protos/perfetto/trace/ftrace/android_fs.pbzero.h" #include "protos/perfetto/trace/ftrace/binder.pbzero.h" #include "protos/perfetto/trace/ftrace/cma.pbzero.h" #include "protos/perfetto/trace/ftrace/cpuhp.pbzero.h" @@ -217,8 +217,7 @@ std::string GetUfsCmdString(uint32_t ufsopcode, uint32_t gid) { } return buffer; } -} // namespace - +} // namespace FtraceParser::FtraceParser(TraceProcessorContext* context) : context_(context), rss_stat_tracker_(context), @@ -315,7 +314,15 @@ FtraceParser::FtraceParser(TraceProcessorContext* context) cma_nr_test_fail_id_(context_->storage->InternString("cma_nr_test_fail")), syscall_ret_id_(context->storage->InternString("ret")), syscall_args_id_(context->storage->InternString("args")), - replica_slice_id_(context->storage->InternString("replica_slice")) { + replica_slice_id_(context->storage->InternString("replica_slice")), + file_path_id_(context_->storage->InternString("file_path")), + offset_id_start_(context_->storage->InternString("offset_start")), + offset_id_end_(context_->storage->InternString("offset_end")), + bytes_read_id_start_(context_->storage->InternString("bytes_read_start")), + bytes_read_id_end_(context_->storage->InternString("bytes_read_end")), + android_fs_category_id_(context_->storage->InternString("android_fs")), + android_fs_data_read_id_( + context_->storage->InternString("android_fs_data_read")) { // Build the lookup table for the strings inside ftrace events (e.g. the // name of ftrace event fields and the names of their args). for (size_t i = 0; i < GetDescriptorsSize(); i++) { @@ -1047,7 +1054,14 @@ util::Status FtraceParser::ParseFtraceEvent(uint32_t cpu, ParseMdssTracingMarkWrite(ts, pid, fld_bytes); break; } - + case FtraceEvent::kAndroidFsDatareadEndFieldNumber: { + ParseAndroidFsDatareadEnd(ts, fld_bytes); + break; + } + case FtraceEvent::kAndroidFsDatareadStartFieldNumber: { + ParseAndroidFsDatareadStart(ts, pid, fld_bytes); + break; + } default: break; } @@ -3092,6 +3106,62 @@ void FtraceParser::ParseFuncgraphExit( context_->slice_tracker->End(timestamp, track, kNullStringId, name_id); } +/** Parses android_fs_dataread_start event.*/ +void FtraceParser::ParseAndroidFsDatareadStart(int64_t ts, + uint32_t pid, + ConstBytes data) { + protos::pbzero::AndroidFsDatareadStartFtraceEvent::Decoder + android_fs_read_begin(data); + base::StringView file_path(android_fs_read_begin.pathbuf()); + std::pair key(android_fs_read_begin.ino(), + android_fs_read_begin.offset()); + inode_offset_thread_map_.Insert(key, pid); + // Create a new Track object for the event. + auto async_track = context_->async_track_set_tracker->InternGlobalTrackSet( + android_fs_category_id_); + TrackId track_id = context_->async_track_set_tracker->Begin(async_track, pid); + StringId string_id = context_->storage->InternString(file_path); + auto args_inserter = [this, &android_fs_read_begin, + &string_id](ArgsTracker::BoundInserter* inserter) { + inserter->AddArg(file_path_id_, Variadic::String(string_id)); + inserter->AddArg(offset_id_start_, + Variadic::Integer(android_fs_read_begin.offset())); + inserter->AddArg(bytes_read_id_start_, + Variadic::Integer(android_fs_read_begin.bytes())); + }; + context_->slice_tracker->Begin(ts, track_id, kNullStringId, + android_fs_data_read_id_, args_inserter); +} + +/** Parses android_fs_dataread_end event.*/ +void FtraceParser::ParseAndroidFsDatareadEnd(int64_t ts, ConstBytes data) { + protos::pbzero::AndroidFsDatareadEndFtraceEvent::Decoder android_fs_read_end( + data); + std::pair key(android_fs_read_end.ino(), + android_fs_read_end.offset()); + // Find the corresponding (inode, offset) pair in the map. + auto it = inode_offset_thread_map_.Find(key); + if (!it) { + return; + } + uint32_t start_event_tid = *it; + auto async_track = context_->async_track_set_tracker->InternGlobalTrackSet( + android_fs_category_id_); + TrackId track_id = + context_->async_track_set_tracker->End(async_track, start_event_tid); + auto args_inserter = + [this, &android_fs_read_end](ArgsTracker::BoundInserter* inserter) { + inserter->AddArg(offset_id_end_, + Variadic::Integer(android_fs_read_end.offset())); + inserter->AddArg(bytes_read_id_end_, + Variadic::Integer(android_fs_read_end.bytes())); + }; + context_->slice_tracker->End(ts, track_id, kNullStringId, kNullStringId, + args_inserter); + // Erase the entry from the map. + inode_offset_thread_map_.Erase(key); +} + StringId FtraceParser::InternedKernelSymbolOrFallback( uint64_t key, PacketSequenceStateGeneration* seq_state) { diff --git a/src/trace_processor/importers/ftrace/ftrace_parser.h b/src/trace_processor/importers/ftrace/ftrace_parser.h index 174861de1e..8003fb1202 100644 --- a/src/trace_processor/importers/ftrace/ftrace_parser.h +++ b/src/trace_processor/importers/ftrace/ftrace_parser.h @@ -17,6 +17,8 @@ #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_FTRACE_PARSER_H_ #define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_FTRACE_PARSER_H_ +#include "perfetto/ext/base/flat_hash_map.h" +#include "perfetto/ext/base/hash.h" #include "perfetto/trace_processor/status.h" #include "src/trace_processor/importers/common/event_tracker.h" #include "src/trace_processor/importers/common/parser_types.h" @@ -285,6 +287,10 @@ class FtraceParser { void ParseMaliKcpuFenceSignal(uint32_t pid, int64_t ts); void ParseMaliKcpuFenceWaitStart(uint32_t pid, int64_t ts); void ParseMaliKcpuFenceWaitEnd(uint32_t pid, int64_t ts); + void ParseAndroidFsDatareadEnd(int64_t timestamp, protozero::ConstBytes); + void ParseAndroidFsDatareadStart(int64_t ts, + uint32_t pid, + protozero::ConstBytes); TraceProcessorContext* context_; RssStatTracker rss_stat_tracker_; @@ -366,6 +372,13 @@ class FtraceParser { const StringId syscall_ret_id_; const StringId syscall_args_id_; const StringId replica_slice_id_; + const StringId file_path_id_; + const StringId offset_id_start_; + const StringId offset_id_end_; + const StringId bytes_read_id_start_; + const StringId bytes_read_id_end_; + const StringId android_fs_category_id_; + const StringId android_fs_data_read_id_; std::vector syscall_arg_name_ids_; struct FtraceMessageStrings { @@ -428,6 +441,18 @@ class FtraceParser { // putting them in the metadata multiple times (the ftrace data sources // re-emits begin stats on every flush). std::unordered_set seen_errors_for_sequence_id_; + + struct PairHash { + std::size_t operator()(const std::pair& p) const { + base::Hasher hasher; + hasher.Update(p.first); + hasher.Update(p.second); + return static_cast(hasher.digest()); + } + }; + + base::FlatHashMap, uint32_t, PairHash> + inode_offset_thread_map_; }; } // namespace trace_processor diff --git a/test/trace_processor/diff_tests/android_fs/tests.py b/test/trace_processor/diff_tests/android_fs/tests.py new file mode 100644 index 0000000000..358384dfd1 --- /dev/null +++ b/test/trace_processor/diff_tests/android_fs/tests.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# Copyright (C) 2023 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License 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, 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 TestSuite + + +class AndroidFs(TestSuite): + + # android_fs_dataread + def test_android_fs_dataread(self): + return DiffTestBlueprint( + trace=TextProto(r""" + packet { + ftrace_events { + cpu: 0 + event { + timestamp: 46448185788840 + pid: 5892 + android_fs_dataread_start { + bytes: 4096 + pid: 5892 + ino: 836 + offset: 0 + cmdline: "am" + i_size: 31772 + pathbuf: "/system/bin/cmd" + } + } + } + } + packet { + ftrace_events { + cpu: 0 + event { + timestamp: 46448185789530 + pid: 156 + android_fs_dataread_end { + bytes: 4096 + ino: 836 + offset: 0 + } + } + } + } + """), + query=""" + SELECT ts, dur, name FROM slice WHERE name = 'android_fs_data_read'; + """, + out=Csv(""" + "ts","dur","name" + 46448185788840,690,"android_fs_data_read" + """)) diff --git a/test/trace_processor/diff_tests/include_index.py b/test/trace_processor/diff_tests/include_index.py index b96052071d..b131e43538 100644 --- a/test/trace_processor/diff_tests/include_index.py +++ b/test/trace_processor/diff_tests/include_index.py @@ -94,6 +94,7 @@ from diff_tests.translation.tests import Translation from diff_tests.ufs.tests import Ufs from diff_tests.webview.tests import WebView +from diff_tests.android_fs.tests import AndroidFs sys.path.pop() @@ -102,6 +103,7 @@ def fetch_all_diff_tests(index_path: str) -> List['testing.TestCase']: return [ *Android(index_path, 'android', 'Android').fetch(), *AndroidBugreport(index_path, 'android', 'AndroidBugreport').fetch(), + *AndroidFs(index_path, 'android_fs', 'AndroidFs').fetch(), *AndroidGames(index_path, 'android', 'AndroidGames').fetch(), *Atrace(index_path, 'atrace', 'Atrace').fetch(), *AtraceErrorHandling(index_path, 'atrace', 'AtraceErrorHandling').fetch(),