Elliott Hughes | 2faa5f1 | 2012-01-30 14:42:07 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2011 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 | */ |
Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 16 | |
Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 17 | #include "utils.h" |
| 18 | |
Christopher Ferris | 943af7d | 2014-01-16 12:41:46 -0800 | [diff] [blame] | 19 | #include <inttypes.h> |
Elliott Hughes | 92b3b56 | 2011-09-08 16:32:26 -0700 | [diff] [blame] | 20 | #include <pthread.h> |
Brian Carlstrom | a9f1978 | 2011-10-13 00:14:47 -0700 | [diff] [blame] | 21 | #include <sys/stat.h> |
Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 22 | #include <sys/types.h> |
| 23 | #include <unistd.h> |
Andreas Gampe | 8cf9cb3 | 2017-07-19 09:28:38 -0700 | [diff] [blame] | 24 | |
Wei Li | 8991ad0 | 2018-09-13 16:43:39 +0800 | [diff] [blame] | 25 | #include <fstream> |
Ian Rogers | 700a402 | 2014-05-19 16:49:03 -0700 | [diff] [blame] | 26 | #include <memory> |
Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 27 | |
David Sehr | 013fd80 | 2018-01-11 22:55:24 -0800 | [diff] [blame] | 28 | #include "android-base/file.h" |
Andreas Gampe | 46ee31b | 2016-12-14 10:11:49 -0800 | [diff] [blame] | 29 | #include "android-base/stringprintf.h" |
Andreas Gampe | 9186ced | 2016-12-12 14:28:21 -0800 | [diff] [blame] | 30 | #include "android-base/strings.h" |
| 31 | |
David Sehr | 1979c64 | 2018-04-26 14:41:18 -0700 | [diff] [blame] | 32 | #include "os.h" |
Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 33 | |
Elliott Hughes | 4ae722a | 2012-03-13 11:08:51 -0700 | [diff] [blame] | 34 | #if defined(__APPLE__) |
David Sehr | fa44200 | 2016-08-22 18:42:08 -0700 | [diff] [blame] | 35 | #include <crt_externs.h> |
Andreas Gampe | 8cf9cb3 | 2017-07-19 09:28:38 -0700 | [diff] [blame] | 36 | #include <sys/syscall.h> |
| 37 | #include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED |
Elliott Hughes | 4ae722a | 2012-03-13 11:08:51 -0700 | [diff] [blame] | 38 | #endif |
| 39 | |
Orion Hodson | f233136 | 2018-07-11 15:14:10 +0100 | [diff] [blame] | 40 | #if defined(__BIONIC__) |
| 41 | // membarrier(2) is only supported for target builds (b/111199492). |
| 42 | #include <linux/membarrier.h> |
| 43 | #include <sys/syscall.h> |
| 44 | #endif |
| 45 | |
Elliott Hughes | 058a6de | 2012-05-24 19:13:02 -0700 | [diff] [blame] | 46 | #if defined(__linux__) |
Elliott Hughes | e1aee69 | 2012-01-17 16:40:10 -0800 | [diff] [blame] | 47 | #include <linux/unistd.h> |
David Sehr | 10db8fe | 2018-07-18 11:01:20 -0700 | [diff] [blame] | 48 | #include <sys/syscall.h> |
| 49 | #endif |
| 50 | |
| 51 | #if defined(_WIN32) |
| 52 | #include <windows.h> |
| 53 | // This include needs to be here due to our coding conventions. Unfortunately |
| 54 | // it drags in the definition of the dread ERROR macro. |
| 55 | #ifdef ERROR |
| 56 | #undef ERROR |
| 57 | #endif |
Elliott Hughes | e1aee69 | 2012-01-17 16:40:10 -0800 | [diff] [blame] | 58 | #endif |
| 59 | |
Elliott Hughes | 11e4507 | 2011-08-16 17:40:46 -0700 | [diff] [blame] | 60 | namespace art { |
| 61 | |
David Sehr | 013fd80 | 2018-01-11 22:55:24 -0800 | [diff] [blame] | 62 | using android::base::ReadFileToString; |
Andreas Gampe | 46ee31b | 2016-12-14 10:11:49 -0800 | [diff] [blame] | 63 | using android::base::StringPrintf; |
| 64 | |
Elliott Hughes | 11d1b0c | 2012-01-23 16:57:47 -0800 | [diff] [blame] | 65 | pid_t GetTid() { |
Brian Carlstrom | f3a2641 | 2012-08-24 11:06:02 -0700 | [diff] [blame] | 66 | #if defined(__APPLE__) |
| 67 | uint64_t owner; |
Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 68 | CHECK_PTHREAD_CALL(pthread_threadid_np, (nullptr, &owner), __FUNCTION__); // Requires Mac OS 10.6 |
Brian Carlstrom | f3a2641 | 2012-08-24 11:06:02 -0700 | [diff] [blame] | 69 | return owner; |
Elliott Hughes | 323aa86 | 2014-08-20 15:00:04 -0700 | [diff] [blame] | 70 | #elif defined(__BIONIC__) |
| 71 | return gettid(); |
David Sehr | 10db8fe | 2018-07-18 11:01:20 -0700 | [diff] [blame] | 72 | #elif defined(_WIN32) |
| 73 | return static_cast<pid_t>(::GetCurrentThreadId()); |
Elliott Hughes | 11d1b0c | 2012-01-23 16:57:47 -0800 | [diff] [blame] | 74 | #else |
Elliott Hughes | 11d1b0c | 2012-01-23 16:57:47 -0800 | [diff] [blame] | 75 | return syscall(__NR_gettid); |
| 76 | #endif |
| 77 | } |
| 78 | |
Elliott Hughes | 289be85 | 2012-06-12 13:57:20 -0700 | [diff] [blame] | 79 | std::string GetThreadName(pid_t tid) { |
| 80 | std::string result; |
David Sehr | 10db8fe | 2018-07-18 11:01:20 -0700 | [diff] [blame] | 81 | #ifdef _WIN32 |
| 82 | UNUSED(tid); |
| 83 | result = "<unknown>"; |
| 84 | #else |
David Sehr | 013fd80 | 2018-01-11 22:55:24 -0800 | [diff] [blame] | 85 | // TODO: make this less Linux-specific. |
Elliott Hughes | 289be85 | 2012-06-12 13:57:20 -0700 | [diff] [blame] | 86 | if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) { |
Brian Carlstrom | 7934ac2 | 2013-07-26 10:54:15 -0700 | [diff] [blame] | 87 | result.resize(result.size() - 1); // Lose the trailing '\n'. |
Elliott Hughes | 289be85 | 2012-06-12 13:57:20 -0700 | [diff] [blame] | 88 | } else { |
| 89 | result = "<unknown>"; |
| 90 | } |
David Sehr | 10db8fe | 2018-07-18 11:01:20 -0700 | [diff] [blame] | 91 | #endif |
Elliott Hughes | 289be85 | 2012-06-12 13:57:20 -0700 | [diff] [blame] | 92 | return result; |
| 93 | } |
| 94 | |
Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 95 | std::string PrettySize(int64_t byte_count) { |
Elliott Hughes | c967f78 | 2012-04-16 10:23:15 -0700 | [diff] [blame] | 96 | // The byte thresholds at which we display amounts. A byte count is displayed |
| 97 | // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1]. |
Ian Rogers | ef7d42f | 2014-01-06 12:55:46 -0800 | [diff] [blame] | 98 | static const int64_t kUnitThresholds[] = { |
Elliott Hughes | c967f78 | 2012-04-16 10:23:15 -0700 | [diff] [blame] | 99 | 0, // B up to... |
| 100 | 3*1024, // KB up to... |
| 101 | 2*1024*1024, // MB up to... |
| 102 | 1024*1024*1024 // GB from here. |
| 103 | }; |
Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 104 | static const int64_t kBytesPerUnit[] = { 1, KB, MB, GB }; |
Elliott Hughes | c967f78 | 2012-04-16 10:23:15 -0700 | [diff] [blame] | 105 | static const char* const kUnitStrings[] = { "B", "KB", "MB", "GB" }; |
Mathieu Chartier | e6da9af | 2013-12-16 11:54:42 -0800 | [diff] [blame] | 106 | const char* negative_str = ""; |
| 107 | if (byte_count < 0) { |
| 108 | negative_str = "-"; |
| 109 | byte_count = -byte_count; |
| 110 | } |
Elliott Hughes | c967f78 | 2012-04-16 10:23:15 -0700 | [diff] [blame] | 111 | int i = arraysize(kUnitThresholds); |
| 112 | while (--i > 0) { |
| 113 | if (byte_count >= kUnitThresholds[i]) { |
| 114 | break; |
| 115 | } |
Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 116 | } |
Brian Carlstrom | 474cc79 | 2014-03-07 14:18:15 -0800 | [diff] [blame] | 117 | return StringPrintf("%s%" PRId64 "%s", |
| 118 | negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]); |
Ian Rogers | 3bb17a6 | 2012-01-27 23:56:44 -0800 | [diff] [blame] | 119 | } |
| 120 | |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 121 | void Split(const std::string& s, char separator, std::vector<std::string>* result) { |
Elliott Hughes | 3402380 | 2011-08-30 12:06:17 -0700 | [diff] [blame] | 122 | const char* p = s.data(); |
| 123 | const char* end = p + s.size(); |
| 124 | while (p != end) { |
Elliott Hughes | 48436bb | 2012-02-07 15:23:28 -0800 | [diff] [blame] | 125 | if (*p == separator) { |
Elliott Hughes | 3402380 | 2011-08-30 12:06:17 -0700 | [diff] [blame] | 126 | ++p; |
| 127 | } else { |
| 128 | const char* start = p; |
Elliott Hughes | 48436bb | 2012-02-07 15:23:28 -0800 | [diff] [blame] | 129 | while (++p != end && *p != separator) { |
| 130 | // Skip to the next occurrence of the separator. |
Elliott Hughes | 3402380 | 2011-08-30 12:06:17 -0700 | [diff] [blame] | 131 | } |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 132 | result->push_back(std::string(start, p - start)); |
Elliott Hughes | 3402380 | 2011-08-30 12:06:17 -0700 | [diff] [blame] | 133 | } |
| 134 | } |
| 135 | } |
| 136 | |
Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 137 | void SetThreadName(const char* thread_name) { |
Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 138 | int hasAt = 0; |
| 139 | int hasDot = 0; |
Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 140 | const char* s = thread_name; |
Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 141 | while (*s) { |
| 142 | if (*s == '.') { |
| 143 | hasDot = 1; |
| 144 | } else if (*s == '@') { |
| 145 | hasAt = 1; |
| 146 | } |
| 147 | s++; |
| 148 | } |
Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 149 | int len = s - thread_name; |
Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 150 | if (len < 15 || hasAt || !hasDot) { |
Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 151 | s = thread_name; |
Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 152 | } else { |
Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 153 | s = thread_name + len - 15; |
Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 154 | } |
David Sehr | 10db8fe | 2018-07-18 11:01:20 -0700 | [diff] [blame] | 155 | #if defined(__linux__) || defined(_WIN32) |
Elliott Hughes | 7c6a61e | 2012-03-12 18:01:41 -0700 | [diff] [blame] | 156 | // pthread_setname_np fails rather than truncating long strings. |
Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 157 | char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel. |
Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 158 | strncpy(buf, s, sizeof(buf)-1); |
| 159 | buf[sizeof(buf)-1] = '\0'; |
| 160 | errno = pthread_setname_np(pthread_self(), buf); |
| 161 | if (errno != 0) { |
| 162 | PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'"; |
| 163 | } |
Elliott Hughes | 0a18df8 | 2015-01-09 15:16:16 -0800 | [diff] [blame] | 164 | #else // __APPLE__ |
Elliott Hughes | 22869a9 | 2012-03-27 14:08:24 -0700 | [diff] [blame] | 165 | pthread_setname_np(thread_name); |
Elliott Hughes | dcc2474 | 2011-09-07 14:02:44 -0700 | [diff] [blame] | 166 | #endif |
| 167 | } |
| 168 | |
Brian Carlstrom | 2921201 | 2013-09-12 22:18:30 -0700 | [diff] [blame] | 169 | void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) { |
| 170 | *utime = *stime = *task_cpu = 0; |
David Sehr | 10db8fe | 2018-07-18 11:01:20 -0700 | [diff] [blame] | 171 | #ifdef _WIN32 |
| 172 | // TODO: implement this. |
| 173 | UNUSED(tid); |
| 174 | *state = 'S'; |
| 175 | #else |
Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 176 | std::string stats; |
David Sehr | 013fd80 | 2018-01-11 22:55:24 -0800 | [diff] [blame] | 177 | // TODO: make this less Linux-specific. |
Elliott Hughes | 8a31b50 | 2012-04-30 19:36:11 -0700 | [diff] [blame] | 178 | if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) { |
Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 179 | return; |
| 180 | } |
| 181 | // Skip the command, which may contain spaces. |
| 182 | stats = stats.substr(stats.find(')') + 2); |
| 183 | // Extract the three fields we care about. |
| 184 | std::vector<std::string> fields; |
Ian Rogers | 6f3dbba | 2014-10-14 17:41:57 -0700 | [diff] [blame] | 185 | Split(stats, ' ', &fields); |
Brian Carlstrom | 2921201 | 2013-09-12 22:18:30 -0700 | [diff] [blame] | 186 | *state = fields[0][0]; |
Mathieu Chartier | 2cebb24 | 2015-04-21 16:50:40 -0700 | [diff] [blame] | 187 | *utime = strtoull(fields[11].c_str(), nullptr, 10); |
| 188 | *stime = strtoull(fields[12].c_str(), nullptr, 10); |
| 189 | *task_cpu = strtoull(fields[36].c_str(), nullptr, 10); |
David Sehr | 10db8fe | 2018-07-18 11:01:20 -0700 | [diff] [blame] | 190 | #endif |
Elliott Hughes | bfe487b | 2011-10-26 15:48:55 -0700 | [diff] [blame] | 191 | } |
| 192 | |
Nicolas Geoffray | abbb0f7 | 2015-10-29 18:55:58 +0000 | [diff] [blame] | 193 | static void ParseStringAfterChar(const std::string& s, |
| 194 | char c, |
| 195 | std::string* parsed_value, |
| 196 | UsageFn Usage) { |
| 197 | std::string::size_type colon = s.find(c); |
| 198 | if (colon == std::string::npos) { |
| 199 | Usage("Missing char %c in option %s\n", c, s.c_str()); |
| 200 | } |
| 201 | // Add one to remove the char we were trimming until. |
| 202 | *parsed_value = s.substr(colon + 1); |
| 203 | } |
| 204 | |
| 205 | void ParseDouble(const std::string& option, |
| 206 | char after_char, |
| 207 | double min, |
| 208 | double max, |
| 209 | double* parsed_value, |
| 210 | UsageFn Usage) { |
| 211 | std::string substring; |
| 212 | ParseStringAfterChar(option, after_char, &substring, Usage); |
| 213 | bool sane_val = true; |
| 214 | double value; |
| 215 | if ((false)) { |
| 216 | // TODO: this doesn't seem to work on the emulator. b/15114595 |
| 217 | std::stringstream iss(substring); |
| 218 | iss >> value; |
| 219 | // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range. |
| 220 | sane_val = iss.eof() && (value >= min) && (value <= max); |
| 221 | } else { |
| 222 | char* end = nullptr; |
| 223 | value = strtod(substring.c_str(), &end); |
| 224 | sane_val = *end == '\0' && value >= min && value <= max; |
| 225 | } |
| 226 | if (!sane_val) { |
| 227 | Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str()); |
| 228 | } |
| 229 | *parsed_value = value; |
| 230 | } |
| 231 | |
Mathieu Chartier | 4d87df6 | 2016-01-07 15:14:19 -0800 | [diff] [blame] | 232 | void SleepForever() { |
| 233 | while (true) { |
| 234 | usleep(1000000); |
| 235 | } |
| 236 | } |
| 237 | |
Wei Li | 8991ad0 | 2018-09-13 16:43:39 +0800 | [diff] [blame] | 238 | std::string GetProcessStatus(const char* key) { |
| 239 | // Build search pattern of key and separator. |
| 240 | std::string pattern(key); |
| 241 | pattern.push_back(':'); |
| 242 | |
| 243 | // Search for status lines starting with pattern. |
| 244 | std::ifstream fs("/proc/self/status"); |
| 245 | std::string line; |
| 246 | while (std::getline(fs, line)) { |
| 247 | if (strncmp(pattern.c_str(), line.c_str(), pattern.size()) == 0) { |
| 248 | // Skip whitespace in matching line (if any). |
| 249 | size_t pos = line.find_first_not_of(" \t", pattern.size()); |
| 250 | if (UNLIKELY(pos == std::string::npos)) { |
| 251 | break; |
| 252 | } |
| 253 | return std::string(line, pos); |
| 254 | } |
| 255 | } |
| 256 | return "<unknown>"; |
| 257 | } |
| 258 | |
Elliott Hughes | 42ee142 | 2011-09-06 12:33:32 -0700 | [diff] [blame] | 259 | } // namespace art |