xref: /aosp_15_r20/external/perfetto/src/trace_redaction/collect_timeline_events.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/trace_redaction/collect_timeline_events.h"
18 
19 #include "src/trace_redaction/process_thread_timeline.h"
20 #include "src/trace_redaction/trace_redaction_framework.h"
21 
22 #include "protos/perfetto/trace/ftrace/ftrace_event.pbzero.h"
23 #include "protos/perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"
24 #include "protos/perfetto/trace/ftrace/sched.pbzero.h"
25 #include "protos/perfetto/trace/ftrace/task.pbzero.h"
26 #include "protos/perfetto/trace/ps/process_tree.pbzero.h"
27 #include "protos/perfetto/trace/trace_packet.pbzero.h"
28 
29 namespace perfetto::trace_redaction {
30 namespace {
31 
32 using TracePacket = protos::pbzero::TracePacket;
33 using ProcessTree = protos::pbzero::ProcessTree;
34 using FtraceEvent = protos::pbzero::FtraceEvent;
35 using FtraceEventBundle = protos::pbzero::FtraceEventBundle;
36 using SchedProcessFreeFtraceEvent = protos::pbzero::SchedProcessFreeFtraceEvent;
37 using TaskNewtaskFtraceEvent = protos::pbzero::TaskNewtaskFtraceEvent;
38 
MarkOpen(uint64_t ts,const ProcessTree::Process::Decoder & process,ProcessThreadTimeline * timeline)39 void MarkOpen(uint64_t ts,
40               const ProcessTree::Process::Decoder& process,
41               ProcessThreadTimeline* timeline) {
42   auto uid = static_cast<uint64_t>(process.uid());
43 
44   // See "trace_redaction_framework.h" for why uid must be normalized.
45   auto e = ProcessThreadTimeline::Event::Open(ts, process.pid(), process.ppid(),
46                                               NormalizeUid(uid));
47   timeline->Append(e);
48 }
49 
MarkOpen(uint64_t ts,const ProcessTree::Thread::Decoder & thread,ProcessThreadTimeline * timeline)50 void MarkOpen(uint64_t ts,
51               const ProcessTree::Thread::Decoder& thread,
52               ProcessThreadTimeline* timeline) {
53   auto e = ProcessThreadTimeline::Event::Open(ts, thread.tid(), thread.tgid());
54   timeline->Append(e);
55 }
56 
MarkClose(const FtraceEvent::Decoder & event,const SchedProcessFreeFtraceEvent::Decoder process_free,ProcessThreadTimeline * timeline)57 void MarkClose(const FtraceEvent::Decoder& event,
58                const SchedProcessFreeFtraceEvent::Decoder process_free,
59                ProcessThreadTimeline* timeline) {
60   auto e = ProcessThreadTimeline::Event::Close(event.timestamp(),
61                                                process_free.pid());
62   timeline->Append(e);
63 }
64 
MarkOpen(const FtraceEvent::Decoder & event,const TaskNewtaskFtraceEvent::Decoder new_task,ProcessThreadTimeline * timeline)65 void MarkOpen(const FtraceEvent::Decoder& event,
66               const TaskNewtaskFtraceEvent::Decoder new_task,
67               ProcessThreadTimeline* timeline) {
68   // Event though pid() is uint32_t. all other pid values use int32_t, so it's
69   // assumed to be safe to narrow-cast it.
70   auto ppid = static_cast<int32_t>(event.pid());
71   auto e = ProcessThreadTimeline::Event::Open(event.timestamp(), new_task.pid(),
72                                               ppid);
73   timeline->Append(e);
74 }
75 
AppendEvents(uint64_t ts,const ProcessTree::Decoder & tree,ProcessThreadTimeline * timeline)76 void AppendEvents(uint64_t ts,
77                   const ProcessTree::Decoder& tree,
78                   ProcessThreadTimeline* timeline) {
79   for (auto it = tree.processes(); it; ++it) {
80     MarkOpen(ts, ProcessTree::Process::Decoder(*it), timeline);
81   }
82 
83   for (auto it = tree.threads(); it; ++it) {
84     MarkOpen(ts, ProcessTree::Thread::Decoder(*it), timeline);
85   }
86 }
87 
AppendEvents(const FtraceEventBundle::Decoder & ftrace_events,ProcessThreadTimeline * timeline)88 void AppendEvents(const FtraceEventBundle::Decoder& ftrace_events,
89                   ProcessThreadTimeline* timeline) {
90   for (auto it = ftrace_events.event(); it; ++it) {
91     FtraceEvent::Decoder event(*it);
92 
93     if (event.has_task_newtask()) {
94       MarkOpen(event, TaskNewtaskFtraceEvent::Decoder(event.task_newtask()),
95                timeline);
96       continue;
97     }
98 
99     if (event.has_sched_process_free()) {
100       MarkClose(
101           event,
102           SchedProcessFreeFtraceEvent::Decoder(event.sched_process_free()),
103           timeline);
104       continue;
105     }
106   }
107 }
108 
109 }  // namespace
110 
Begin(Context * context) const111 base::Status CollectTimelineEvents::Begin(Context* context) const {
112   // This primitive is artifically limited to owning the timeline. In practice
113   // there is no reason why multiple primitives could contribute to the
114   // timeline.
115   if (context->timeline) {
116     return base::ErrStatus(
117         "CollectTimelineEvents: timeline was already initialized");
118   }
119 
120   context->timeline = std::make_unique<ProcessThreadTimeline>();
121   return base::OkStatus();
122 }
123 
Collect(const TracePacket::Decoder & packet,Context * context) const124 base::Status CollectTimelineEvents::Collect(const TracePacket::Decoder& packet,
125                                             Context* context) const {
126   // Unlike ftrace events, process trees do not provide per-process or
127   // per-thread timing information. The packet has timestamp and the process
128   // tree has collection_end_timestamp (collection_end_timestamp > timestamp).
129   //
130   // The packet's timestamp based on the assumption that in order to be
131   // collected, the processes and threads had to exist before "now".
132   if (packet.has_process_tree()) {
133     AppendEvents(packet.timestamp(),
134                  ProcessTree::Decoder(packet.process_tree()),
135                  context->timeline.get());
136   }
137 
138   if (packet.has_ftrace_events()) {
139     AppendEvents(FtraceEventBundle::Decoder(packet.ftrace_events()),
140                  context->timeline.get());
141   }
142 
143   return base::OkStatus();
144 }
145 
End(Context * context) const146 base::Status CollectTimelineEvents::End(Context* context) const {
147   // Sort must be called in order to read from the timeline. If any more events
148   // are added after this, then sort will need to be called again.
149   context->timeline->Sort();
150   return base::OkStatus();
151 }
152 
153 }  // namespace perfetto::trace_redaction
154