Home | History | Annotate | Download | only in base
      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  */
     16 
     17 #include "utils.h"
     18 
     19 #include <inttypes.h>
     20 #include <pthread.h>
     21 #include <sys/stat.h>
     22 #include <sys/syscall.h>
     23 #include <sys/types.h>
     24 #include <sys/wait.h>
     25 #include <unistd.h>
     26 
     27 #include <memory>
     28 
     29 #include "android-base/file.h"
     30 #include "android-base/stringprintf.h"
     31 #include "android-base/strings.h"
     32 
     33 #include "base/os.h"
     34 
     35 #if defined(__APPLE__)
     36 #include <crt_externs.h>
     37 #include <sys/syscall.h>
     38 #include "AvailabilityMacros.h"  // For MAC_OS_X_VERSION_MAX_ALLOWED
     39 #endif
     40 
     41 #if defined(__linux__)
     42 #include <linux/unistd.h>
     43 #endif
     44 
     45 namespace art {
     46 
     47 using android::base::ReadFileToString;
     48 using android::base::StringAppendF;
     49 using android::base::StringPrintf;
     50 
     51 pid_t GetTid() {
     52 #if defined(__APPLE__)
     53   uint64_t owner;
     54   CHECK_PTHREAD_CALL(pthread_threadid_np, (nullptr, &owner), __FUNCTION__);  // Requires Mac OS 10.6
     55   return owner;
     56 #elif defined(__BIONIC__)
     57   return gettid();
     58 #else
     59   return syscall(__NR_gettid);
     60 #endif
     61 }
     62 
     63 std::string GetThreadName(pid_t tid) {
     64   std::string result;
     65   // TODO: make this less Linux-specific.
     66   if (ReadFileToString(StringPrintf("/proc/self/task/%d/comm", tid), &result)) {
     67     result.resize(result.size() - 1);  // Lose the trailing '\n'.
     68   } else {
     69     result = "<unknown>";
     70   }
     71   return result;
     72 }
     73 
     74 std::string PrettySize(int64_t byte_count) {
     75   // The byte thresholds at which we display amounts.  A byte count is displayed
     76   // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
     77   static const int64_t kUnitThresholds[] = {
     78     0,              // B up to...
     79     3*1024,         // KB up to...
     80     2*1024*1024,    // MB up to...
     81     1024*1024*1024  // GB from here.
     82   };
     83   static const int64_t kBytesPerUnit[] = { 1, KB, MB, GB };
     84   static const char* const kUnitStrings[] = { "B", "KB", "MB", "GB" };
     85   const char* negative_str = "";
     86   if (byte_count < 0) {
     87     negative_str = "-";
     88     byte_count = -byte_count;
     89   }
     90   int i = arraysize(kUnitThresholds);
     91   while (--i > 0) {
     92     if (byte_count >= kUnitThresholds[i]) {
     93       break;
     94     }
     95   }
     96   return StringPrintf("%s%" PRId64 "%s",
     97                       negative_str, byte_count / kBytesPerUnit[i], kUnitStrings[i]);
     98 }
     99 
    100 void Split(const std::string& s, char separator, std::vector<std::string>* result) {
    101   const char* p = s.data();
    102   const char* end = p + s.size();
    103   while (p != end) {
    104     if (*p == separator) {
    105       ++p;
    106     } else {
    107       const char* start = p;
    108       while (++p != end && *p != separator) {
    109         // Skip to the next occurrence of the separator.
    110       }
    111       result->push_back(std::string(start, p - start));
    112     }
    113   }
    114 }
    115 
    116 void SetThreadName(const char* thread_name) {
    117   int hasAt = 0;
    118   int hasDot = 0;
    119   const char* s = thread_name;
    120   while (*s) {
    121     if (*s == '.') {
    122       hasDot = 1;
    123     } else if (*s == '@') {
    124       hasAt = 1;
    125     }
    126     s++;
    127   }
    128   int len = s - thread_name;
    129   if (len < 15 || hasAt || !hasDot) {
    130     s = thread_name;
    131   } else {
    132     s = thread_name + len - 15;
    133   }
    134 #if defined(__linux__)
    135   // pthread_setname_np fails rather than truncating long strings.
    136   char buf[16];       // MAX_TASK_COMM_LEN=16 is hard-coded in the kernel.
    137   strncpy(buf, s, sizeof(buf)-1);
    138   buf[sizeof(buf)-1] = '\0';
    139   errno = pthread_setname_np(pthread_self(), buf);
    140   if (errno != 0) {
    141     PLOG(WARNING) << "Unable to set the name of current thread to '" << buf << "'";
    142   }
    143 #else  // __APPLE__
    144   pthread_setname_np(thread_name);
    145 #endif
    146 }
    147 
    148 void GetTaskStats(pid_t tid, char* state, int* utime, int* stime, int* task_cpu) {
    149   *utime = *stime = *task_cpu = 0;
    150   std::string stats;
    151   // TODO: make this less Linux-specific.
    152   if (!ReadFileToString(StringPrintf("/proc/self/task/%d/stat", tid), &stats)) {
    153     return;
    154   }
    155   // Skip the command, which may contain spaces.
    156   stats = stats.substr(stats.find(')') + 2);
    157   // Extract the three fields we care about.
    158   std::vector<std::string> fields;
    159   Split(stats, ' ', &fields);
    160   *state = fields[0][0];
    161   *utime = strtoull(fields[11].c_str(), nullptr, 10);
    162   *stime = strtoull(fields[12].c_str(), nullptr, 10);
    163   *task_cpu = strtoull(fields[36].c_str(), nullptr, 10);
    164 }
    165 
    166 static void ParseStringAfterChar(const std::string& s,
    167                                  char c,
    168                                  std::string* parsed_value,
    169                                  UsageFn Usage) {
    170   std::string::size_type colon = s.find(c);
    171   if (colon == std::string::npos) {
    172     Usage("Missing char %c in option %s\n", c, s.c_str());
    173   }
    174   // Add one to remove the char we were trimming until.
    175   *parsed_value = s.substr(colon + 1);
    176 }
    177 
    178 void ParseDouble(const std::string& option,
    179                  char after_char,
    180                  double min,
    181                  double max,
    182                  double* parsed_value,
    183                  UsageFn Usage) {
    184   std::string substring;
    185   ParseStringAfterChar(option, after_char, &substring, Usage);
    186   bool sane_val = true;
    187   double value;
    188   if ((false)) {
    189     // TODO: this doesn't seem to work on the emulator.  b/15114595
    190     std::stringstream iss(substring);
    191     iss >> value;
    192     // Ensure that we have a value, there was no cruft after it and it satisfies a sensible range.
    193     sane_val = iss.eof() && (value >= min) && (value <= max);
    194   } else {
    195     char* end = nullptr;
    196     value = strtod(substring.c_str(), &end);
    197     sane_val = *end == '\0' && value >= min && value <= max;
    198   }
    199   if (!sane_val) {
    200     Usage("Invalid double value %s for option %s\n", substring.c_str(), option.c_str());
    201   }
    202   *parsed_value = value;
    203 }
    204 
    205 void SleepForever() {
    206   while (true) {
    207     usleep(1000000);
    208   }
    209 }
    210 
    211 }  // namespace art
    212