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 <limits> 21 #include <memory> 22 #include <set> 23 #include <unordered_map> 24 #include <vector> 25 26 #include "perfetto/base/flat_set.h" 27 #include "perfetto/ext/base/scoped_file.h" 28 #include "perfetto/ext/base/weak_ptr.h" 29 #include "perfetto/ext/tracing/core/basic_types.h" 30 #include "perfetto/ext/tracing/core/trace_writer.h" 31 #include "perfetto/tracing/core/forward_decls.h" 32 #include "src/traced/probes/common/cpu_freq_info.h" 33 #include "src/traced/probes/probes_data_source.h" 34 35 namespace perfetto { 36 37 namespace base { 38 class TaskRunner; 39 } 40 41 namespace protos { 42 namespace pbzero { 43 class ProcessTree; 44 class ProcessStats; 45 class ProcessStats_Process; 46 } // namespace pbzero 47 } // namespace protos 48 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 66 // ProbesDataSource implementation. 67 void Start() override; 68 void Flush(FlushRequestID, std::function<void()> callback) override; 69 void ClearIncrementalState() override; 70 on_demand_dumps_enabled()71 bool on_demand_dumps_enabled() const { return enable_on_demand_dumps_; } 72 73 // Virtual for testing. 74 virtual base::ScopedDir OpenProcDir(); 75 virtual std::string ReadProcPidFile(int32_t pid, const std::string& file); 76 virtual base::ScopedDir OpenProcTaskDir(int32_t pid); 77 78 private: 79 struct CachedProcessStats { 80 uint32_t vm_size_kb = std::numeric_limits<uint32_t>::max(); 81 uint32_t vm_rss_kb = std::numeric_limits<uint32_t>::max(); 82 uint32_t rss_anon_kb = std::numeric_limits<uint32_t>::max(); 83 uint32_t rss_file_kb = std::numeric_limits<uint32_t>::max(); 84 uint32_t rss_shmem_kb = std::numeric_limits<uint32_t>::max(); 85 uint32_t vm_swap_kb = std::numeric_limits<uint32_t>::max(); 86 uint32_t vm_locked_kb = std::numeric_limits<uint32_t>::max(); 87 uint32_t vm_hvm_kb = std::numeric_limits<uint32_t>::max(); 88 int oom_score_adj = std::numeric_limits<int>::max(); 89 90 // ctime + stime from /proc/pid/stat 91 uint64_t cpu_time = std::numeric_limits<uint64_t>::max(); 92 }; 93 94 // Common functions. 95 ProcessStatsDataSource(const ProcessStatsDataSource&) = delete; 96 ProcessStatsDataSource& operator=(const ProcessStatsDataSource&) = delete; 97 98 void StartNewPacketIfNeeded(); 99 void FinalizeCurPacket(); 100 protos::pbzero::ProcessTree* GetOrCreatePsTree(); 101 protos::pbzero::ProcessStats* GetOrCreateStats(); 102 protos::pbzero::ProcessStats_Process* GetOrCreateStatsProcess(int32_t pid); 103 104 // Functions for snapshotting process/thread long-term info and relationships. 105 void WriteProcess(int32_t pid, const std::string& proc_status); 106 void WriteThread(int32_t tid, int32_t tgid, const char* optional_name); 107 void WriteProcessOrThread(int32_t pid); 108 std::string ReadProcStatusEntry(const std::string& buf, const char* key); 109 110 // Functions for periodically sampling process stats/counters. 111 static void Tick(base::WeakPtr<ProcessStatsDataSource>); 112 void WriteAllProcessStats(); 113 bool WriteMemCounters(int32_t pid, const std::string& proc_status); 114 bool ShouldWriteThreadStats(int32_t pid); 115 void WriteThreadStats(int32_t pid, int32_t tid); 116 117 // Scans /proc/pid/status and writes the ProcessTree packet for input pids. 118 void WriteProcessTree(const base::FlatSet<int32_t>&); 119 120 // Read and "latch" the current procfs scan-start timestamp, which 121 // we reset only in FinalizeCurPacket. 122 uint64_t CacheProcFsScanStartTimestamp(); 123 124 // Common fields used for both process/tree relationships and stats/counters. 125 base::TaskRunner* const task_runner_; 126 std::unique_ptr<TraceWriter> writer_; 127 TraceWriter::TracePacketHandle cur_packet_; 128 129 // Cached before-scan timestamp; zero means cached time is absent. 130 // By the time we create the trace packet into which we dump procfs 131 // scan results, we've already read at least one bit of data from 132 // procfs, and by that point, it's too late to snap a timestamp from 133 // before we started looking at procfs at all, which is what trace 134 // analysis wants. To solve this problem, we record the scan-start 135 // timestamp here when we first open something in procfs and use 136 // that time when we create the packet. 137 // We reset this field after each FinalizeCurPacket(). 138 uint64_t cur_procfs_scan_start_timestamp_ = 0; 139 140 // Fields for keeping track of the state of process/tree relationships. 141 protos::pbzero::ProcessTree* cur_ps_tree_ = nullptr; 142 bool record_thread_names_ = false; 143 bool enable_on_demand_dumps_ = true; 144 bool dump_all_procs_on_start_ = false; 145 bool record_thread_time_in_state_ = false; 146 147 // This set contains PIDs as per the Linux kernel notion of a PID (which is 148 // really a TID). In practice this set will contain all TIDs for all processes 149 // seen, not just the main thread id (aka thread group ID). 150 base::FlatSet<int32_t> seen_pids_; 151 152 // Fields for keeping track of the periodic stats/counters. 153 uint32_t poll_period_ms_ = 0; 154 uint64_t cache_ticks_ = 0; 155 protos::pbzero::ProcessStats* cur_ps_stats_ = nullptr; 156 protos::pbzero::ProcessStats_Process* cur_ps_stats_process_ = nullptr; 157 std::vector<bool> skip_stats_for_pids_; 158 159 // Cached process stats per process. Cleared every |cache_ttl_ticks_| * 160 // |poll_period_ms_| ms. 161 uint32_t process_stats_cache_ttl_ticks_ = 0; 162 std::unordered_map<int32_t, CachedProcessStats> process_stats_cache_; 163 164 using TimeInStateCacheEntry = std::tuple</* tid */ int32_t, 165 /* cpu_freq_index */ uint32_t, 166 /* ticks */ uint64_t>; 167 168 // Cache for time in state. Size specificed in the config. Values are stored 169 // at index: hash(tid, cpu_freq_index) % thread_time_in_state_cache_size_. 170 std::vector<TimeInStateCacheEntry> thread_time_in_state_cache_; 171 uint32_t thread_time_in_state_cache_size_; 172 173 std::unique_ptr<CpuFreqInfo> cpu_freq_info_; 174 175 // If true, the next trace packet will have the |incremental_state_cleared| 176 // flag set. Set when handling a ClearIncrementalState call. 177 // 178 // TODO(rsavitski): initialized to true since the first packet also doesn't 179 // have any prior state to refer to. It might make more sense to let the 180 // tracing service set this for every first packet (as it does for 181 // |previous_packet_dropped|). 182 bool did_clear_incremental_state_ = true; 183 184 base::WeakPtrFactory<ProcessStatsDataSource> weak_factory_; // Keep last. 185 }; 186 187 } // namespace perfetto 188 189 #endif // SRC_TRACED_PROBES_PS_PROCESS_STATS_DATA_SOURCE_H_ 190