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