1 /*
2  * Copyright (C) 2019 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 #ifndef SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_SCHED_EVENT_TRACKER_H_
18 #define SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_SCHED_EVENT_TRACKER_H_
19 
20 #include <array>
21 #include <limits>
22 
23 #include "perfetto/ext/base/string_view.h"
24 #include "perfetto/ext/base/utils.h"
25 #include "src/trace_processor/storage/trace_storage.h"
26 #include "src/trace_processor/types/destructible.h"
27 #include "src/trace_processor/types/trace_processor_context.h"
28 
29 namespace perfetto {
30 namespace trace_processor {
31 
32 class EventTracker;
33 
34 // Tracks sched events and stores them into the storage as sched slices.
35 class SchedEventTracker : public Destructible {
36  public:
37   // Declared public for testing only.
38   explicit SchedEventTracker(TraceProcessorContext*);
39   SchedEventTracker(const SchedEventTracker&) = delete;
40   SchedEventTracker& operator=(const SchedEventTracker&) = delete;
41   ~SchedEventTracker() override;
GetOrCreate(TraceProcessorContext * context)42   static SchedEventTracker* GetOrCreate(TraceProcessorContext* context) {
43     if (!context->sched_tracker) {
44       context->sched_tracker.reset(new SchedEventTracker(context));
45     }
46     return static_cast<SchedEventTracker*>(context->sched_tracker.get());
47   }
48 
49   // This method is called when a sched_switch event is seen in the trace.
50   // Virtual for testing.
51   virtual void PushSchedSwitch(uint32_t cpu,
52                                int64_t timestamp,
53                                uint32_t prev_pid,
54                                base::StringView prev_comm,
55                                int32_t prev_prio,
56                                int64_t prev_state,
57                                uint32_t next_pid,
58                                base::StringView next_comm,
59                                int32_t next_prio);
60 
61   // This method is called when parsing a sched_switch encoded in the compact
62   // format.
63   void PushSchedSwitchCompact(uint32_t cpu,
64                               int64_t ts,
65                               int64_t prev_state,
66                               uint32_t next_pid,
67                               int32_t next_prio,
68                               StringId next_comm_id);
69 
70   // This method is called when parsing a sched_waking encoded in the compact
71   // format. Note that the default encoding is handled by
72   // |EventTracker::PushInstant|.
73   void PushSchedWakingCompact(uint32_t cpu,
74                               int64_t ts,
75                               uint32_t wakee_pid,
76                               int32_t target_cpu,
77                               int32_t prio,
78                               StringId comm_id);
79 
80   // Called at the end of trace to flush any events which are pending to the
81   // storage.
82   void FlushPendingEvents();
83 
84  private:
85   // Information retained from the preceding sched_switch seen on a given cpu.
86   struct PendingSchedInfo {
87     // The pending scheduling slice that the next event will complete.
88     uint32_t pending_slice_storage_idx = std::numeric_limits<uint32_t>::max();
89 
90     // pid/utid/prio corresponding to the last sched_switch seen on this cpu
91     // (its "next_*" fields). There is some duplication with respect to the
92     // slices storage, but we don't always have a slice when decoding events in
93     // the compact format.
94     uint32_t last_pid = std::numeric_limits<uint32_t>::max();
95     UniqueTid last_utid = std::numeric_limits<UniqueTid>::max();
96     int32_t last_prio = std::numeric_limits<int32_t>::max();
97   };
98 
99   uint32_t AddRawEventAndStartSlice(uint32_t cpu,
100                                     int64_t ts,
101                                     UniqueTid prev_utid,
102                                     uint32_t prev_pid,
103                                     StringId prev_comm_id,
104                                     int32_t prev_prio,
105                                     int64_t prev_state,
106                                     UniqueTid next_utid,
107                                     uint32_t next_pid,
108                                     StringId next_comm_id,
109                                     int32_t next_prio);
110 
111   void ClosePendingSlice(uint32_t slice_idx, int64_t ts, int64_t prev_state);
112 
113   // Infromation retained from the preceding sched_switch seen on a given cpu.
114   std::array<PendingSchedInfo, kMaxCpus> pending_sched_per_cpu_{};
115 
116   static constexpr uint8_t kSchedSwitchMaxFieldId = 7;
117   std::array<StringId, kSchedSwitchMaxFieldId + 1> sched_switch_field_ids_;
118   StringId sched_switch_id_;
119 
120   static constexpr uint8_t kSchedWakingMaxFieldId = 5;
121   std::array<StringId, kSchedWakingMaxFieldId + 1> sched_waking_field_ids_;
122   StringId sched_waking_id_;
123 
124   TraceProcessorContext* const context_;
125 };
126 
127 }  // namespace trace_processor
128 }  // namespace perfetto
129 
130 #endif  // SRC_TRACE_PROCESSOR_IMPORTERS_FTRACE_SCHED_EVENT_TRACKER_H_
131