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