1 /*
2 * Copyright (c) 2021, 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_PROCDISKSTATS_H_
18 #define CPP_WATCHDOG_SERVER_SRC_PROCDISKSTATS_H_
19
20 #include <android-base/result.h>
21 #include <android-base/stringprintf.h>
22 #include <android-base/strings.h>
23 #include <utils/Mutex.h>
24 #include <utils/RefBase.h>
25
26 #include <string>
27 #include <unordered_set>
28 #include <vector>
29
30 namespace android {
31 namespace automotive {
32 namespace watchdog {
33
34 constexpr const char* kProcDiskStatsPath = "/proc/diskstats";
35
recordStatsForDevice(const std::string & deviceName)36 inline constexpr bool recordStatsForDevice(const std::string& deviceName) {
37 for (const auto& prefix : {"zram", "ram"}) {
38 if (android::base::StartsWith(deviceName, prefix)) {
39 return false;
40 }
41 }
42 return true;
43 }
44
45 // Struct that represents the stats from |kUidIoStatsPath|.
46 struct DiskStats {
47 int major = 0;
48 int minor = 0;
49 std::string deviceName;
50 uint64_t numReadsCompleted = 0;
51 uint64_t numReadsMerged = 0;
52 uint64_t numKibRead = 0;
53 uint64_t readTimeInMs = 0;
54 uint64_t numWritesCompleted = 0;
55 uint64_t numWritesMerged = 0;
56 uint64_t numKibWritten = 0;
57 uint64_t writeTimeInMs = 0;
58 uint64_t totalIoTimeInMs = 0;
59 uint64_t weightedTotalIoTimeInMs = 0;
60 uint64_t numFlushCompleted = 0;
61 uint64_t flushTimeInMs = 0;
62
63 DiskStats& operator-=(const DiskStats& rhs);
64 DiskStats& operator+=(const DiskStats& rhs);
65 struct HashByPartition {
66 size_t operator()(const DiskStats& stats) const;
67 };
68 struct EqualByPartition {
69 bool operator()(const DiskStats& lhs, const DiskStats& rhs) const;
70 };
71 };
72
73 /*
74 * Contains methods that should be implemented by the /proc/diskstats reader or any mock reader
75 * used in tests.
76 */
77 class IProcDiskStatsInterface : public android::RefBase {
78 public:
79 using PerPartitionDiskStats = ::std::unordered_set<DiskStats, DiskStats::HashByPartition,
80 DiskStats::EqualByPartition>;
81
82 // Collects the system-wide block devices statistics.
83 virtual android::base::Result<void> collect() = 0;
84
85 // Returns the latest per-disk stats.
86 virtual PerPartitionDiskStats latestPerPartitionDiskStats() const = 0;
87
88 // Returns the aggregated delta stats since the last before collection.
89 virtual DiskStats deltaSystemWideDiskStats() const = 0;
90
91 // Returns true when the proc diskstats file is accessible. Otherwise, returns false.
92 virtual bool enabled() const = 0;
93
94 // Path to the disk stats file.
95 virtual std::string filePath() const = 0;
96 };
97
98 class ProcDiskStats : public IProcDiskStatsInterface {
99 public:
100 explicit ProcDiskStats(const std::string& path = kProcDiskStatsPath) :
101 kEnabled(!access(path.c_str(), R_OK)),
102 kPath(path) {}
103
~ProcDiskStats()104 ~ProcDiskStats() {}
105
106 android::base::Result<void> collect();
107
latestPerPartitionDiskStats()108 PerPartitionDiskStats latestPerPartitionDiskStats() const {
109 Mutex::Autolock lock(mMutex);
110 return mLatestPerPartitionDiskStats;
111 }
112
deltaSystemWideDiskStats()113 DiskStats deltaSystemWideDiskStats() const {
114 Mutex::Autolock lock(mMutex);
115 return mDeltaSystemWideDiskStats;
116 }
117
enabled()118 bool enabled() const { return kEnabled; }
119
filePath()120 std::string filePath() const { return kPath; }
121
122 private:
123 // Makes sure only one collection is running at any given time.
124 mutable Mutex mMutex;
125
126 // Delta of per-UID I/O usage since last before collection.
127 DiskStats mDeltaSystemWideDiskStats GUARDED_BY(mMutex);
128
129 /*
130 * Latest per-disk stats from the file at |kPath|. Per-disk stats is required for calculating
131 * per-disk delta since last collection. Because the stats reported in |kPath| may overflow,
132 * storing the stats per-disk helps to deal with this issue.
133 */
134 PerPartitionDiskStats mLatestPerPartitionDiskStats GUARDED_BY(mMutex);
135
136 // True if |kPath| is accessible.
137 const bool kEnabled;
138
139 // Path to disk stats file.
140 const std::string kPath;
141 };
142
143 } // namespace watchdog
144 } // namespace automotive
145 } // namespace android
146
147 #endif // CPP_WATCHDOG_SERVER_SRC_PROCDISKSTATS_H_
148