Home | History | Annotate | Download | only in performanced
      1 #include "cpu_set.h"
      2 
      3 #include <log/log.h>
      4 
      5 #include <algorithm>
      6 #include <iomanip>
      7 #include <iostream>
      8 #include <sstream>
      9 #include <string>
     10 
     11 #include <android-base/file.h>
     12 
     13 #include "directory_reader.h"
     14 #include "stdio_filebuf.h"
     15 #include "task.h"
     16 #include "unique_file.h"
     17 
     18 using android::pdx::ErrorStatus;
     19 using android::pdx::Status;
     20 
     21 namespace {
     22 
     23 constexpr int kDirectoryFlags = O_RDONLY | O_DIRECTORY | O_CLOEXEC;
     24 constexpr pid_t kKernelThreadDaemonPid = 2;
     25 
     26 }  // anonymous namespace
     27 
     28 namespace android {
     29 namespace dvr {
     30 
     31 bool CpuSet::prefix_enabled_ = false;
     32 
     33 void CpuSetManager::Load(const std::string& cpuset_root) {
     34   if (!root_set_)
     35     root_set_ = Create(cpuset_root);
     36 }
     37 
     38 std::unique_ptr<CpuSet> CpuSetManager::Create(const std::string& path) {
     39   base::unique_fd root_cpuset_fd(open(path.c_str(), kDirectoryFlags));
     40   if (root_cpuset_fd.get() < 0) {
     41     ALOGE("CpuSet::Create: Failed to open \"%s\": %s", path.c_str(),
     42           strerror(errno));
     43     return nullptr;
     44   }
     45 
     46   return Create(std::move(root_cpuset_fd), "/", nullptr);
     47 }
     48 
     49 std::unique_ptr<CpuSet> CpuSetManager::Create(base::unique_fd base_fd,
     50                                               const std::string& name,
     51                                               CpuSet* parent) {
     52   DirectoryReader directory(base::unique_fd(dup(base_fd)));
     53   if (!directory) {
     54     ALOGE("CpuSet::Create: Failed to opendir %s cpuset: %s", name.c_str(),
     55           strerror(directory.GetError()));
     56     return nullptr;
     57   }
     58 
     59   std::unique_ptr<CpuSet> group(
     60       new CpuSet(parent, name, base::unique_fd(dup(base_fd))));
     61   path_map_.insert(std::make_pair(group->path(), group.get()));
     62 
     63   while (dirent* entry = directory.Next()) {
     64     if (entry->d_type == DT_DIR) {
     65       std::string directory_name(entry->d_name);
     66 
     67       if (directory_name == "." || directory_name == "..")
     68         continue;
     69 
     70       base::unique_fd entry_fd(
     71           openat(base_fd.get(), directory_name.c_str(), kDirectoryFlags));
     72       if (entry_fd.get() >= 0) {
     73         auto child =
     74             Create(std::move(entry_fd), directory_name.c_str(), group.get());
     75 
     76         if (child)
     77           group->AddChild(std::move(child));
     78         else
     79           return nullptr;
     80       } else {
     81         ALOGE("CpuSet::Create: Failed to openat \"%s\": %s", entry->d_name,
     82               strerror(errno));
     83         return nullptr;
     84       }
     85     }
     86   }
     87 
     88   return group;
     89 }
     90 
     91 CpuSet* CpuSetManager::Lookup(const std::string& path) {
     92   auto search = path_map_.find(path);
     93   if (search != path_map_.end())
     94     return search->second;
     95   else
     96     return nullptr;
     97 }
     98 
     99 std::vector<CpuSet*> CpuSetManager::GetCpuSets() {
    100   std::vector<CpuSet*> sets(path_map_.size());
    101 
    102   for (const auto& pair : path_map_) {
    103     sets.push_back(pair.second);
    104   }
    105 
    106   return sets;
    107 }
    108 
    109 std::string CpuSetManager::DumpState() const {
    110   size_t max_path = 0;
    111   std::vector<CpuSet*> sets;
    112 
    113   for (const auto& pair : path_map_) {
    114     max_path = std::max(max_path, pair.second->path().length());
    115     sets.push_back(pair.second);
    116   }
    117 
    118   std::sort(sets.begin(), sets.end(), [](const CpuSet* a, const CpuSet* b) {
    119     return a->path() < b->path();
    120   });
    121 
    122   std::ostringstream stream;
    123 
    124   stream << std::left;
    125   stream << std::setw(max_path) << "Path";
    126   stream << " ";
    127   stream << std::setw(6) << "CPUs";
    128   stream << " ";
    129   stream << std::setw(6) << "Tasks";
    130   stream << std::endl;
    131 
    132   stream << std::string(max_path, '_');
    133   stream << " ";
    134   stream << std::string(6, '_');
    135   stream << " ";
    136   stream << std::string(6, '_');
    137   stream << std::endl;
    138 
    139   for (const auto set : sets) {
    140     stream << std::left;
    141     stream << std::setw(max_path) << set->path();
    142     stream << " ";
    143     stream << std::right;
    144     stream << std::setw(6) << set->GetCpuList();
    145     stream << " ";
    146     stream << std::setw(6) << set->GetTasks().size();
    147     stream << std::endl;
    148   }
    149 
    150   return stream.str();
    151 }
    152 
    153 void CpuSetManager::MoveUnboundTasks(const std::string& target_set) {
    154   auto root = Lookup("/");
    155   if (!root) {
    156     ALOGE("CpuSetManager::MoveUnboundTasks: Failed to find root cpuset!");
    157     return;
    158   }
    159 
    160   auto target = Lookup(target_set);
    161   if (!target) {
    162     ALOGE(
    163         "CpuSetManager::MoveUnboundTasks: Failed to find target cpuset \"%s\"!",
    164         target_set.c_str());
    165     return;
    166   }
    167 
    168   auto cpu_list = root->GetCpuList();
    169 
    170   for (auto task_id : root->GetTasks()) {
    171     Task task(task_id);
    172 
    173     // Move only unbound kernel threads to the target cpuset.
    174     if (task.cpus_allowed_list() == cpu_list &&
    175         task.parent_process_id() == kKernelThreadDaemonPid) {
    176       ALOGD_IF(TRACE,
    177                "CpuSetManager::MoveUnboundTasks: Moving task_id=%d name=%s to "
    178                "target_set=%s tgid=%d ppid=%d.",
    179                task_id, task.name().c_str(), target_set.c_str(),
    180                task.thread_group_id(), task.parent_process_id());
    181 
    182       auto status = target->AttachTask(task_id);
    183       ALOGW_IF(!status && status.error() != EINVAL,
    184                "CpuSetManager::MoveUnboundTasks: Failed to attach task_id=%d "
    185                "to cpuset=%s: %s",
    186                task_id, target_set.c_str(), status.GetErrorMessage().c_str());
    187     } else {
    188       ALOGD_IF(TRACE,
    189                "CpuSet::MoveUnboundTasks: Skipping task_id=%d name=%s cpus=%s.",
    190                task_id, task.name().c_str(), task.cpus_allowed_list().c_str());
    191     }
    192   }
    193 }
    194 
    195 CpuSet::CpuSet(CpuSet* parent, const std::string& name,
    196                base::unique_fd&& cpuset_fd)
    197     : parent_(parent), name_(name), cpuset_fd_(std::move(cpuset_fd)) {
    198   if (parent_ == nullptr)
    199     path_ = name_;
    200   else if (parent_->IsRoot())
    201     path_ = parent_->name() + name_;
    202   else
    203     path_ = parent_->path() + "/" + name_;
    204 
    205   ALOGI("CpuSet::CpuSet: path=%s", path().c_str());
    206 }
    207 
    208 base::unique_fd CpuSet::OpenPropertyFile(const std::string& name) const {
    209   return OpenFile(prefix_enabled_ ? "cpuset." + name : name);
    210 }
    211 
    212 UniqueFile CpuSet::OpenPropertyFilePointer(const std::string& name) const {
    213   return OpenFilePointer(prefix_enabled_ ? "cpuset." + name : name);
    214 }
    215 
    216 base::unique_fd CpuSet::OpenFile(const std::string& name, int flags) const {
    217   const std::string relative_path = "./" + name;
    218   return base::unique_fd(
    219       openat(cpuset_fd_.get(), relative_path.c_str(), flags));
    220 }
    221 
    222 UniqueFile CpuSet::OpenFilePointer(const std::string& name, int flags) const {
    223   const std::string relative_path = "./" + name;
    224   base::unique_fd fd(openat(cpuset_fd_.get(), relative_path.c_str(), flags));
    225   if (fd.get() < 0) {
    226     ALOGE("CpuSet::OpenPropertyFilePointer: Failed to open %s/%s: %s",
    227           path_.c_str(), name.c_str(), strerror(errno));
    228     return nullptr;
    229   }
    230 
    231   UniqueFile fp(fdopen(fd.release(), "r"));
    232   if (!fp)
    233     ALOGE("CpuSet::OpenPropertyFilePointer: Failed to fdopen %s/%s: %s",
    234           path_.c_str(), name.c_str(), strerror(errno));
    235 
    236   return fp;
    237 }
    238 
    239 Status<void> CpuSet::AttachTask(pid_t task_id) const {
    240   auto file = OpenFile("tasks", O_RDWR);
    241   if (file.get() >= 0) {
    242     std::ostringstream stream;
    243     stream << task_id;
    244     std::string value = stream.str();
    245 
    246     const bool ret = base::WriteStringToFd(value, file.get());
    247     if (!ret)
    248       return ErrorStatus(errno);
    249     else
    250       return {};
    251   } else {
    252     const int error = errno;
    253     ALOGE("CpuSet::AttachTask: Failed to open %s/tasks: %s", path_.c_str(),
    254           strerror(error));
    255     return ErrorStatus(error);
    256   }
    257 }
    258 
    259 std::vector<pid_t> CpuSet::GetTasks() const {
    260   std::vector<pid_t> tasks;
    261 
    262   if (auto file = OpenFilePointer("tasks")) {
    263     stdio_filebuf<char> filebuf(file.get());
    264     std::istream file_stream(&filebuf);
    265 
    266     for (std::string line; std::getline(file_stream, line);) {
    267       pid_t task_id = std::strtol(line.c_str(), nullptr, 10);
    268       tasks.push_back(task_id);
    269     }
    270   }
    271 
    272   return tasks;
    273 }
    274 
    275 std::string CpuSet::GetCpuList() const {
    276   if (auto file = OpenPropertyFilePointer("cpus")) {
    277     stdio_filebuf<char> filebuf(file.get());
    278     std::istream file_stream(&filebuf);
    279 
    280     std::string line;
    281     if (std::getline(file_stream, line))
    282       return line;
    283   }
    284 
    285   ALOGE("CpuSet::GetCpuList: Failed to read cpu list!!!");
    286   return "";
    287 }
    288 
    289 void CpuSet::AddChild(std::unique_ptr<CpuSet> child) {
    290   children_.push_back(std::move(child));
    291 }
    292 
    293 }  // namespace dvr
    294 }  // namespace android
    295