Home | History | Annotate | Download | only in performanced
      1 #include "performance_service.h"
      2 
      3 #include <sched.h>
      4 #include <sys/prctl.h>
      5 #include <unistd.h>
      6 
      7 #include <pdx/default_transport/service_endpoint.h>
      8 #include <pdx/rpc/argument_encoder.h>
      9 #include <pdx/rpc/message_buffer.h>
     10 #include <pdx/rpc/remote_method.h>
     11 #include <private/dvr/performance_rpc.h>
     12 
     13 #include "task.h"
     14 
     15 // This prctl is only available in Android kernels.
     16 #define PR_SET_TIMERSLACK_PID 41
     17 
     18 using android::pdx::Message;
     19 using android::pdx::rpc::DispatchRemoteMethod;
     20 using android::pdx::default_transport::Endpoint;
     21 
     22 namespace {
     23 
     24 const char kCpuSetBasePath[] = "/dev/cpuset";
     25 
     26 constexpr unsigned long kTimerSlackForegroundNs = 50000;
     27 constexpr unsigned long kTimerSlackBackgroundNs = 40000000;
     28 
     29 }  // anonymous namespace
     30 
     31 namespace android {
     32 namespace dvr {
     33 
     34 PerformanceService::PerformanceService()
     35     : BASE("PerformanceService",
     36            Endpoint::Create(PerformanceRPC::kClientPath)) {
     37   cpuset_.Load(kCpuSetBasePath);
     38 
     39   Task task(getpid());
     40   ALOGI("Running in cpuset=%s uid=%d gid=%d", task.GetCpuSetPath().c_str(),
     41         task.user_id()[Task::kUidReal], task.group_id()[Task::kUidReal]);
     42 
     43   // Errors here are checked in IsInitialized().
     44   sched_fifo_min_priority_ = sched_get_priority_min(SCHED_FIFO);
     45   sched_fifo_max_priority_ = sched_get_priority_max(SCHED_FIFO);
     46 
     47   const int fifo_range = sched_fifo_max_priority_ - sched_fifo_min_priority_;
     48   const int fifo_low = sched_fifo_min_priority_;
     49   const int fifo_medium = sched_fifo_min_priority_ + fifo_range / 5;
     50 
     51   // TODO(eieio): Make this configurable on the command line.
     52   cpuset_.MoveUnboundTasks("/kernel");
     53 
     54   // Setup the scheduler classes.
     55   scheduler_classes_ = {
     56       {"audio:low",
     57        {.timer_slack = kTimerSlackForegroundNs,
     58         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
     59         .priority = fifo_medium}},
     60       {"audio:high",
     61        {.timer_slack = kTimerSlackForegroundNs,
     62         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
     63         .priority = fifo_medium + 3}},
     64       {"graphics",
     65        {.timer_slack = kTimerSlackForegroundNs,
     66         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
     67         .priority = fifo_medium}},
     68       {"graphics:low",
     69        {.timer_slack = kTimerSlackForegroundNs,
     70         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
     71         .priority = fifo_medium}},
     72       {"graphics:high",
     73        {.timer_slack = kTimerSlackForegroundNs,
     74         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
     75         .priority = fifo_medium + 2}},
     76       {"sensors",
     77        {.timer_slack = kTimerSlackForegroundNs,
     78         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
     79         .priority = fifo_low}},
     80       {"sensors:low",
     81        {.timer_slack = kTimerSlackForegroundNs,
     82         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
     83         .priority = fifo_low}},
     84       {"sensors:high",
     85        {.timer_slack = kTimerSlackForegroundNs,
     86         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
     87         .priority = fifo_low + 1}},
     88       {"normal",
     89        {.timer_slack = kTimerSlackForegroundNs,
     90         .scheduler_policy = SCHED_NORMAL,
     91         .priority = 0}},
     92       {"foreground",
     93        {.timer_slack = kTimerSlackForegroundNs,
     94         .scheduler_policy = SCHED_NORMAL,
     95         .priority = 0}},
     96       {"background",
     97        {.timer_slack = kTimerSlackBackgroundNs,
     98         .scheduler_policy = SCHED_BATCH,
     99         .priority = 0}},
    100       {"batch",
    101        {.timer_slack = kTimerSlackBackgroundNs,
    102         .scheduler_policy = SCHED_BATCH,
    103         .priority = 0}},
    104   };
    105 }
    106 
    107 bool PerformanceService::IsInitialized() const {
    108   return BASE::IsInitialized() && cpuset_ && sched_fifo_min_priority_ >= 0 &&
    109          sched_fifo_max_priority_ >= 0;
    110 }
    111 
    112 std::string PerformanceService::DumpState(size_t /*max_length*/) {
    113   return cpuset_.DumpState();
    114 }
    115 
    116 int PerformanceService::OnSetCpuPartition(Message& message, pid_t task_id,
    117                                           const std::string& partition) {
    118   Task task(task_id);
    119   if (!task || task.thread_group_id() != message.GetProcessId())
    120     return -EINVAL;
    121 
    122   auto target_set = cpuset_.Lookup(partition);
    123   if (!target_set)
    124     return -ENOENT;
    125 
    126   const auto attach_error = target_set->AttachTask(task_id);
    127   if (attach_error)
    128     return attach_error;
    129 
    130   return 0;
    131 }
    132 
    133 int PerformanceService::OnSetSchedulerClass(
    134     Message& message, pid_t task_id, const std::string& scheduler_class) {
    135   // Make sure the task id is valid and belongs to the sending process.
    136   Task task(task_id);
    137   if (!task || task.thread_group_id() != message.GetProcessId())
    138     return -EINVAL;
    139 
    140   struct sched_param param;
    141 
    142   // TODO(eieio): Apply rules based on the requesting process. Applications are
    143   // only allowed one audio thread that runs at SCHED_FIFO. System services can
    144   // have more than one.
    145   auto search = scheduler_classes_.find(scheduler_class);
    146   if (search != scheduler_classes_.end()) {
    147     auto config = search->second;
    148     param.sched_priority = config.priority;
    149     sched_setscheduler(task_id, config.scheduler_policy, &param);
    150     prctl(PR_SET_TIMERSLACK_PID, config.timer_slack, task_id);
    151     ALOGI("PerformanceService::OnSetSchedulerClass: Set task=%d to class=%s.",
    152           task_id, scheduler_class.c_str());
    153     return 0;
    154   } else {
    155     ALOGE(
    156         "PerformanceService::OnSetSchedulerClass: Invalid class=%s requested "
    157         "by task=%d.",
    158         scheduler_class.c_str(), task_id);
    159     return -EINVAL;
    160   }
    161 }
    162 
    163 std::string PerformanceService::OnGetCpuPartition(Message& message,
    164                                                   pid_t task_id) {
    165   // Make sure the task id is valid and belongs to the sending process.
    166   Task task(task_id);
    167   if (!task || task.thread_group_id() != message.GetProcessId())
    168     REPLY_ERROR_RETURN(message, EINVAL, "");
    169 
    170   return task.GetCpuSetPath();
    171 }
    172 
    173 pdx::Status<void> PerformanceService::HandleMessage(Message& message) {
    174   switch (message.GetOp()) {
    175     case PerformanceRPC::SetCpuPartition::Opcode:
    176       DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
    177           *this, &PerformanceService::OnSetCpuPartition, message);
    178       return {};
    179 
    180     case PerformanceRPC::SetSchedulerClass::Opcode:
    181       DispatchRemoteMethod<PerformanceRPC::SetSchedulerClass>(
    182           *this, &PerformanceService::OnSetSchedulerClass, message);
    183       return {};
    184 
    185     case PerformanceRPC::GetCpuPartition::Opcode:
    186       DispatchRemoteMethod<PerformanceRPC::GetCpuPartition>(
    187           *this, &PerformanceService::OnGetCpuPartition, message);
    188       return {};
    189 
    190     default:
    191       return Service::HandleMessage(message);
    192   }
    193 }
    194 
    195 }  // namespace dvr
    196 }  // namespace android
    197