diff options
author | 2018-03-02 12:01:51 -0800 | |
---|---|---|
committer | 2018-03-05 13:58:20 -0800 | |
commit | c431b9dc4b23cc950eb313695258df5d89f53b22 (patch) | |
tree | 422273559c3ae52caff0c6b1cf1a62a8312f0e26 /libartbase/base/utils.cc | |
parent | f46f46cf5bd32788d5252b7107628a66594a5e98 (diff) |
Move most of runtime/base to libartbase/base
Enforce the layering that code in runtime/base should not depend on
runtime by separating it into libartbase. Some of the code in
runtime/base depends on the Runtime class, so it cannot be moved yet.
Also, some of the tests depend on CommonRuntimeTest, which itself needs
to be factored (in a subsequent CL).
Bug: 22322814
Test: make -j 50 checkbuild
make -j 50 test-art-host
Change-Id: I8b096c1e2542f829eb456b4b057c71421b77d7e2
Diffstat (limited to 'libartbase/base/utils.cc')
-rw-r--r-- | libartbase/base/utils.cc | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/libartbase/base/utils.cc b/libartbase/base/utils.cc new file mode 100644 index 0000000000..029cffd3ab --- /dev/null +++ b/libartbase/base/utils.cc @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "utils.h" + +#include <inttypes.h> +#include <pthread.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <memory> + +#include "android-base/file.h" +#include "android-base/stringprintf.h" +#include "android-base/strings.h" + +#include "base/os.h" + +#if defined(__APPLE__) +#include <crt_externs.h> +#include <sys/syscall.h> +#include "AvailabilityMacros.h" // For MAC_OS_X_VERSION_MAX_ALLOWED +#endif + +#if defined(__linux__) +#include <linux/unistd.h> +#endif + +namespace art { + +using android::base::ReadFileToString; +using android::base::StringAppendF; +using android::base::StringPrintf; + +pid_t GetTid() { +#if defined(__APPLE__) + uint64_t owner; + CHECK_PTHREAD_CALL(pthread_threadid_np, (nullptr, &owner), __FUNCTION__); // Requires Mac OS 10.6 + return owner; +#elif defined(__BIONIC__) + return gettid(); +#else + return syscall(__NR_gettid); +#endif +} + +std::string GetThreadName(pid_t tid) { + std::string result; + // TODO: make this less Linux-specific. + if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) { + result.resize(result.size() - 1); // Lose the trailing '\n'. + } else { + result = "<unknown>"; + } + return result; +} + +std::string PrettySize(int64_t byte_count) { + // The byte thresholds at which we display amounts. A byte count is displayed + // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1]. + static const int64_t kUnitThresholds[] = { + 0, // B up to... + 3*1024, // KB up to... + 2*1024*1024, // MB up to... + 1024*1024*1024 // GB from here. + }; + static const int64_t kBytesPerUnit[] = { 1, KB, MB, GB }; + static const char* const kUnitStrings[] = { "B", "KB", "MB", "GB" }; + const char* negative_str = ""; + if (byte_count < 0) { + negative_str = "-"; + byte_count = -byte_count; + } + int i = arraysize(kUnitThresholds); + while (--i > 0) { + if (byte_count >= kUnitThresholds[i]) { + break; + } + } + return StringPrintf("%s%" PRId64 "%s", + negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]); +} + +void Split(const std::string& s, char separator, std::vector<std::string>* result) { + const char* p = s.data(); + const char* end = p + s.size(); + while (p != end) { + if (*p == separator) { + ++p; + } else { + const char* start = p; + while (++p != end && *p != separator) { + // Skip to the next occurrence of the separator. + } + result->push_back(std::string(start, p - start)); + } + } +} + +void SetThreadName(const char* thread_name) { + int hasAt = 0; + int hasDot = 0; + const char* s = thread_name; + while (*s) { + if (*s == '.') { + hasDot = 1; + } else if (*s == '@') { + hasAt = 1; + } + s++; + } + int len = s - thread_name; + if (len < 15 || hasAt || !hasDot) { + s = thread_name; + } else { + s = thread_name + len - 15; + } +#if defined(__linux__) + // pthread_setname_np fails rather than truncating long strings. + char buf[16]; // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel. + strncpy(buf, s, sizeof(buf)-1); + buf[sizeof(buf)-1] = '\0'; + errno = pthread_setname_np(pthread_self(), buf); + if (errno != 0) { + PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'"; + } +#else // __APPLE__ + pthread_setname_np(thread_name); +#endif +} + +void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) { + *utime = *stime = *task_cpu = 0; + std::string stats; + // TODO: make this less Linux-specific. + if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) { + return; + } + // Skip the command, which may contain spaces. + stats = stats.substr(stats.find(')') + 2); + // Extract the three fields we care about. + std::vector<std::string> fields; + Split(stats, ' ', &fields); + *state = fields[0][0]; + *utime = strtoull(fields[11].c_str(), nullptr, 10); + *stime = strtoull(fields[12].c_str(), nullptr, 10); + *task_cpu = strtoull(fields[36].c_str(), nullptr, 10); +} + +static void ParseStringAfterChar(const std::string& s, + char c, + std::string* parsed_value, + UsageFn Usage) { + std::string::size_type colon = s.find(c); + if (colon == std::string::npos) { + Usage("Missing char %c in option %s\n", c, s.c_str()); + } + // Add one to remove the char we were trimming until. + *parsed_value = s.substr(colon + 1); +} + +void ParseDouble(const std::string& option, + char after_char, + double min, + double max, + double* parsed_value, + UsageFn Usage) { + std::string substring; + ParseStringAfterChar(option, after_char, &substring, Usage); + bool sane_val = true; + double value; + if ((false)) { + // TODO: this doesn't seem to work on the emulator. b/15114595 + std::stringstream iss(substring); + iss >> value; + // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range. + sane_val = iss.eof() && (value >= min) && (value <= max); + } else { + char* end = nullptr; + value = strtod(substring.c_str(), &end); + sane_val = *end == '\0' && value >= min && value <= max; + } + if (!sane_val) { + Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str()); + } + *parsed_value = value; +} + +void SleepForever() { + while (true) { + usleep(1000000); + } +} + +} // namespace art |