sched_policy.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. /* libs/cutils/sched_policy.c
  2. **
  3. ** Copyright 2007, The Android Open Source Project
  4. **
  5. ** Licensed under the Apache License, Version 2.0 (the "License");
  6. ** you may not use this file except in compliance with the License.
  7. ** You may obtain a copy of the License at
  8. **
  9. ** http://www.apache.org/licenses/LICENSE-2.0
  10. **
  11. ** Unless required by applicable law or agreed to in writing, software
  12. ** distributed under the License is distributed on an "AS IS" BASIS,
  13. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ** See the License for the specific language governing permissions and
  15. ** limitations under the License.
  16. */
  17. #define LOG_TAG "SchedPolicy"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <string.h>
  22. #include <errno.h>
  23. #include <fcntl.h>
  24. #include <cutils/sched_policy.h>
  25. #include <cutils/log.h>
  26. /* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged.
  27. * Call this any place a SchedPolicy is used as an input parameter.
  28. * Returns the possibly re-mapped policy.
  29. */
  30. static inline SchedPolicy _policy(SchedPolicy p)
  31. {
  32. return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p;
  33. }
  34. #if defined(HAVE_ANDROID_OS) && defined(HAVE_SCHED_H) && defined(HAVE_PTHREADS)
  35. #include <sched.h>
  36. #include <pthread.h>
  37. #ifndef SCHED_NORMAL
  38. #define SCHED_NORMAL 0
  39. #endif
  40. #ifndef SCHED_BATCH
  41. #define SCHED_BATCH 3
  42. #endif
  43. #define POLICY_DEBUG 0
  44. #define CAN_SET_SP_SYSTEM 0 // non-zero means to implement set_sched_policy(tid, SP_SYSTEM)
  45. static pthread_once_t the_once = PTHREAD_ONCE_INIT;
  46. static int __sys_supports_schedgroups = -1;
  47. // File descriptors open to /dev/cpuctl/../tasks, setup by initialize, or -1 on error.
  48. static int bg_cgroup_fd = -1;
  49. static int fg_cgroup_fd = -1;
  50. #if CAN_SET_SP_SYSTEM
  51. static int system_cgroup_fd = -1;
  52. #endif
  53. /* Add tid to the scheduling group defined by the policy */
  54. static int add_tid_to_cgroup(int tid, SchedPolicy policy)
  55. {
  56. int fd;
  57. switch (policy) {
  58. case SP_BACKGROUND:
  59. fd = bg_cgroup_fd;
  60. break;
  61. case SP_FOREGROUND:
  62. case SP_AUDIO_APP:
  63. case SP_AUDIO_SYS:
  64. fd = fg_cgroup_fd;
  65. break;
  66. #if CAN_SET_SP_SYSTEM
  67. case SP_SYSTEM:
  68. fd = system_cgroup_fd;
  69. break;
  70. #endif
  71. default:
  72. fd = -1;
  73. break;
  74. }
  75. if (fd < 0) {
  76. SLOGE("add_tid_to_cgroup failed; policy=%d\n", policy);
  77. return -1;
  78. }
  79. // specialized itoa -- works for tid > 0
  80. char text[22];
  81. char *end = text + sizeof(text) - 1;
  82. char *ptr = end;
  83. *ptr = '\0';
  84. while (tid > 0) {
  85. *--ptr = '0' + (tid % 10);
  86. tid = tid / 10;
  87. }
  88. if (write(fd, ptr, end - ptr) < 0) {
  89. /*
  90. * If the thread is in the process of exiting,
  91. * don't flag an error
  92. */
  93. if (errno == ESRCH)
  94. return 0;
  95. SLOGW("add_tid_to_cgroup failed to write '%s' (%s); policy=%d\n",
  96. ptr, strerror(errno), policy);
  97. return -1;
  98. }
  99. return 0;
  100. }
  101. static void __initialize(void) {
  102. char* filename;
  103. if (!access("/dev/cpuctl/tasks", F_OK)) {
  104. __sys_supports_schedgroups = 1;
  105. #if CAN_SET_SP_SYSTEM
  106. filename = "/dev/cpuctl/tasks";
  107. system_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
  108. if (system_cgroup_fd < 0) {
  109. SLOGV("open of %s failed: %s\n", filename, strerror(errno));
  110. }
  111. #endif
  112. filename = "/dev/cpuctl/apps/tasks";
  113. fg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
  114. if (fg_cgroup_fd < 0) {
  115. SLOGE("open of %s failed: %s\n", filename, strerror(errno));
  116. }
  117. filename = "/dev/cpuctl/apps/bg_non_interactive/tasks";
  118. bg_cgroup_fd = open(filename, O_WRONLY | O_CLOEXEC);
  119. if (bg_cgroup_fd < 0) {
  120. SLOGE("open of %s failed: %s\n", filename, strerror(errno));
  121. }
  122. } else {
  123. __sys_supports_schedgroups = 0;
  124. }
  125. }
  126. /*
  127. * Try to get the scheduler group.
  128. *
  129. * The data from /proc/<pid>/cgroup looks (something) like:
  130. * 2:cpu:/bg_non_interactive
  131. * 1:cpuacct:/
  132. *
  133. * We return the part after the "/", which will be an empty string for
  134. * the default cgroup. If the string is longer than "bufLen", the string
  135. * will be truncated.
  136. */
  137. static int getSchedulerGroup(int tid, char* buf, size_t bufLen)
  138. {
  139. #ifdef HAVE_ANDROID_OS
  140. char pathBuf[32];
  141. char lineBuf[256];
  142. FILE *fp;
  143. snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid);
  144. if (!(fp = fopen(pathBuf, "r"))) {
  145. return -1;
  146. }
  147. while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) {
  148. char *next = lineBuf;
  149. char *subsys;
  150. char *grp;
  151. size_t len;
  152. /* Junk the first field */
  153. if (!strsep(&next, ":")) {
  154. goto out_bad_data;
  155. }
  156. if (!(subsys = strsep(&next, ":"))) {
  157. goto out_bad_data;
  158. }
  159. if (strcmp(subsys, "cpu")) {
  160. /* Not the subsys we're looking for */
  161. continue;
  162. }
  163. if (!(grp = strsep(&next, ":"))) {
  164. goto out_bad_data;
  165. }
  166. grp++; /* Drop the leading '/' */
  167. len = strlen(grp);
  168. grp[len-1] = '\0'; /* Drop the trailing '\n' */
  169. if (bufLen <= len) {
  170. len = bufLen - 1;
  171. }
  172. strncpy(buf, grp, len);
  173. buf[len] = '\0';
  174. fclose(fp);
  175. return 0;
  176. }
  177. SLOGE("Failed to find cpu subsys");
  178. fclose(fp);
  179. return -1;
  180. out_bad_data:
  181. SLOGE("Bad cgroup data {%s}", lineBuf);
  182. fclose(fp);
  183. return -1;
  184. #else
  185. errno = ENOSYS;
  186. return -1;
  187. #endif
  188. }
  189. int get_sched_policy(int tid, SchedPolicy *policy)
  190. {
  191. #ifdef HAVE_GETTID
  192. if (tid == 0) {
  193. tid = gettid();
  194. }
  195. #endif
  196. pthread_once(&the_once, __initialize);
  197. if (__sys_supports_schedgroups) {
  198. char grpBuf[32];
  199. if (getSchedulerGroup(tid, grpBuf, sizeof(grpBuf)) < 0)
  200. return -1;
  201. if (grpBuf[0] == '\0') {
  202. *policy = SP_SYSTEM;
  203. } else if (!strcmp(grpBuf, "apps/bg_non_interactive")) {
  204. *policy = SP_BACKGROUND;
  205. } else if (!strcmp(grpBuf, "apps")) {
  206. *policy = SP_FOREGROUND;
  207. } else {
  208. errno = ERANGE;
  209. return -1;
  210. }
  211. } else {
  212. int rc = sched_getscheduler(tid);
  213. if (rc < 0)
  214. return -1;
  215. else if (rc == SCHED_NORMAL)
  216. *policy = SP_FOREGROUND;
  217. else if (rc == SCHED_BATCH)
  218. *policy = SP_BACKGROUND;
  219. else {
  220. errno = ERANGE;
  221. return -1;
  222. }
  223. }
  224. return 0;
  225. }
  226. int set_sched_policy(int tid, SchedPolicy policy)
  227. {
  228. #ifdef HAVE_GETTID
  229. if (tid == 0) {
  230. tid = gettid();
  231. }
  232. #endif
  233. policy = _policy(policy);
  234. pthread_once(&the_once, __initialize);
  235. #if POLICY_DEBUG
  236. char statfile[64];
  237. char statline[1024];
  238. char thread_name[255];
  239. int fd;
  240. sprintf(statfile, "/proc/%d/stat", tid);
  241. memset(thread_name, 0, sizeof(thread_name));
  242. fd = open(statfile, O_RDONLY);
  243. if (fd >= 0) {
  244. int rc = read(fd, statline, 1023);
  245. close(fd);
  246. statline[rc] = 0;
  247. char *p = statline;
  248. char *q;
  249. for (p = statline; *p != '('; p++);
  250. p++;
  251. for (q = p; *q != ')'; q++);
  252. strncpy(thread_name, p, (q-p));
  253. }
  254. switch (policy) {
  255. case SP_BACKGROUND:
  256. SLOGD("vvv tid %d (%s)", tid, thread_name);
  257. break;
  258. case SP_FOREGROUND:
  259. case SP_AUDIO_APP:
  260. case SP_AUDIO_SYS:
  261. SLOGD("^^^ tid %d (%s)", tid, thread_name);
  262. break;
  263. case SP_SYSTEM:
  264. SLOGD("/// tid %d (%s)", tid, thread_name);
  265. break;
  266. default:
  267. SLOGD("??? tid %d (%s)", tid, thread_name);
  268. break;
  269. }
  270. #endif
  271. if (__sys_supports_schedgroups) {
  272. if (add_tid_to_cgroup(tid, policy)) {
  273. if (errno != ESRCH && errno != ENOENT)
  274. return -errno;
  275. }
  276. } else {
  277. struct sched_param param;
  278. param.sched_priority = 0;
  279. sched_setscheduler(tid,
  280. (policy == SP_BACKGROUND) ?
  281. SCHED_BATCH : SCHED_NORMAL,
  282. &param);
  283. }
  284. return 0;
  285. }
  286. #else
  287. /* Stubs for non-Android targets. */
  288. int set_sched_policy(int tid, SchedPolicy policy)
  289. {
  290. return 0;
  291. }
  292. int get_sched_policy(int tid, SchedPolicy *policy)
  293. {
  294. *policy = SP_SYSTEM_DEFAULT;
  295. return 0;
  296. }
  297. #endif
  298. const char *get_sched_policy_name(SchedPolicy policy)
  299. {
  300. policy = _policy(policy);
  301. static const char * const strings[SP_CNT] = {
  302. [SP_BACKGROUND] = "bg",
  303. [SP_FOREGROUND] = "fg",
  304. [SP_SYSTEM] = " ",
  305. [SP_AUDIO_APP] = "aa",
  306. [SP_AUDIO_SYS] = "as",
  307. };
  308. if ((policy < SP_CNT) && (strings[policy] != NULL))
  309. return strings[policy];
  310. else
  311. return "error";
  312. }