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 51 class ProcessStatsDataSource : public ProbesDataSource { 52 public: 53 static const ProbesDataSource::Descriptor descriptor; 54 55 ProcessStatsDataSource(base::TaskRunner*, 56 TracingSessionID, 57 std::unique_ptr<TraceWriter> writer, 58 const DataSourceConfig&, 59 std::unique_ptr<CpuFreqInfo> cpu_freq_info); 60 ~ProcessStatsDataSource() override; 61 62 base::WeakPtr<ProcessStatsDataSource> GetWeakPtr() const; 63 void WriteAllProcesses(); 64 void OnPids(const base::FlatSet<int32_t>& pids); 65 void OnRenamePids(const base::FlatSet<int32_t>& pids); 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 base::ScopedDir OpenProcDir(); 76 virtual std::string ReadProcPidFile(int32_t pid, const std::string& file); 77 virtual base::ScopedDir OpenProcTaskDir(int32_t pid); 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 91 // ctime + stime from /proc/pid/stat 92 uint64_t cpu_time = std::numeric_limits<uint64_t>::max(); 93 }; 94 95 // Common functions. 96 ProcessStatsDataSource(const ProcessStatsDataSource&) = delete; 97 ProcessStatsDataSource& operator=(const ProcessStatsDataSource&) = delete; 98 99 void StartNewPacketIfNeeded(); 100 void FinalizeCurPacket(); 101 protos::pbzero::ProcessTree* GetOrCreatePsTree(); 102 protos::pbzero::ProcessStats* GetOrCreateStats(); 103 protos::pbzero::ProcessStats_Process* GetOrCreateStatsProcess(int32_t pid); 104 105 // Functions for snapshotting process/thread long-term info and relationships. 106 void WriteProcess(int32_t pid, const std::string& proc_status); 107 void WriteThread(int32_t tid, 108 int32_t tgid, 109 const char* optional_name, 110 const std::string& proc_status); 111 void WriteProcessOrThread(int32_t pid); 112 std::string ReadProcStatusEntry(const std::string& buf, const char* key); 113 114 constexpr static size_t kMaxNamespacedTidSize = 8; 115 using TidArray = std::array<int32_t, kMaxNamespacedTidSize>; 116 // Reads the thread IDs in each non-root level of PID namespace from 117 // /proc/tid/status. 118 void ReadNamespacedTids(int32_t tid, 119 const std::string& proc_status, 120 TidArray& out); 121 122 // Functions for periodically sampling process stats/counters. 123 static void Tick(base::WeakPtr<ProcessStatsDataSource>); 124 void WriteAllProcessStats(); 125 bool WriteMemCounters(int32_t pid, const std::string& proc_status); 126 bool ShouldWriteThreadStats(int32_t pid); 127 void WriteThreadStats(int32_t pid, int32_t tid); 128 129 // Scans /proc/pid/status and writes the ProcessTree packet for input pids. 130 void WriteProcessTree(const base::FlatSet<int32_t>&); 131 132 // Read and "latch" the current procfs scan-start timestamp, which 133 // we reset only in FinalizeCurPacket. 134 uint64_t CacheProcFsScanStartTimestamp(); 135 136 // Common fields used for both process/tree relationships and stats/counters. 137 base::TaskRunner* const task_runner_; 138 std::unique_ptr<TraceWriter> writer_; 139 TraceWriter::TracePacketHandle cur_packet_; 140 141 // Cached before-scan timestamp; zero means cached time is absent. 142 // By the time we create the trace packet into which we dump procfs 143 // scan results, we've already read at least one bit of data from 144 // procfs, and by that point, it's too late to snap a timestamp from 145 // before we started looking at procfs at all, which is what trace 146 // analysis wants. To solve this problem, we record the scan-start 147 // timestamp here when we first open something in procfs and use 148 // that time when we create the packet. 149 // We reset this field after each FinalizeCurPacket(). 150 uint64_t cur_procfs_scan_start_timestamp_ = 0; 151 152 // Fields for keeping track of the state of process/tree relationships. 153 protos::pbzero::ProcessTree* cur_ps_tree_ = nullptr; 154 bool record_thread_names_ = false; 155 bool enable_on_demand_dumps_ = true; 156 bool dump_all_procs_on_start_ = false; 157 bool record_thread_time_in_state_ = false; 158 159 // This set contains PIDs as per the Linux kernel notion of a PID (which is 160 // really a TID). In practice this set will contain all TIDs for all processes 161 // seen, not just the main thread id (aka thread group ID). 162 base::FlatSet<int32_t> seen_pids_; 163 164 // Fields for keeping track of the periodic stats/counters. 165 uint32_t poll_period_ms_ = 0; 166 uint64_t cache_ticks_ = 0; 167 protos::pbzero::ProcessStats* cur_ps_stats_ = nullptr; 168 protos::pbzero::ProcessStats_Process* cur_ps_stats_process_ = nullptr; 169 std::vector<bool> skip_stats_for_pids_; 170 171 // Cached process stats per process. Cleared every |cache_ttl_ticks_| * 172 // |poll_period_ms_| ms. 173 uint32_t process_stats_cache_ttl_ticks_ = 0; 174 std::unordered_map<int32_t, CachedProcessStats> process_stats_cache_; 175 176 using TimeInStateCacheEntry = std::tuple</* tid */ int32_t, 177 /* cpu_freq_index */ uint32_t, 178 /* ticks */ uint64_t>; 179 180 // Cache for time in state. Size specificed in the config. Values are stored 181 // at index: hash(tid, cpu_freq_index) % thread_time_in_state_cache_size_. 182 std::vector<TimeInStateCacheEntry> thread_time_in_state_cache_; 183 uint32_t thread_time_in_state_cache_size_; 184 185 std::unique_ptr<CpuFreqInfo> cpu_freq_info_; 186 187 // If true, the next trace packet will have the |incremental_state_cleared| 188 // flag set. Set when handling a ClearIncrementalState call. 189 // 190 // TODO(rsavitski): initialized to true since the first packet also doesn't 191 // have any prior state to refer to. It might make more sense to let the 192 // tracing service set this for every first packet (as it does for 193 // |previous_packet_dropped|). 194 bool did_clear_incremental_state_ = true; 195 196 base::WeakPtrFactory<ProcessStatsDataSource> weak_factory_; // Keep last. 197 }; 198 199 } // namespace perfetto 200 201 #endif // SRC_TRACED_PROBES_PS_PROCESS_STATS_DATA_SOURCE_H_ 202