blob: 7e56238cbb0a857a9801a478d2c174e2da21039a [file] [log] [blame]
Sandeep Patil54d87212018-08-29 17:10:47 -07001/*
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#include <ctype.h>
18#include <errno.h>
19#include <fcntl.h>
Sandeep Patil70fa72d2018-11-09 19:18:29 -080020#include <inttypes.h>
Sandeep Patil54d87212018-08-29 17:10:47 -070021#include <stdlib.h>
22#include <unistd.h>
23
24#include <cctype>
Sandeep Patil70fa72d2018-11-09 19:18:29 -080025#include <cstdio>
Sandeep Patil54d87212018-08-29 17:10:47 -070026#include <fstream>
27#include <string>
28#include <utility>
29#include <vector>
30
31#include <android-base/file.h>
32#include <android-base/logging.h>
33#include <android-base/parseint.h>
Sandeep Patil70fa72d2018-11-09 19:18:29 -080034#include <android-base/stringprintf.h>
Sandeep Patil54d87212018-08-29 17:10:47 -070035#include <android-base/strings.h>
Sandeep Patil70fa72d2018-11-09 19:18:29 -080036#include <android-base/unique_fd.h>
Sandeep Patil54d87212018-08-29 17:10:47 -070037
38#include "meminfo_private.h"
39
40namespace android {
41namespace meminfo {
42
43const std::vector<std::string> SysMemInfo::kDefaultSysMemInfoTags = {
Sandeep Patil70fa72d2018-11-09 19:18:29 -080044 SysMemInfo::kMemTotal, SysMemInfo::kMemFree, SysMemInfo::kMemBuffers,
45 SysMemInfo::kMemCached, SysMemInfo::kMemShmem, SysMemInfo::kMemSlab,
46 SysMemInfo::kMemSReclaim, SysMemInfo::kMemSUnreclaim, SysMemInfo::kMemSwapTotal,
47 SysMemInfo::kMemSwapFree, SysMemInfo::kMemMapped, SysMemInfo::kMemVmallocUsed,
48 SysMemInfo::kMemPageTables, SysMemInfo::kMemKernelStack,
Sandeep Patil54d87212018-08-29 17:10:47 -070049};
50
51bool SysMemInfo::ReadMemInfo(const std::string& path) {
52 return ReadMemInfo(SysMemInfo::kDefaultSysMemInfoTags, path);
53}
54
55// TODO: Delete this function if it can't match up with the c-like implementation below.
56// Currently, this added about 50 % extra overhead on hikey.
57#if 0
58bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, const std::string& path) {
59 std::string buffer;
60 if (!::android::base::ReadFileToString(path, &buffer)) {
61 PLOG(ERROR) << "Failed to read : " << path;
62 return false;
63 }
64
65 uint32_t total_found = 0;
66 for (auto s = buffer.begin(); s < buffer.end() && total_found < tags.size();) {
67 for (auto& tag : tags) {
68 if (tag == std::string(s, s + tag.size())) {
69 s += tag.size();
70 while (isspace(*s)) s++;
71 auto num_start = s;
72 while (std::isdigit(*s)) s++;
73
74 std::string number(num_start, num_start + (s - num_start));
75 if (!::android::base::ParseUint(number, &mem_in_kb_[tag])) {
76 LOG(ERROR) << "Failed to parse uint";
77 return false;
78 }
79 total_found++;
80 break;
81 }
82 }
83 while (s < buffer.end() && *s != '\n') s++;
84 if (s < buffer.end()) s++;
85 }
86
87 return true;
88}
89
90#else
91bool SysMemInfo::ReadMemInfo(const std::vector<std::string>& tags, const std::string& path) {
92 char buffer[4096];
93 int fd = open(path.c_str(), O_RDONLY | O_CLOEXEC);
94 if (fd < 0) {
95 PLOG(ERROR) << "Failed to open file :" << path;
96 return false;
97 }
98
99 const int len = read(fd, buffer, sizeof(buffer) - 1);
100 close(fd);
101 if (len < 0) {
102 return false;
103 }
104
105 buffer[len] = '\0';
106 char* p = buffer;
107 uint32_t found = 0;
Sandeep Patil2259fdf2018-11-09 16:42:45 -0800108 uint32_t lineno = 0;
Sandeep Patil54d87212018-08-29 17:10:47 -0700109 while (*p && found < tags.size()) {
110 for (auto& tag : tags) {
111 if (strncmp(p, tag.c_str(), tag.size()) == 0) {
112 p += tag.size();
113 while (*p == ' ') p++;
114 char* endptr = nullptr;
115 mem_in_kb_[tag] = strtoull(p, &endptr, 10);
116 if (p == endptr) {
Sandeep Patil2259fdf2018-11-09 16:42:45 -0800117 PLOG(ERROR) << "Failed to parse line:" << lineno + 1 << " in file: " << path;
Sandeep Patil54d87212018-08-29 17:10:47 -0700118 return false;
119 }
120 p = endptr;
121 found++;
122 break;
123 }
124 }
125 while (*p && *p != '\n') {
126 p++;
127 }
128 if (*p) p++;
Sandeep Patil2259fdf2018-11-09 16:42:45 -0800129 lineno++;
Sandeep Patil54d87212018-08-29 17:10:47 -0700130 }
131
132 return true;
133}
134#endif
135
Sandeep Patil70fa72d2018-11-09 19:18:29 -0800136uint64_t SysMemInfo::mem_zram_kb(const std::string& zram_dev) {
137 uint64_t mem_zram_total = 0;
138 if (!zram_dev.empty()) {
139 if (!MemZramDevice(zram_dev, &mem_zram_total)) {
140 return 0;
141 }
142 return mem_zram_total / 1024;
143 }
144
145 constexpr uint32_t kMaxZramDevices = 256;
146 for (uint32_t i = 0; i < kMaxZramDevices; i++) {
147 std::string zram_dev = ::android::base::StringPrintf("/sys/block/zram%u/", i);
148 if (access(zram_dev.c_str(), F_OK)) {
149 // We assume zram devices appear in range 0-255 and appear always in sequence
150 // under /sys/block. So, stop looking for them once we find one is missing.
151 break;
152 }
153
154 uint64_t mem_zram_dev;
155 if (!MemZramDevice(zram_dev, &mem_zram_dev)) {
156 return 0;
157 }
158
159 mem_zram_total += mem_zram_dev;
160 }
161
162 return mem_zram_total / 1024;
163}
164
165bool SysMemInfo::MemZramDevice(const std::string& zram_dev, uint64_t* mem_zram_dev) {
166 std::string content;
167 if (android::base::ReadFileToString(zram_dev + "mm_stat", &content)) {
168 std::vector<std::string> values = ::android::base::Split(content, " ");
169 if (values.size() < 3) {
170 LOG(ERROR) << "Malformed mm_stat file for zram dev: " << zram_dev
171 << " content: " << content;
172 return false;
173 }
174
175 if (!::android::base::ParseUint(values[2], mem_zram_dev)) {
176 LOG(ERROR) << "Malformed mm_stat file for zram dev: " << zram_dev
177 << " value: " << values[2];
178 return false;
179 }
180
181 return true;
182 }
183
184 if (::android::base::ReadFileToString(zram_dev + "mem_used_total", &content)) {
185 *mem_zram_dev = strtoull(content.c_str(), NULL, 10);
186 if (*mem_zram_dev == ULLONG_MAX) {
187 PLOG(ERROR) << "Malformed mem_used_total file for zram dev: " << zram_dev
188 << " content: " << content;
189 return false;
190 }
191
192 return true;
193 }
194
195 LOG(ERROR) << "Can't find memory status under: " << zram_dev;
196 return false;
197}
198
Sandeep Patil54d87212018-08-29 17:10:47 -0700199} // namespace meminfo
200} // namespace android