1 /* 2 * Copyright (C) 2018 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_PS_PROCESS_STATS_DATA_SOURCE_H_ 18 #define SRC_TRACED_PROBES_PS_PROCESS_STATS_DATA_SOURCE_H_ 19 20 #include <array> 21 #include <limits> 22 #include <memory> 23 #include <set> 24 #include <unordered_map> 25 #include <vector> 26 27 #include "perfetto/base/flat_set.h" 28 #include "perfetto/ext/base/scoped_file.h" 29 #include "perfetto/ext/base/weak_ptr.h" 30 #include "perfetto/ext/tracing/core/basic_types.h" 31 #include "perfetto/ext/tracing/core/trace_writer.h" 32 #include "perfetto/tracing/core/forward_decls.h" 33 #include "src/traced/probes/common/cpu_freq_info.h" 34 #include "src/traced/probes/probes_data_source.h" 35 36 namespace perfetto { 37 38 namespace base { 39 class TaskRunner; 40 } 41 42 namespace protos { 43 namespace pbzero { 44 class ProcessTree; 45 class ProcessStats; 46 class ProcessStats_Process; 47 } // namespace pbzero 48 } // namespace protos 49 50 class ProcessStatsDataSource : public ProbesDataSource { 51 public: 52 static const ProbesDataSource::Descriptor descriptor; 53 54 ProcessStatsDataSource(base::TaskRunner*, 55 TracingSessionID, 56 std::unique_ptr<TraceWriter> writer, 57 const DataSourceConfig&, 58 std::unique_ptr<CpuFreqInfo> cpu_freq_info); 59 ~ProcessStatsDataSource() override; 60 61 base::WeakPtr<ProcessStatsDataSource> GetWeakPtr() const; 62 void WriteAllProcesses(); 63 void OnPids(const base::FlatSet<int32_t>& pids); 64 void OnRenamePids(const base::FlatSet<int32_t>& pids); 65 void OnFds(const base::FlatSet<std::pair<pid_t, uint64_t>>& fds); 66 67 // ProbesDataSource implementation. 68 void Start() override; 69 void Flush(FlushRequestID, std::function<void()> callback) override; 70 void ClearIncrementalState() override; 71 on_demand_dumps_enabled()72 bool on_demand_dumps_enabled() const { return enable_on_demand_dumps_; } 73 74 // Virtual for testing. 75 virtual const char* GetProcMountpoint(); 76 virtual base::ScopedDir OpenProcDir(); 77 virtual std::string ReadProcPidFile(int32_t pid, const std::string& file); 78 79 private: 80 struct CachedProcessStats { 81 uint32_t vm_size_kb = std::numeric_limits<uint32_t>::max(); 82 uint32_t vm_rss_kb = std::numeric_limits<uint32_t>::max(); 83 uint32_t rss_anon_kb = std::numeric_limits<uint32_t>::max(); 84 uint32_t rss_file_kb = std::numeric_limits<uint32_t>::max(); 85 uint32_t rss_shmem_kb = std::numeric_limits<uint32_t>::max(); 86 uint32_t vm_swap_kb = std::numeric_limits<uint32_t>::max(); 87 uint32_t vm_locked_kb = std::numeric_limits<uint32_t>::max(); 88 uint32_t vm_hvm_kb = std::numeric_limits<uint32_t>::max(); 89 int oom_score_adj = std::numeric_limits<int>::max(); 90 uint32_t smr_rss_kb = std::numeric_limits<uint32_t>::max(); 91 uint32_t smr_pss_kb = std::numeric_limits<uint32_t>::max(); 92 uint32_t smr_pss_anon_kb = std::numeric_limits<uint32_t>::max(); 93 uint32_t smr_pss_file_kb = std::numeric_limits<uint32_t>::max(); 94 uint32_t smr_pss_shmem_kb = std::numeric_limits<uint32_t>::max(); 95 96 // ctime + stime from /proc/pid/stat 97 uint64_t cpu_time = std::numeric_limits<uint64_t>::max(); 98 99 // file descriptors 100 base::FlatSet<uint64_t> seen_fds; 101 }; 102 103 // Common functions. 104 ProcessStatsDataSource(const ProcessStatsDataSource&) = delete; 105 ProcessStatsDataSource& operator=(const ProcessStatsDataSource&) = delete; 106 107 void StartNewPacketIfNeeded(); 108 void FinalizeCurPacket(); 109 protos::pbzero::ProcessTree* GetOrCreatePsTree(); 110 protos::pbzero::ProcessStats* GetOrCreateStats(); 111 protos::pbzero::ProcessStats_Process* GetOrCreateStatsProcess(int32_t pid); 112 113 // Functions for snapshotting process/thread long-term info and relationships. 114 void WriteProcess(int32_t pid, const std::string& proc_status); 115 void WriteThread(int32_t tid, 116 int32_t tgid, 117 const char* optional_name, 118 const std::string& proc_status); 119 void WriteProcessOrThread(int32_t pid); 120 std::string ReadProcStatusEntry(const std::string& buf, const char* key); 121 122 constexpr static size_t kMaxNamespacedTidSize = 8; 123 using TidArray = std::array<int32_t, kMaxNamespacedTidSize>; 124 // Reads the thread IDs in each non-root level of PID namespace from 125 // /proc/tid/status. 126 void ReadNamespacedTids(int32_t tid, 127 const std::string& proc_status, 128 TidArray& out); 129 130 // Functions for periodically sampling process stats/counters. 131 static void Tick(base::WeakPtr<ProcessStatsDataSource>); 132 void WriteAllProcessStats(); 133 bool WriteMemCounters(int32_t pid, const std::string& proc_status); 134 void WriteFds(int32_t pid); 135 void WriteSingleFd(int32_t pid, uint64_t fd); 136 bool ShouldWriteThreadStats(int32_t pid); 137 void WriteThreadStats(int32_t pid, int32_t tid); 138 139 // Scans /proc/pid/status and writes the ProcessTree packet for input pids. 140 void WriteProcessTree(const base::FlatSet<int32_t>&); 141 142 // Read and "latch" the current procfs scan-start timestamp, which 143 // we reset only in FinalizeCurPacket. 144 uint64_t CacheProcFsScanStartTimestamp(); 145 146 // Common fields used for both process/tree relationships and stats/counters. 147 base::TaskRunner* const task_runner_; 148 std::unique_ptr<TraceWriter> writer_; 149 TraceWriter::TracePacketHandle cur_packet_; 150 151 // Cached before-scan timestamp; zero means cached time is absent. 152 // By the time we create the trace packet into which we dump procfs 153 // scan results, we've already read at least one bit of data from 154 // procfs, and by that point, it's too late to snap a timestamp from 155 // before we started looking at procfs at all, which is what trace 156 // analysis wants. To solve this problem, we record the scan-start 157 // timestamp here when we first open something in procfs and use 158 // that time when we create the packet. 159 // We reset this field after each FinalizeCurPacket(). 160 uint64_t cur_procfs_scan_start_timestamp_ = 0; 161 162 // Fields for keeping track of the state of process/tree relationships. 163 protos::pbzero::ProcessTree* cur_ps_tree_ = nullptr; 164 bool record_thread_names_ = false; 165 bool enable_on_demand_dumps_ = true; 166 bool dump_all_procs_on_start_ = false; 167 bool resolve_process_fds_ = false; 168 bool scan_smaps_rollup_ = false; 169 170 // This set contains PIDs as per the Linux kernel notion of a PID (which is 171 // really a TID). In practice this set will contain all TIDs for all processes 172 // seen, not just the main thread id (aka thread group ID). 173 struct SeenPid { 174 int32_t pid; 175 int32_t tgid; 176 pidSeenPid177 inline SeenPid(int32_t _pid, int32_t _tgid = 0) : pid(_pid), tgid(_tgid) {} 178 // TODO(rsavitski): add comparator support to FlatSet 179 inline bool operator==(const SeenPid& other) const { 180 return pid == other.pid; 181 } 182 inline bool operator<(const SeenPid& other) const { 183 return pid < other.pid; 184 } 185 }; 186 base::FlatSet<SeenPid> seen_pids_; 187 188 // Fields for keeping track of the periodic stats/counters. 189 uint32_t poll_period_ms_ = 0; 190 uint64_t cache_ticks_ = 0; 191 protos::pbzero::ProcessStats* cur_ps_stats_ = nullptr; 192 protos::pbzero::ProcessStats_Process* cur_ps_stats_process_ = nullptr; 193 std::vector<bool> skip_stats_for_pids_; 194 195 // Cached process stats per process. Cleared every |cache_ttl_ticks_| * 196 // |poll_period_ms_| ms. 197 uint32_t process_stats_cache_ttl_ticks_ = 0; 198 std::unordered_map<int32_t, CachedProcessStats> process_stats_cache_; 199 200 using TimeInStateCacheEntry = std::tuple</* tid */ int32_t, 201 /* cpu_freq_index */ uint32_t, 202 /* ticks */ uint64_t>; 203 204 std::unique_ptr<CpuFreqInfo> cpu_freq_info_; 205 206 // If true, the next trace packet will have the |incremental_state_cleared| 207 // flag set. Set when handling a ClearIncrementalState call. 208 // 209 // TODO(rsavitski): initialized to true since the first packet also doesn't 210 // have any prior state to refer to. It might make more sense to let the 211 // tracing service set this for every first packet (as it does for 212 // |previous_packet_dropped|). 213 bool did_clear_incremental_state_ = true; 214 215 base::WeakPtrFactory<ProcessStatsDataSource> weak_factory_; // Keep last. 216 }; 217 218 } // namespace perfetto 219 220 #endif // SRC_TRACED_PROBES_PS_PROCESS_STATS_DATA_SOURCE_H_ 221