summaryrefslogtreecommitdiff
path: root/libartbase/base/utils.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libartbase/base/utils.cc')
-rw-r--r--libartbase/base/utils.cc211
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