blob: c95c41d3023acbedcdec5b9dbb77b7162f2c7afd [file] [log] [blame]
Lalit Maganticaed37e2018-06-01 03:03:08 +01001/*
2 * Copyright (C) 2017 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_TRACE_STORAGE_H_
18#define SRC_TRACE_PROCESSOR_TRACE_STORAGE_H_
19
Lalit Maganti35622b72018-06-06 12:03:11 +010020#include <array>
Lalit Maganticaed37e2018-06-01 03:03:08 +010021#include <deque>
Isabelle Taylor47328cf2018-06-12 14:33:59 +010022#include <map>
Lalit Maganticaed37e2018-06-01 03:03:08 +010023#include <string>
24#include <unordered_map>
25#include <vector>
26
Lalit Maganti35622b72018-06-06 12:03:11 +010027#include "perfetto/base/logging.h"
28
Lalit Maganticaed37e2018-06-01 03:03:08 +010029namespace perfetto {
30namespace trace_processor {
31
32// Stores a data inside a trace file in a columnar form. This makes it efficient
33// to read or search across a single field of the trace (e.g. all the thread
34// names for a given CPU).
35class TraceStorage {
36 public:
Isabelle Taylor47328cf2018-06-12 14:33:59 +010037 TraceStorage();
38
Lalit Maganti35622b72018-06-06 12:03:11 +010039 constexpr static size_t kMaxCpus = 128;
Isabelle Taylor68e42192018-06-19 16:19:31 +010040
Isabelle Taylor47328cf2018-06-12 14:33:59 +010041 // StringId is an offset into |string_pool_|.
Lalit Maganti35622b72018-06-06 12:03:11 +010042 using StringId = size_t;
Isabelle Taylor68e42192018-06-19 16:19:31 +010043
Isabelle Taylor47328cf2018-06-12 14:33:59 +010044 // UniquePid is an offset into |unique_processes_|. This is necessary because
45 // Unix pids are reused and thus not guaranteed to be unique over a long
46 // period of time.
47 using UniquePid = uint32_t;
Isabelle Taylor68e42192018-06-19 16:19:31 +010048
49 // UniqueTid is an offset into |unique_threads_|. Necessary because tids can
50 // be reused.
51 using UniqueTid = uint32_t;
Isabelle Taylor47328cf2018-06-12 14:33:59 +010052 using UniqueProcessIterator =
53 std::multimap<uint32_t, UniquePid>::const_iterator;
54 using UniqueProcessRange =
55 std::pair<UniqueProcessIterator, UniqueProcessIterator>;
Lalit Maganti35622b72018-06-06 12:03:11 +010056
57 class SlicesPerCpu {
58 public:
59 inline void AddSlice(uint64_t start_ns,
60 uint64_t duration_ns,
Isabelle Taylor68e42192018-06-19 16:19:31 +010061 uint32_t tid,
Lalit Maganti35622b72018-06-06 12:03:11 +010062 StringId thread_name_id) {
63 start_ns_.emplace_back(start_ns);
64 durations_.emplace_back(duration_ns);
Isabelle Taylor68e42192018-06-19 16:19:31 +010065
66 auto pair_it = storage_->tids_.equal_range(tid);
67
68 // If there is a previous utid for that tid, use that.
69 if (pair_it.first != pair_it.second) {
70 UniqueTid prev_utid = std::prev(pair_it.second)->second;
71 utids_.emplace_back(prev_utid);
72 } else {
73 // If none exist, assign a new utid and store it.
74 TaskInfo new_thread;
75 new_thread.name_id = thread_name_id;
76 new_thread.start_ns = start_ns;
77 storage_->tids_.emplace(tid, storage_->unique_threads_.size());
78 utids_.emplace_back(storage_->unique_threads_.size());
79 storage_->unique_threads_.emplace_back(std::move(new_thread));
80 }
Lalit Maganti35622b72018-06-06 12:03:11 +010081 }
82
Isabelle Taylor47328cf2018-06-12 14:33:59 +010083 size_t slice_count() const { return start_ns_.size(); }
Lalit Maganti35622b72018-06-06 12:03:11 +010084
Isabelle Taylor47328cf2018-06-12 14:33:59 +010085 const std::deque<uint64_t>& start_ns() const { return start_ns_; }
Lalit Maganti35622b72018-06-06 12:03:11 +010086
Isabelle Taylor47328cf2018-06-12 14:33:59 +010087 const std::deque<uint64_t>& durations() const { return durations_; }
Lalit Maganti35622b72018-06-06 12:03:11 +010088
Isabelle Taylor68e42192018-06-19 16:19:31 +010089 const std::deque<UniqueTid>& utids() const { return utids_; }
90
91 void InitalizeSlices(TraceStorage* storage) { storage_ = storage; }
92
Lalit Maganti35622b72018-06-06 12:03:11 +010093 private:
94 // Each vector below has the same number of entries (the number of slices
95 // in the trace for the CPU).
96 std::deque<uint64_t> start_ns_;
97 std::deque<uint64_t> durations_;
Isabelle Taylor68e42192018-06-19 16:19:31 +010098 std::deque<UniqueTid> utids_;
99
100 TraceStorage* storage_;
Lalit Maganti35622b72018-06-06 12:03:11 +0100101 };
102
103 struct Stats {
104 uint64_t mismatched_sched_switch_tids_ = 0;
105 };
106
107 virtual ~TraceStorage();
108
Isabelle Taylor68e42192018-06-19 16:19:31 +0100109 // Information about a unique process or thread seen in a trace.
110 struct TaskInfo {
111 uint64_t start_ns = 0;
112 uint64_t end_ns = 0;
113 StringId name_id;
Isabelle Taylor47328cf2018-06-12 14:33:59 +0100114 };
115
Lalit Maganticaed37e2018-06-01 03:03:08 +0100116 // Adds a sched slice for a given cpu.
Lalit Maganti35622b72018-06-06 12:03:11 +0100117 // Virtual for testing.
118 virtual void PushSchedSwitch(uint32_t cpu,
119 uint64_t timestamp,
120 uint32_t prev_pid,
121 uint32_t prev_state,
122 const char* prev_comm,
123 size_t prev_comm_len,
124 uint32_t next_pid);
Lalit Maganticaed37e2018-06-01 03:03:08 +0100125
Isabelle Taylor47328cf2018-06-12 14:33:59 +0100126 // Adds a process entry for a given pid.
127 virtual void PushProcess(uint32_t pid,
128 const char* process_name,
129 size_t process_name_len);
130
131 // Returns the bounds of a range that includes all UniquePids that have the
132 // requested pid.
133 UniqueProcessRange UpidsForPid(uint32_t pid);
134
Lalit Maganticaed37e2018-06-01 03:03:08 +0100135 // Reading methods.
Lalit Maganti35622b72018-06-06 12:03:11 +0100136 const SlicesPerCpu& SlicesForCpu(uint32_t cpu) const {
Isabelle Taylor47328cf2018-06-12 14:33:59 +0100137 PERFETTO_CHECK(cpu < cpu_events_.size());
Lalit Maganti35622b72018-06-06 12:03:11 +0100138 return cpu_events_[cpu];
Lalit Maganticaed37e2018-06-01 03:03:08 +0100139 }
140
Isabelle Taylor68e42192018-06-19 16:19:31 +0100141 const TaskInfo& GetProcess(UniquePid upid) {
Isabelle Taylor47328cf2018-06-12 14:33:59 +0100142 PERFETTO_CHECK(upid < unique_processes_.size());
143 return unique_processes_[upid];
144 }
145
Isabelle Taylor68e42192018-06-19 16:19:31 +0100146 const TaskInfo& GetThread(UniqueTid utid) {
147 PERFETTO_CHECK(utid < unique_threads_.size());
148 return unique_threads_[utid];
149 }
150
Isabelle Taylor47328cf2018-06-12 14:33:59 +0100151 const std::string& GetString(StringId id) {
152 PERFETTO_CHECK(id < string_pool_.size());
153 return string_pool_[id];
154 }
155
Lalit Maganticaed37e2018-06-01 03:03:08 +0100156 private:
Lalit Maganti35622b72018-06-06 12:03:11 +0100157 using StringHash = uint32_t;
Lalit Maganticaed37e2018-06-01 03:03:08 +0100158
Lalit Maganti35622b72018-06-06 12:03:11 +0100159 struct SchedSwitchEvent {
160 uint64_t cpu = 0;
161 uint64_t timestamp = 0;
162 uint32_t prev_pid = 0;
163 uint32_t prev_state = 0;
Isabelle Taylor68e42192018-06-19 16:19:31 +0100164 StringId prev_thread_name_id = 0;
Lalit Maganti35622b72018-06-06 12:03:11 +0100165 uint32_t next_pid = 0;
Lalit Maganticaed37e2018-06-01 03:03:08 +0100166
Lalit Maganti35622b72018-06-06 12:03:11 +0100167 bool valid() const { return timestamp != 0; }
Lalit Maganticaed37e2018-06-01 03:03:08 +0100168 };
169
Lalit Maganti35622b72018-06-06 12:03:11 +0100170 // Return an unqiue identifier for the contents of each string.
171 // The string is copied internally and can be destroyed after this called.
172 StringId InternString(const char* data, size_t length);
173
174 // Metadata counters for events being added.
175 Stats stats_;
176
Lalit Maganticaed37e2018-06-01 03:03:08 +0100177 // One entry for each CPU in the trace.
Lalit Maganti35622b72018-06-06 12:03:11 +0100178 std::array<SchedSwitchEvent, kMaxCpus> last_sched_per_cpu_;
179
180 // One entry for each CPU in the trace.
181 std::array<SlicesPerCpu, kMaxCpus> cpu_events_;
Lalit Maganticaed37e2018-06-01 03:03:08 +0100182
183 // One entry for each unique string in the trace.
Lalit Maganti35622b72018-06-06 12:03:11 +0100184 std::deque<std::string> string_pool_;
Lalit Maganticaed37e2018-06-01 03:03:08 +0100185
186 // One entry for each unique string in the trace.
Lalit Maganti35622b72018-06-06 12:03:11 +0100187 std::unordered_map<StringHash, StringId> string_index_;
Isabelle Taylor47328cf2018-06-12 14:33:59 +0100188
189 // Each pid can have multiple UniquePid entries, a new UniquePid is assigned
190 // each time a process is seen in the trace.
191 std::multimap<uint32_t, UniquePid> pids_;
192
193 // One entry for each UniquePid, with UniquePid as the index.
Isabelle Taylor68e42192018-06-19 16:19:31 +0100194 std::deque<TaskInfo> unique_processes_;
195
196 // Each tid can have multiple UniqueTid entries, a new UniqueTid is assigned
197 // each time a thread is seen in the trace.
198 std::multimap<uint32_t, UniqueTid> tids_;
199
200 // One entry for each UniqueTid, with UniqueTid as the index.
201 std::deque<TaskInfo> unique_threads_;
Lalit Maganticaed37e2018-06-01 03:03:08 +0100202};
203
204} // namespace trace_processor
205} // namespace perfetto
206
207#endif // SRC_TRACE_PROCESSOR_TRACE_STORAGE_H_