• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020, 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 CPP_WATCHDOG_SERVER_SRC_UIDPROCSTATSCOLLECTOR_H_
18 #define CPP_WATCHDOG_SERVER_SRC_UIDPROCSTATSCOLLECTOR_H_
19 
20 #include <android-base/result.h>
21 #include <android-base/stringprintf.h>
22 #include <gtest/gtest_prod.h>
23 #include <utils/Mutex.h>
24 #include <utils/RefBase.h>
25 
26 #include <inttypes.h>
27 #include <stdint.h>
28 #include <unistd.h>
29 
30 #include <string>
31 #include <unordered_map>
32 #include <vector>
33 
34 namespace android {
35 namespace automotive {
36 namespace watchdog {
37 
38 using ::android::base::StringPrintf;
39 
40 #define PID_FOR_INIT 1
41 
42 constexpr const char kProcDirPath[] = "/proc";
43 constexpr const char kStatFileFormat[] = "/%" PRIu32 "/stat";
44 constexpr const char kTaskDirFormat[] = "/%" PRIu32 "/task";
45 constexpr const char kStatusFileFormat[] = "/%" PRIu32 "/status";
46 constexpr const char kTimeInStateFormat[] = "/%" PRIu32 "/time_in_state";
47 // Per-pid/tid stats.
48 // The int64_t type is used due to AIDL limitations representing long field values.
49 struct PidStat {
50     std::string comm = "";
51     std::string state = "";
52     int64_t startTimeMillis = 0;
53     int64_t cpuTimeMillis = 0;
54     uint64_t majorFaults = 0;
55 };
56 
57 // Per-process stats.
58 struct ProcessStats {
59     std::string comm = "";
60     int64_t startTimeMillis = 0;  // Useful when identifying PID reuse
61     int64_t cpuTimeMillis = 0;
62     // Stats in below fields are aggregated across all threads
63     uint64_t totalCpuCycles = 0;
64     uint64_t totalMajorFaults = 0;
65     int totalTasksCount = 0;
66     int ioBlockedTasksCount = 0;
67     std::unordered_map<pid_t, uint64_t> cpuCyclesByTid = {};
68     std::string toString() const;
69 };
70 
71 // Per-UID stats.
72 struct UidProcStats {
73     int64_t cpuTimeMillis = 0;
74     uint64_t cpuCycles = 0;
75     uint64_t totalMajorFaults = 0;
76     int totalTasksCount = 0;
77     int ioBlockedTasksCount = 0;
78     std::unordered_map<pid_t, ProcessStats> processStatsByPid = {};
79     std::string toString() const;
80 };
81 
82 // Collector/parser for `/proc/[pid]/stat`, `/proc/[pid]/task/[tid]/stat` and /proc/[pid]/status`
83 // files.
84 class UidProcStatsCollectorInterface : public RefBase {
85 public:
86     // Initializes the collector.
87     virtual void init() = 0;
88     // Collects the per-uid stats from /proc directory.
89     virtual android::base::Result<void> collect() = 0;
90     // Returns the latest per-uid process stats.
91     virtual const std::unordered_map<uid_t, UidProcStats> latestStats() const = 0;
92     // Returns the delta of per-uid process stats since the last before collection.
93     virtual const std::unordered_map<uid_t, UidProcStats> deltaStats() const = 0;
94     // Returns true only when the /proc files for the init process are accessible.
95     virtual bool enabled() const = 0;
96     // Returns the /proc files common ancestor directory path.
97     virtual const std::string dirPath() const = 0;
98 };
99 
100 class UidProcStatsCollector final : public UidProcStatsCollectorInterface {
101 public:
102     explicit UidProcStatsCollector(const std::string& path = kProcDirPath) :
sysconf(_SC_CLK_TCK)103           mMillisPerClockTick(1000 / sysconf(_SC_CLK_TCK)),
104           mPath(path),
105           mLatestStats({}),
106           mDeltaStats({}) {}
107 
~UidProcStatsCollector()108     ~UidProcStatsCollector() {}
109 
110     void init() override;
111 
112     android::base::Result<void> collect() override;
113 
latestStats()114     const std::unordered_map<uid_t, UidProcStats> latestStats() const {
115         Mutex::Autolock lock(mMutex);
116         return mLatestStats;
117     }
118 
deltaStats()119     const std::unordered_map<uid_t, UidProcStats> deltaStats() const {
120         Mutex::Autolock lock(mMutex);
121         return mDeltaStats;
122     }
123 
enabled()124     bool enabled() const {
125         Mutex::Autolock lock(mMutex);
126         return mEnabled;
127     }
128 
dirPath()129     const std::string dirPath() const { return mPath; }
130 
131     static android::base::Result<PidStat> readStatFileForPid(pid_t pid);
132 
133     static android::base::Result<std::tuple<uid_t, pid_t>> readPidStatusFileForPid(pid_t pid);
134 
135 private:
136     android::base::Result<std::unordered_map<uid_t, UidProcStats>> readUidProcStatsLocked() const;
137 
138     // Reads the contents of the below files:
139     // 1. Pid stat file at |mPath| + |kStatFileFormat|
140     // 2. Aggregated per-process status at |mPath| + |kStatusFileFormat|
141     // 3. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat|
142     android::base::Result<std::tuple<uid_t, ProcessStats>> readProcessStatsLocked(pid_t pid) const;
143 
144     // Number of milliseconds per clock cycle.
145     int32_t mMillisPerClockTick;
146 
147     // Proc directory path. Default value is |kProcDirPath|.
148     // Updated by tests to point to a different location when needed.
149     std::string mPath;
150 
151     // Makes sure only one collection is running at any given time.
152     mutable Mutex mMutex;
153 
154     // True if the below files are accessible:
155     // 1. Pid stat file at |mPath| + |kTaskStatFileFormat|
156     // 2. Tid stat file at |mPath| + |kTaskDirFormat| + |kStatFileFormat|
157     // 3. Pid status file at |mPath| + |kStatusFileFormat|
158     // Otherwise, set to false.
159     bool mEnabled GUARDED_BY(mMutex);
160 
161     // True if the tid time_in_state file at
162     // |mPath| + |kTaskDirFormat| + |kTimeInStateFormat| is available.
163     bool mTimeInStateEnabled GUARDED_BY(mMutex);
164 
165     // Latest dump of per-UID stats.
166     std::unordered_map<uid_t, UidProcStats> mLatestStats GUARDED_BY(mMutex);
167 
168     // Latest delta of per-uid stats.
169     std::unordered_map<uid_t, UidProcStats> mDeltaStats GUARDED_BY(mMutex);
170 
171     FRIEND_TEST(PerformanceProfilerTest, TestValidProcPidContents);
172     FRIEND_TEST(UidProcStatsCollectorTest, TestValidStatFiles);
173     FRIEND_TEST(UidProcStatsCollectorTest, TestHandlesProcessTerminationBetweenScanningAndParsing);
174     FRIEND_TEST(UidProcStatsCollectorTest, TestHandlesPidTidReuse);
175 };
176 
177 }  // namespace watchdog
178 }  // namespace automotive
179 }  // namespace android
180 
181 #endif  //  CPP_WATCHDOG_SERVER_SRC_UIDPROCSTATSCOLLECTOR_H_
182