xref: /aosp_15_r20/system/media/audio_utils/threads.cpp (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1*b9df5ad1SAndroid Build Coastguard Worker /*
2*b9df5ad1SAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*b9df5ad1SAndroid Build Coastguard Worker  *
4*b9df5ad1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*b9df5ad1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*b9df5ad1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*b9df5ad1SAndroid Build Coastguard Worker  *
8*b9df5ad1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*b9df5ad1SAndroid Build Coastguard Worker  *
10*b9df5ad1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*b9df5ad1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*b9df5ad1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b9df5ad1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*b9df5ad1SAndroid Build Coastguard Worker  * limitations under the License.
15*b9df5ad1SAndroid Build Coastguard Worker  */
16*b9df5ad1SAndroid Build Coastguard Worker 
17*b9df5ad1SAndroid Build Coastguard Worker #define LOG_TAG "audio_utils::threads"
18*b9df5ad1SAndroid Build Coastguard Worker 
19*b9df5ad1SAndroid Build Coastguard Worker #include <audio_utils/threads.h>
20*b9df5ad1SAndroid Build Coastguard Worker 
21*b9df5ad1SAndroid Build Coastguard Worker #include <algorithm>  // std::clamp
22*b9df5ad1SAndroid Build Coastguard Worker #include <errno.h>
23*b9df5ad1SAndroid Build Coastguard Worker #include <sched.h>    // scheduler
24*b9df5ad1SAndroid Build Coastguard Worker #include <sys/resource.h>
25*b9df5ad1SAndroid Build Coastguard Worker #include <thread>
26*b9df5ad1SAndroid Build Coastguard Worker #include <utils/Errors.h>  // status_t
27*b9df5ad1SAndroid Build Coastguard Worker #include <utils/Log.h>
28*b9df5ad1SAndroid Build Coastguard Worker 
29*b9df5ad1SAndroid Build Coastguard Worker namespace android::audio_utils {
30*b9df5ad1SAndroid Build Coastguard Worker 
31*b9df5ad1SAndroid Build Coastguard Worker /**
32*b9df5ad1SAndroid Build Coastguard Worker  * Sets the unified priority of the tid.
33*b9df5ad1SAndroid Build Coastguard Worker  */
set_thread_priority(pid_t tid,int priority)34*b9df5ad1SAndroid Build Coastguard Worker status_t set_thread_priority(pid_t tid, int priority) {
35*b9df5ad1SAndroid Build Coastguard Worker     if (is_realtime_priority(priority)) {
36*b9df5ad1SAndroid Build Coastguard Worker         // audio processes are designed to work with FIFO, not RR.
37*b9df5ad1SAndroid Build Coastguard Worker         constexpr int new_policy = SCHED_FIFO;
38*b9df5ad1SAndroid Build Coastguard Worker         const int rtprio = unified_priority_to_rtprio(priority);
39*b9df5ad1SAndroid Build Coastguard Worker         struct sched_param param {
40*b9df5ad1SAndroid Build Coastguard Worker             .sched_priority = rtprio,
41*b9df5ad1SAndroid Build Coastguard Worker         };
42*b9df5ad1SAndroid Build Coastguard Worker         if (sched_setscheduler(tid, new_policy, &param) != 0) {
43*b9df5ad1SAndroid Build Coastguard Worker             ALOGW("%s: Cannot set FIFO priority for tid %d to policy %d rtprio %d  %s",
44*b9df5ad1SAndroid Build Coastguard Worker                     __func__, tid, new_policy, rtprio, strerror(errno));
45*b9df5ad1SAndroid Build Coastguard Worker             return -errno;
46*b9df5ad1SAndroid Build Coastguard Worker         }
47*b9df5ad1SAndroid Build Coastguard Worker         return NO_ERROR;
48*b9df5ad1SAndroid Build Coastguard Worker     } else if (is_cfs_priority(priority)) {
49*b9df5ad1SAndroid Build Coastguard Worker         const int policy = sched_getscheduler(tid);
50*b9df5ad1SAndroid Build Coastguard Worker         const int nice = unified_priority_to_nice(priority);
51*b9df5ad1SAndroid Build Coastguard Worker         if (policy != SCHED_OTHER) {
52*b9df5ad1SAndroid Build Coastguard Worker             struct sched_param param{};
53*b9df5ad1SAndroid Build Coastguard Worker             constexpr int new_policy = SCHED_OTHER;
54*b9df5ad1SAndroid Build Coastguard Worker             if (sched_setscheduler(tid, new_policy, &param) != 0) {
55*b9df5ad1SAndroid Build Coastguard Worker                 ALOGW("%s: Cannot set CFS priority for tid %d to policy %d nice %d  %s",
56*b9df5ad1SAndroid Build Coastguard Worker                         __func__, tid, new_policy, nice, strerror(errno));
57*b9df5ad1SAndroid Build Coastguard Worker                 return -errno;
58*b9df5ad1SAndroid Build Coastguard Worker             }
59*b9df5ad1SAndroid Build Coastguard Worker         }
60*b9df5ad1SAndroid Build Coastguard Worker         if (setpriority(PRIO_PROCESS, tid, nice) != 0) return -errno;
61*b9df5ad1SAndroid Build Coastguard Worker         return NO_ERROR;
62*b9df5ad1SAndroid Build Coastguard Worker     } else {
63*b9df5ad1SAndroid Build Coastguard Worker         return BAD_VALUE;
64*b9df5ad1SAndroid Build Coastguard Worker     }
65*b9df5ad1SAndroid Build Coastguard Worker }
66*b9df5ad1SAndroid Build Coastguard Worker 
67*b9df5ad1SAndroid Build Coastguard Worker /**
68*b9df5ad1SAndroid Build Coastguard Worker  * Returns the unified priority of the tid.
69*b9df5ad1SAndroid Build Coastguard Worker  *
70*b9df5ad1SAndroid Build Coastguard Worker  * A negative number represents error.
71*b9df5ad1SAndroid Build Coastguard Worker  */
get_thread_priority(int tid)72*b9df5ad1SAndroid Build Coastguard Worker int get_thread_priority(int tid) {
73*b9df5ad1SAndroid Build Coastguard Worker     const int policy = sched_getscheduler(tid);
74*b9df5ad1SAndroid Build Coastguard Worker     if (policy < 0) return -errno;
75*b9df5ad1SAndroid Build Coastguard Worker 
76*b9df5ad1SAndroid Build Coastguard Worker     if (policy == SCHED_OTHER) {
77*b9df5ad1SAndroid Build Coastguard Worker         errno = 0;  // negative return value valid, so check errno change.
78*b9df5ad1SAndroid Build Coastguard Worker         const int nice = getpriority(PRIO_PROCESS, tid);
79*b9df5ad1SAndroid Build Coastguard Worker         if (errno != 0) return -errno;
80*b9df5ad1SAndroid Build Coastguard Worker         return nice_to_unified_priority(nice);
81*b9df5ad1SAndroid Build Coastguard Worker     } else if (policy == SCHED_FIFO || policy == SCHED_RR) {
82*b9df5ad1SAndroid Build Coastguard Worker         struct sched_param param{};
83*b9df5ad1SAndroid Build Coastguard Worker         if (sched_getparam(tid, &param) < 0) return -errno;
84*b9df5ad1SAndroid Build Coastguard Worker         return rtprio_to_unified_priority(param.sched_priority);
85*b9df5ad1SAndroid Build Coastguard Worker     } else {
86*b9df5ad1SAndroid Build Coastguard Worker         return INVALID_OPERATION;
87*b9df5ad1SAndroid Build Coastguard Worker     }
88*b9df5ad1SAndroid Build Coastguard Worker }
89*b9df5ad1SAndroid Build Coastguard Worker 
set_thread_affinity(pid_t tid,const std::bitset<kMaxCpus> & mask)90*b9df5ad1SAndroid Build Coastguard Worker status_t set_thread_affinity(pid_t tid, const std::bitset<kMaxCpus>& mask) {
91*b9df5ad1SAndroid Build Coastguard Worker     cpu_set_t cpuset;
92*b9df5ad1SAndroid Build Coastguard Worker     CPU_ZERO(&cpuset);
93*b9df5ad1SAndroid Build Coastguard Worker     const size_t limit = std::min(get_number_cpus(), kMaxCpus);
94*b9df5ad1SAndroid Build Coastguard Worker     for (size_t i = 0; i < limit; ++i) {
95*b9df5ad1SAndroid Build Coastguard Worker         if (mask.test(i)) {
96*b9df5ad1SAndroid Build Coastguard Worker             CPU_SET(i, &cpuset);
97*b9df5ad1SAndroid Build Coastguard Worker         }
98*b9df5ad1SAndroid Build Coastguard Worker     }
99*b9df5ad1SAndroid Build Coastguard Worker     if (sched_setaffinity(tid, sizeof(cpuset), &cpuset) == 0) {
100*b9df5ad1SAndroid Build Coastguard Worker         return OK;
101*b9df5ad1SAndroid Build Coastguard Worker     }
102*b9df5ad1SAndroid Build Coastguard Worker     return -errno;
103*b9df5ad1SAndroid Build Coastguard Worker }
104*b9df5ad1SAndroid Build Coastguard Worker 
get_thread_affinity(pid_t tid)105*b9df5ad1SAndroid Build Coastguard Worker std::bitset<kMaxCpus> get_thread_affinity(pid_t tid) {
106*b9df5ad1SAndroid Build Coastguard Worker     cpu_set_t cpuset;
107*b9df5ad1SAndroid Build Coastguard Worker     CPU_ZERO(&cpuset);
108*b9df5ad1SAndroid Build Coastguard Worker     std::bitset<kMaxCpus> mask;
109*b9df5ad1SAndroid Build Coastguard Worker     if (sched_getaffinity(tid, sizeof(cpuset), &cpuset) == 0) {
110*b9df5ad1SAndroid Build Coastguard Worker         const size_t limit = std::min(get_number_cpus(), kMaxCpus);
111*b9df5ad1SAndroid Build Coastguard Worker         for (size_t i = 0; i < limit; ++i) {
112*b9df5ad1SAndroid Build Coastguard Worker             if (CPU_ISSET(i, &cpuset)) {
113*b9df5ad1SAndroid Build Coastguard Worker                 mask.set(i);
114*b9df5ad1SAndroid Build Coastguard Worker             }
115*b9df5ad1SAndroid Build Coastguard Worker         }
116*b9df5ad1SAndroid Build Coastguard Worker     }
117*b9df5ad1SAndroid Build Coastguard Worker     return mask;
118*b9df5ad1SAndroid Build Coastguard Worker }
119*b9df5ad1SAndroid Build Coastguard Worker 
get_cpu()120*b9df5ad1SAndroid Build Coastguard Worker int get_cpu() {
121*b9df5ad1SAndroid Build Coastguard Worker     return sched_getcpu();
122*b9df5ad1SAndroid Build Coastguard Worker }
123*b9df5ad1SAndroid Build Coastguard Worker 
124*b9df5ad1SAndroid Build Coastguard Worker /*
125*b9df5ad1SAndroid Build Coastguard Worker  * std::thread::hardware_concurrency() is not optimized.  We cache the value here
126*b9df5ad1SAndroid Build Coastguard Worker  * and it is implementation dependent whether std::thread::hardware_concurrency()
127*b9df5ad1SAndroid Build Coastguard Worker  * returns only the cpus currently online, or includes offline hot plug cpus.
128*b9df5ad1SAndroid Build Coastguard Worker  *
129*b9df5ad1SAndroid Build Coastguard Worker  * See external/libcxx/src/thread.cpp.
130*b9df5ad1SAndroid Build Coastguard Worker  */
get_number_cpus()131*b9df5ad1SAndroid Build Coastguard Worker size_t get_number_cpus() {
132*b9df5ad1SAndroid Build Coastguard Worker     static constinit std::atomic<size_t> n{};  // zero initialized.
133*b9df5ad1SAndroid Build Coastguard Worker     size_t value = n.load(std::memory_order_relaxed);
134*b9df5ad1SAndroid Build Coastguard Worker     if (value == 0) {  // not set, so we fetch.
135*b9df5ad1SAndroid Build Coastguard Worker         value = std::thread::hardware_concurrency();
136*b9df5ad1SAndroid Build Coastguard Worker         n.store(value, std::memory_order_relaxed);  // on race, this store is idempotent.
137*b9df5ad1SAndroid Build Coastguard Worker     }
138*b9df5ad1SAndroid Build Coastguard Worker     return value;
139*b9df5ad1SAndroid Build Coastguard Worker }
140*b9df5ad1SAndroid Build Coastguard Worker 
141*b9df5ad1SAndroid Build Coastguard Worker } // namespace android::audio_utils
142