• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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