blob: 20771c0c5d5c396b1b151957927ea9901880661c [file] [log] [blame]
Raphael0384a982009-09-15 17:10:17 -07001
San Mehat493dad92009-09-12 10:06:57 -07002/* libs/cutils/sched_policy.c
3**
4** Copyright 2007, The Android Open Source Project
5**
6** Licensed under the Apache License, Version 2.0 (the "License");
7** you may not use this file except in compliance with the License.
8** You may obtain a copy of the License at
9**
10** http://www.apache.org/licenses/LICENSE-2.0
11**
12** Unless required by applicable law or agreed to in writing, software
13** distributed under the License is distributed on an "AS IS" BASIS,
14** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15** See the License for the specific language governing permissions and
16** limitations under the License.
17*/
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <unistd.h>
22#include <string.h>
23#include <errno.h>
24#include <fcntl.h>
Raphael0384a982009-09-15 17:10:17 -070025
San Mehatd2e4e462009-10-29 11:48:00 -070026#define LOG_TAG "SchedPolicy"
27#include "cutils/log.h"
28
Raphael0384a982009-09-15 17:10:17 -070029#ifdef HAVE_SCHED_H
Brad Fitzpatrick86b12152010-05-08 11:51:13 -070030#ifdef HAVE_PTHREADS
Raphael0384a982009-09-15 17:10:17 -070031
San Mehat493dad92009-09-12 10:06:57 -070032#include <sched.h>
Brad Fitzpatrick86b12152010-05-08 11:51:13 -070033#include <pthread.h>
San Mehat493dad92009-09-12 10:06:57 -070034
35#include <cutils/sched_policy.h>
36
San Mehat3cd5b662009-09-14 16:05:24 -070037#ifndef SCHED_NORMAL
38 #define SCHED_NORMAL 0
39#endif
40
41#ifndef SCHED_BATCH
42 #define SCHED_BATCH 3
43#endif
44
San Mehat805d67a2009-10-29 13:56:26 -070045#define POLICY_DEBUG 0
San Mehatd2e4e462009-10-29 11:48:00 -070046
Glenn Kasten10ec3c72012-04-19 15:25:58 -070047#define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
48
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070049static pthread_once_t the_once = PTHREAD_ONCE_INIT;
50
San Mehatc0dfca72009-10-27 11:52:55 -070051static int __sys_supports_schedgroups = -1;
52
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070053// File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070054static int bg_cgroup_fd = -1;
Glenn Kasten10ec3c72012-04-19 15:25:58 -070055static int fg_cgroup_fd = -1;
56#if CAN_SET_SP_SYSTEM
57static int system_cgroup_fd = -1;
58#endif
59static int audio_app_cgroup_fd = -1;
60static int audio_sys_cgroup_fd = -1;
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070061
62/* Add tid to the scheduling group defined by the policy */
63static int add_tid_to_cgroup(int tid, SchedPolicy policy)
San Mehat493dad92009-09-12 10:06:57 -070064{
65 int fd;
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070066
Glenn Kasten10ec3c72012-04-19 15:25:58 -070067 switch (policy) {
68 case SP_BACKGROUND:
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070069 fd = bg_cgroup_fd;
Glenn Kasten10ec3c72012-04-19 15:25:58 -070070 break;
71 case SP_FOREGROUND:
72 fd = fg_cgroup_fd;
73 break;
74#if CAN_SET_SP_SYSTEM
75 case SP_SYSTEM:
76 fd = system_cgroup_fd;
77 break;
78#endif
79 case SP_AUDIO_APP:
80 fd = audio_app_cgroup_fd;
81 break;
82 case SP_AUDIO_SYS:
83 fd = audio_sys_cgroup_fd;
84 break;
85 default:
86 fd = -1;
87 break;
Brad Fitzpatricke43c2482010-05-07 12:06:05 -070088 }
89
90 if (fd < 0) {
Glenn Kasten10ec3c72012-04-19 15:25:58 -070091 SLOGE("add_tid_to_cgroup failed; policy=%d\n", policy);
San Mehat493dad92009-09-12 10:06:57 -070092 return -1;
San Mehat805d67a2009-10-29 13:56:26 -070093 }
San Mehat493dad92009-09-12 10:06:57 -070094
Brad Fitzpatrick253e27a2010-05-06 10:00:37 -070095 // specialized itoa -- works for tid > 0
96 char text[22];
97 char *end = text + sizeof(text) - 1;
98 char *ptr = end;
99 *ptr = '\0';
100 while (tid > 0) {
101 *--ptr = '0' + (tid % 10);
102 tid = tid / 10;
103 }
104
105 if (write(fd, ptr, end - ptr) < 0) {
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700106 /*
107 * If the thread is in the process of exiting,
108 * don't flag an error
109 */
110 if (errno == ESRCH)
111 return 0;
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700112 SLOGW("add_tid_to_cgroup failed to write '%s' (%s); policy=%d\n",
113 ptr, strerror(errno), policy);
San Mehat493dad92009-09-12 10:06:57 -0700114 return -1;
115 }
116
San Mehat493dad92009-09-12 10:06:57 -0700117 return 0;
118}
119
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700120static void __initialize(void) {
121 char* filename;
122 if (!access("/dev/cpuctl/tasks", F_OK)) {
123 __sys_supports_schedgroups = 1;
124
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700125#if CAN_SET_SP_SYSTEM
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700126 filename = "/dev/cpuctl/tasks";
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700127 system_cgroup_fd = open(filename, O_WRONLY);
128 if (system_cgroup_fd < 0) {
129 SLOGV("open of %s failed: %s\n", filename, strerror(errno));
130 }
131#endif
132
133 filename = "/dev/cpuctl/foreground/tasks";
134 fg_cgroup_fd = open(filename, O_WRONLY);
135 if (fg_cgroup_fd < 0) {
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700136 SLOGE("open of %s failed: %s\n", filename, strerror(errno));
San Mehat493dad92009-09-12 10:06:57 -0700137 }
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700138
139 filename = "/dev/cpuctl/bg_non_interactive/tasks";
140 bg_cgroup_fd = open(filename, O_WRONLY);
141 if (bg_cgroup_fd < 0) {
142 SLOGE("open of %s failed: %s\n", filename, strerror(errno));
143 }
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700144
145 filename = "/dev/cpuctl/audio_app/tasks";
146 audio_app_cgroup_fd = open(filename, O_WRONLY);
147 if (audio_app_cgroup_fd < 0) {
148 SLOGV("open of %s failed: %s\n", filename, strerror(errno));
149 }
150
151 filename = "/dev/cpuctl/audio_sys/tasks";
152 audio_sys_cgroup_fd = open(filename, O_WRONLY);
153 if (audio_sys_cgroup_fd < 0) {
154 SLOGV("open of %s failed: %s\n", filename, strerror(errno));
155 }
156
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700157 } else {
158 __sys_supports_schedgroups = 0;
San Mehat493dad92009-09-12 10:06:57 -0700159 }
San Mehatc0dfca72009-10-27 11:52:55 -0700160}
161
162/*
163 * Try to get the scheduler group.
164 *
San Mehat503df202010-03-02 17:09:56 -0800165 * The data from /proc/<pid>/cgroup looks (something) like:
San Mehatc0dfca72009-10-27 11:52:55 -0700166 * 2:cpu:/bg_non_interactive
San Mehat503df202010-03-02 17:09:56 -0800167 * 1:cpuacct:/
San Mehatc0dfca72009-10-27 11:52:55 -0700168 *
169 * We return the part after the "/", which will be an empty string for
170 * the default cgroup. If the string is longer than "bufLen", the string
171 * will be truncated.
172 */
173static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
174{
175#ifdef HAVE_ANDROID_OS
176 char pathBuf[32];
San Mehat503df202010-03-02 17:09:56 -0800177 char lineBuf[256];
178 FILE *fp;
San Mehatc0dfca72009-10-27 11:52:55 -0700179
180 snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
San Mehat503df202010-03-02 17:09:56 -0800181 if (!(fp = fopen(pathBuf, "r"))) {
San Mehatc0dfca72009-10-27 11:52:55 -0700182 return -1;
183 }
184
San Mehat503df202010-03-02 17:09:56 -0800185 while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
186 char *next = lineBuf;
187 char *subsys;
188 char *grp;
189 size_t len;
San Mehatc0dfca72009-10-27 11:52:55 -0700190
San Mehat503df202010-03-02 17:09:56 -0800191 /* Junk the first field */
192 if (!strsep(&next, ":")) {
193 goto out_bad_data;
194 }
San Mehatc0dfca72009-10-27 11:52:55 -0700195
San Mehat503df202010-03-02 17:09:56 -0800196 if (!(subsys = strsep(&next, ":"))) {
197 goto out_bad_data;
198 }
199
200 if (strcmp(subsys, "cpu")) {
201 /* Not the subsys we're looking for */
202 continue;
203 }
204
205 if (!(grp = strsep(&next, ":"))) {
206 goto out_bad_data;
207 }
208 grp++; /* Drop the leading '/' */
209 len = strlen(grp);
210 grp[len-1] = '\0'; /* Drop the trailing '\n' */
211
212 if (bufLen <= len) {
213 len = bufLen - 1;
214 }
215 strncpy(buf, grp, len);
216 buf[len] = '\0';
217 fclose(fp);
218 return 0;
San Mehatc0dfca72009-10-27 11:52:55 -0700219 }
220
San Mehat7e8529a2010-03-25 09:31:42 -0700221 SLOGE("Failed to find cpu subsys");
San Mehat503df202010-03-02 17:09:56 -0800222 fclose(fp);
223 return -1;
224 out_bad_data:
San Mehat7e8529a2010-03-25 09:31:42 -0700225 SLOGE("Bad cgroup data {%s}", lineBuf);
San Mehat503df202010-03-02 17:09:56 -0800226 fclose(fp);
227 return -1;
San Mehatc0dfca72009-10-27 11:52:55 -0700228#else
229 errno = ENOSYS;
230 return -1;
231#endif
232}
233
234int get_sched_policy(int tid, SchedPolicy *policy)
235{
Glenn Kasten69bfb1f2012-03-16 09:43:19 -0700236#ifdef HAVE_GETTID
237 if (tid == 0) {
238 tid = gettid();
239 }
240#endif
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700241 pthread_once(&the_once, __initialize);
San Mehatc0dfca72009-10-27 11:52:55 -0700242
243 if (__sys_supports_schedgroups) {
244 char grpBuf[32];
245 if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
246 return -1;
247 if (grpBuf[0] == '\0') {
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700248 *policy = SP_SYSTEM;
San Mehatc0dfca72009-10-27 11:52:55 -0700249 } else if (!strcmp(grpBuf, "bg_non_interactive")) {
250 *policy = SP_BACKGROUND;
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700251 } else if (!strcmp(grpBuf, "foreground")) {
252 *policy = SP_FOREGROUND;
253 } else if (!strcmp(grpBuf, "audio_app")) {
254 *policy = SP_AUDIO_APP;
255 } else if (!strcmp(grpBuf, "audio_sys")) {
256 *policy = SP_AUDIO_SYS;
San Mehatc0dfca72009-10-27 11:52:55 -0700257 } else {
258 errno = ERANGE;
259 return -1;
260 }
261 } else {
262 int rc = sched_getscheduler(tid);
263 if (rc < 0)
264 return -1;
265 else if (rc == SCHED_NORMAL)
266 *policy = SP_FOREGROUND;
267 else if (rc == SCHED_BATCH)
268 *policy = SP_BACKGROUND;
269 else {
270 errno = ERANGE;
271 return -1;
272 }
273 }
274 return 0;
275}
276
Glenn Kasten69bfb1f2012-03-16 09:43:19 -0700277/* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
278 * Call this any place a SchedPolicy is used as an input parameter.
279 * Returns the possibly re-mapped policy.
280 */
281static inline SchedPolicy _policy(SchedPolicy p)
282{
283 return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
284}
285
San Mehatc0dfca72009-10-27 11:52:55 -0700286int set_sched_policy(int tid, SchedPolicy policy)
287{
Glenn Kasten69bfb1f2012-03-16 09:43:19 -0700288#ifdef HAVE_GETTID
289 if (tid == 0) {
290 tid = gettid();
291 }
292#endif
293 policy = _policy(policy);
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700294 pthread_once(&the_once, __initialize);
San Mehat493dad92009-09-12 10:06:57 -0700295
San Mehatd2e4e462009-10-29 11:48:00 -0700296#if POLICY_DEBUG
297 char statfile[64];
298 char statline[1024];
299 char thread_name[255];
300 int fd;
301
302 sprintf(statfile, "/proc/%d/stat", tid);
303 memset(thread_name, 0, sizeof(thread_name));
304
305 fd = open(statfile, O_RDONLY);
306 if (fd >= 0) {
307 int rc = read(fd, statline, 1023);
308 close(fd);
309 statline[rc] = 0;
310 char *p = statline;
311 char *q;
312
313 for (p = statline; *p != '('; p++);
314 p++;
315 for (q = p; *q != ')'; q++);
316
317 strncpy(thread_name, p, (q-p));
318 }
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700319 switch (policy) {
320 case SP_BACKGROUND:
San Mehat7e8529a2010-03-25 09:31:42 -0700321 SLOGD("vvv tid %d (%s)", tid, thread_name);
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700322 break;
323 case SP_FOREGROUND:
San Mehat7e8529a2010-03-25 09:31:42 -0700324 SLOGD("^^^ tid %d (%s)", tid, thread_name);
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700325 break;
326 case SP_SYSTEM:
327 SLOGD("/// tid %d (%s)", tid, thread_name);
328 break;
329 case SP_AUDIO_APP:
330 SLOGD("aaa tid %d (%s)", tid, thread_name);
331 break;
332 case SP_AUDIO_SYS:
333 SLOGD("sss tid %d (%s)", tid, thread_name);
334 break;
335 default:
San Mehat7e8529a2010-03-25 09:31:42 -0700336 SLOGD("??? tid %d (%s)", tid, thread_name);
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700337 break;
San Mehatd2e4e462009-10-29 11:48:00 -0700338 }
339#endif
340
San Mehat493dad92009-09-12 10:06:57 -0700341 if (__sys_supports_schedgroups) {
Brad Fitzpatricke43c2482010-05-07 12:06:05 -0700342 if (add_tid_to_cgroup(tid, policy)) {
San Mehat493dad92009-09-12 10:06:57 -0700343 if (errno != ESRCH && errno != ENOENT)
344 return -errno;
345 }
346 } else {
347 struct sched_param param;
348
349 param.sched_priority = 0;
350 sched_setscheduler(tid,
351 (policy == SP_BACKGROUND) ?
352 SCHED_BATCH : SCHED_NORMAL,
353 &param);
354 }
355
356 return 0;
357}
Raphael0384a982009-09-15 17:10:17 -0700358
Glenn Kasten86c7cc82012-03-05 16:14:39 -0800359const char *get_sched_policy_name(SchedPolicy policy)
360{
Glenn Kasten69bfb1f2012-03-16 09:43:19 -0700361 policy = _policy(policy);
Glenn Kasten86c7cc82012-03-05 16:14:39 -0800362 static const char * const strings[SP_CNT] = {
363 [SP_BACKGROUND] = "bg",
364 [SP_FOREGROUND] = "fg",
Glenn Kasten10ec3c72012-04-19 15:25:58 -0700365 [SP_SYSTEM] = " ",
366 [SP_AUDIO_APP] = "aa",
367 [SP_AUDIO_SYS] = "as",
Glenn Kasten86c7cc82012-03-05 16:14:39 -0800368 };
369 if ((policy < SP_CNT) && (strings[policy] != NULL))
370 return strings[policy];
371 else
372 return "error";
373}
374
Brad Fitzpatrick86b12152010-05-08 11:51:13 -0700375#endif /* HAVE_PTHREADS */
Raphael0384a982009-09-15 17:10:17 -0700376#endif /* HAVE_SCHED_H */