/src/perfetto/src/traced/probes/ftrace/ftrace_metadata.h
Line | Count | Source |
1 | | /* |
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_TRACED_PROBES_FTRACE_FTRACE_METADATA_H_ |
18 | | #define SRC_TRACED_PROBES_FTRACE_FTRACE_METADATA_H_ |
19 | | |
20 | | #include <stdint.h> |
21 | | #include <sys/stat.h> |
22 | | #include <unistd.h> |
23 | | |
24 | | #include <bitset> |
25 | | |
26 | | #include "perfetto/base/flat_set.h" |
27 | | #include "perfetto/base/logging.h" |
28 | | #include "perfetto/ext/traced/data_source_types.h" |
29 | | |
30 | | namespace perfetto { |
31 | | |
32 | | using BlockDeviceID = decltype(stat::st_dev); |
33 | | using Inode = decltype(stat::st_ino); |
34 | | |
35 | | // Container for tracking miscellaneous information while parsing ftrace events, |
36 | | // scoped to an individual data source. Cleared periodically, after the metadata |
37 | | // is processed by the data sources interested in it, see |
38 | | // |OnFtraceDataWrittenIntoDataSourceBuffers|. |
39 | | struct FtraceMetadata { |
40 | | struct KernelAddr { |
41 | 0 | KernelAddr(uint64_t _addr, uint32_t _index) : addr(_addr), index(_index) {} |
42 | | uint64_t addr = 0; |
43 | | uint32_t index = 0; |
44 | | |
45 | | // We never keep more than one KernelAddr entry per address in the set. This |
46 | | // is really just a workaround for the lack of a FlatMap. |
47 | | // The |index| is written only after the entry is added to the set, to have |
48 | | // a monotonic value that reflects the insertion order. |
49 | 0 | friend bool operator<(const KernelAddr& lhs, const KernelAddr& rhs) { |
50 | 0 | return lhs.addr < rhs.addr; |
51 | 0 | } |
52 | 0 | friend bool operator==(const KernelAddr& lhs, const KernelAddr& rhs) { |
53 | 0 | return lhs.addr == rhs.addr; |
54 | 0 | } |
55 | | }; |
56 | | |
57 | 1.26k | FtraceMetadata() { |
58 | | // A sched_switch is 64 bytes, a page is 4096 bytes and we expect |
59 | | // 2 pid's per sched_switch. 4096/64*2=128. Give it a 2x margin. |
60 | 1.26k | pids.reserve(256); |
61 | | |
62 | | // We expect to see only a small number of task rename events. |
63 | 1.26k | rename_pids.reserve(32); |
64 | | |
65 | 1.26k | kernel_addrs.reserve(256); |
66 | 1.26k | } |
67 | | |
68 | 0 | void AddDevice(BlockDeviceID device_id) { |
69 | 0 | last_seen_device_id = device_id; |
70 | | #if PERFETTO_DCHECK_IS_ON() |
71 | | seen_device_id = true; |
72 | | #endif |
73 | 0 | } |
74 | | |
75 | 0 | void AddInode(Inode inode_number) { |
76 | | #if PERFETTO_DCHECK_IS_ON() |
77 | | PERFETTO_DCHECK(seen_device_id); |
78 | | #endif |
79 | 0 | static int32_t cached_pid = 0; |
80 | 0 | if (!cached_pid) |
81 | 0 | cached_pid = getpid(); |
82 | |
|
83 | 0 | PERFETTO_DCHECK(last_seen_common_pid); |
84 | 0 | PERFETTO_DCHECK(cached_pid == getpid()); |
85 | | // Ignore own scanning activity. |
86 | 0 | if (cached_pid != last_seen_common_pid) { |
87 | 0 | inode_and_device.insert( |
88 | 0 | std::make_pair(inode_number, last_seen_device_id)); |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | 0 | void AddRenamePid(int32_t pid) { rename_pids.insert(pid); } |
93 | | |
94 | 12.1k | void AddPid(int32_t pid) { |
95 | 12.1k | const size_t pid_bit = static_cast<size_t>(pid); |
96 | 12.1k | if (PERFETTO_LIKELY(pid_bit < pids_cache.size())) { |
97 | 2.67k | if (pids_cache.test(pid_bit)) |
98 | 1.51k | return; |
99 | 1.16k | pids_cache.set(pid_bit); |
100 | 1.16k | } |
101 | 10.6k | pids.insert(pid); |
102 | 10.6k | } |
103 | | |
104 | 6.54k | void AddCommonPid(int32_t pid) { |
105 | 6.54k | last_seen_common_pid = pid; |
106 | 6.54k | AddPid(pid); |
107 | 6.54k | } |
108 | | |
109 | | // Returns the index of the symbol (a monotonic counter, which is set when |
110 | | // the symbol is inserted the first time). |
111 | 0 | uint32_t AddSymbolAddr(uint64_t addr) { |
112 | 0 | auto it_and_inserted = kernel_addrs.insert(KernelAddr(addr, 0)); |
113 | | // Deliberately prefer a branch here to always computing and passing |
114 | | // size + 1 to the above. |
115 | 0 | if (it_and_inserted.second) { |
116 | 0 | const auto index = static_cast<uint32_t>(kernel_addrs.size()); |
117 | 0 | it_and_inserted.first->index = index; |
118 | 0 | } |
119 | 0 | return it_and_inserted.first->index; |
120 | 0 | } |
121 | | |
122 | 0 | void Clear() { |
123 | 0 | inode_and_device.clear(); |
124 | 0 | rename_pids.clear(); |
125 | 0 | pids.clear(); |
126 | 0 | pids_cache.reset(); |
127 | 0 | kernel_addrs.clear(); |
128 | 0 | fds.clear(); |
129 | 0 | last_kernel_addr_index_written = 0; |
130 | 0 | FinishEvent(); |
131 | 0 | } |
132 | | |
133 | 6.54k | void FinishEvent() { |
134 | 6.54k | last_seen_device_id = 0; |
135 | 6.54k | last_seen_common_pid = 0; |
136 | | #if PERFETTO_DCHECK_IS_ON() |
137 | | seen_device_id = false; |
138 | | #endif |
139 | 6.54k | } |
140 | | |
141 | | BlockDeviceID last_seen_device_id = 0; |
142 | | #if PERFETTO_DCHECK_IS_ON() |
143 | | bool seen_device_id = false; |
144 | | #endif |
145 | | int32_t last_seen_common_pid = 0; |
146 | | uint32_t last_kernel_addr_index_written = 0; |
147 | | |
148 | | base::FlatSet<InodeBlockPair> inode_and_device; |
149 | | base::FlatSet<int32_t> rename_pids; |
150 | | base::FlatSet<int32_t> pids; |
151 | | base::FlatSet<KernelAddr> kernel_addrs; |
152 | | base::FlatSet<std::pair<pid_t, uint64_t>> fds; |
153 | | |
154 | | // This bitmap is a cache for |pids|. It speculates on the fact that on most |
155 | | // Android kernels, PID_MAX=32768. It saves ~1-2% cpu time on high load |
156 | | // scenarios, as AddPid() is a very hot path. |
157 | | std::bitset<32768> pids_cache; |
158 | | }; |
159 | | |
160 | | } // namespace perfetto |
161 | | |
162 | | #endif // SRC_TRACED_PROBES_FTRACE_FTRACE_METADATA_H_ |