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, ¶m) != 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, ¶m) != 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, ¶m) < 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