xref: /aosp_15_r20/system/media/audio_utils/include/audio_utils/threads.h (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <algorithm>
20 #include <bitset>
21 #include <sys/syscall.h>   // SYS_gettid
22 #include <unistd.h>        // bionic gettid
23 #include <utils/Errors.h>  // status_t
24 
25 namespace android::audio_utils {
26 
27 /*
28  * Some basic priority definitions from linux,
29  * see MACROs in common/include/linux/sched/prio.h.
30  *
31  * On device limits may be found with the following command $ adb shell chrt -m
32  */
33 inline constexpr int kMaxNice = 19;  // inclusive
34 inline constexpr int kMinNice = -20; // inclusive
35 inline constexpr int kNiceWidth = (kMaxNice - kMinNice + 1);
36 inline constexpr int kMinRtPrio = 1; // inclusive
37 inline constexpr int kMaxRtPrio = 100;                    // [sic] exclusive
38 inline constexpr int kMaxPrio = kMaxRtPrio + kNiceWidth;  // [sic] exclusive
39 inline constexpr int kDefaultPrio = kMaxRtPrio + kNiceWidth / 2;
40 
41 /*
42  * The following conversion routines follow the linux equivalent.
43  * Here we use the term "unified priority" as the linux normal_prio.
44  *
45  * See common/kernel/sched/core.c __normal_prio().
46  */
47 
48 /**
49  * Convert CFS (SCHED_OTHER) nice to unified priority.
50  */
nice_to_unified_priority(int nice)51 inline int nice_to_unified_priority(int nice) {
52     return kDefaultPrio + nice;
53 }
54 
55 /**
56  * Convert unified priority to CFS (SCHED_OTHER) nice.
57  *
58  * Some unified priorities are not CFS, they will be clamped in range.
59  * Use is_cfs_priority() to check if a CFS priority.
60  */
unified_priority_to_nice(int priority)61 inline int unified_priority_to_nice(int priority) {
62     return std::clamp(priority - kDefaultPrio, kMinNice, kMaxNice);
63 }
64 
65 /**
66  * Convert SCHED_FIFO/SCHED_RR rtprio 1 - 99 to unified priority 98 to 0.
67  */
rtprio_to_unified_priority(int rtprio)68 inline int rtprio_to_unified_priority(int rtprio) {
69     return kMaxRtPrio - 1 - rtprio;
70 }
71 
72 /**
73  * Convert unified priority 0 to 98 to SCHED_FIFO/SCHED_RR rtprio 99 to 1.
74  *
75  * Some unified priorities are not real time, they will be clamped in range.
76  * Use is_realtime_priority() to check if real time priority.
77  */
unified_priority_to_rtprio(int priority)78 inline int unified_priority_to_rtprio(int priority) {
79     return std::clamp(kMaxRtPrio - 1 - priority, kMinRtPrio, kMaxRtPrio - 1);
80 }
81 
82 /**
83  * Returns whether the unified priority is realtime.
84  */
is_realtime_priority(int priority)85 inline bool is_realtime_priority(int priority) {
86     return priority >= 0 && priority < kMaxRtPrio;  // note this allows the unified value 99.
87 }
88 
89 /**
90  * Returns whether the unified priority is CFS.
91  */
is_cfs_priority(int priority)92 inline bool is_cfs_priority(int priority) {
93     return priority >= kMaxRtPrio && priority < kMaxPrio;
94 }
95 
96 /**
97  * Returns the linux thread id.
98  *
99  * We use gettid() which is available on bionic libc and modern glibc;
100  * for other libc, we syscall directly.
101  *
102  * This is not the same as std::thread::get_id() which returns pthread_self().
103  */
gettid_wrapper()104 pid_t inline gettid_wrapper() {
105 #if defined(__BIONIC__)
106     return ::gettid();
107 #else
108     return syscall(SYS_gettid);
109 #endif
110 }
111 
112 /*
113  * set_thread_priority() and get_thread_priority()
114  * both use the unified scheduler priority, where a lower value represents
115  * increasing priority.
116  *
117  * The linux kernel unified scheduler priority values are as follows:
118  * 0 - 98    (A real time priority rtprio between 99 and 1)
119  * 100 - 139 (A Completely Fair Scheduler niceness between -20 and 19)
120  *
121  * Real time schedulers (SCHED_FIFO and SCHED_RR) have rtprio between 1 and 99,
122  * where 1 is the lowest and 99 is the highest.
123  *
124  * The Completely Fair Scheduler (also known as SCHED_OTHER) has a
125  * nice value between 19 and -20, where 19 is the lowest and -20 the highest.
126  *
127  * Note: the unified priority is reported on /proc/<tid>/stat file as "prio".
128  *
129  * See common/kernel/sched/debug.c proc_sched_show_task().
130  */
131 
132 /**
133  * Sets the priority of tid to a unified priority.
134  *
135  * The range of priority is 0 through 139, inclusive.
136  * A priority value of 99 is changed to 98.
137  */
138 status_t set_thread_priority(pid_t tid, int priority);
139 
140 /**
141  * Returns the unified priority of the tid.
142  *
143  * A negative number represents error.
144  */
145 int get_thread_priority(int tid);
146 
147 /**
148  * An arbitrary CPU limit for Android running on Chrome / Linux / Windows devices.
149  */
150 inline constexpr size_t kMaxCpus = std::min(256, CPU_SETSIZE);
151 
152 /**
153  * Sets the thread affinity based on a bit mask.
154  *
155  * \param  tid where 0 represents the current thread.
156  * \param  mask where a set bit indicates that core is available for the thread
157  *         to execute on.
158  *         A 64 bit integer may be used so long as you only need to access
159  *         the first 64 cores (an integer will implicitly convert to the std::bitset).
160  * \return 0 on success or -errno on failure.
161  */
162 status_t set_thread_affinity(pid_t tid, const std::bitset<kMaxCpus>& mask);
163 
164 /**
165  * Returns the CPU mask thread affinity, which has a count of 0 if not found.
166  *
167  * \param  tid where 0 represents the current thread.
168  * \return a mask where a set bit indicates that core is allowed for the thread.
169  *         The bitset method to_ullong() may be used for devices with 64 CPUs or less.
170  */
171 std::bitset<kMaxCpus> get_thread_affinity(pid_t tid);
172 
173 /**
174  * Returns current thread's CPU core or -1 if not found.
175  */
176  int get_cpu();
177 
178 /**
179  * Returns number of CPUs (equivalent to std::thread::hardware_concurrency()
180  * but is internally cached).
181  *
182  * If the value is not well defined or not computable, 0 is returned.
183  * This is not cached and a subsequent call will retry.
184  */
185 size_t get_number_cpus();
186 
187 } // namespace android::audio_utils
188