uclampset.c 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /* uclampset.c - The quota version of "nice".
  2. *
  3. * Copyright 2021 The Android Open Source Project
  4. *
  5. * See https://man7.org/linux/man-pages/man1/uclampset.1.html
  6. USE_UCLAMPSET(NEWTOY(uclampset, "p#am#<-1>1024M#<-1>1024R", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
  7. config UCLAMPSET
  8. bool "uclampset"
  9. default y
  10. help
  11. usage: uclampset [-m MIN] [-M MAX] {-p PID | COMMAND...}
  12. Set or query process utilization limits ranging from 0 to 1024, or -1 to
  13. reset to system default. With no arguments, prints current values.
  14. -m MIN Reserve at least this much CPU utilization for task
  15. -M MAX Limit task to at most this much CPU utilization
  16. -p PID Apply to PID rather than new COMMAND
  17. -R Reset child processes to default values on fork
  18. -a Apply to all threads for the given PID
  19. */
  20. #define FOR_uclampset
  21. #include "toys.h"
  22. GLOBALS(
  23. long M, m, p;
  24. )
  25. // Added to 5.3 kernel (commit a509a7cd7974): too new to rely on headers
  26. #ifndef SCHED_FLAG_RESET_ON_FORK
  27. #define SCHED_FLAG_RESET_ON_FORK 0x01
  28. #define SCHED_FLAG_KEEP_POLICY 0x08
  29. #define SCHED_FLAG_KEEP_PARAMS 0x10
  30. #define SCHED_FLAG_UTIL_CLAMP_MIN 0x20
  31. #define SCHED_FLAG_UTIL_CLAMP_MAX 0x40
  32. #endif
  33. static void do_uclampset(pid_t pid)
  34. {
  35. unsigned *sa = (void *)toybuf; // sa[12] is min, sa[13] is max
  36. char *comm, buf[32];
  37. if (FLAG(R)|FLAG(m)|FLAG(M)) {
  38. if (syscall(__NR_sched_setattr, pid, sa, 0))
  39. perror_exit("sched_setattr for pid %d", pid);
  40. } else {
  41. sprintf(buf, "/proc/%u/comm", pid);
  42. comm = chomp(xreadfile(buf, 0, 0));
  43. if (syscall(__NR_sched_getattr, pid, sa, *sa, 0))
  44. perror_exit("sched_getattr for pid %d", pid);
  45. printf("%s (%d) util_clamp: min: %u max: %u\n", comm, pid, sa[12], sa[13]);
  46. free(comm);
  47. }
  48. }
  49. static int task_callback(struct dirtree *new)
  50. {
  51. if (!new->parent) return DIRTREE_RECURSE;
  52. if (isdigit(*new->name)) do_uclampset(atoi(new->name));
  53. return 0;
  54. }
  55. void uclampset_main(void)
  56. {
  57. unsigned *sa = (void *)toybuf;
  58. long long *flags = (void *)(sa+2);
  59. char buf[32];
  60. sa[0] = 14*4; // size
  61. sa[12] = TT.m;
  62. sa[13] = TT.M;
  63. *flags = SCHED_FLAG_KEEP_POLICY | SCHED_FLAG_KEEP_PARAMS;
  64. if (FLAG(R)) *flags |= SCHED_FLAG_RESET_ON_FORK;
  65. if (FLAG(m)) *flags |= SCHED_FLAG_UTIL_CLAMP_MIN;
  66. if (FLAG(M)) *flags |= SCHED_FLAG_UTIL_CLAMP_MAX;
  67. if (!FLAG(p)) {
  68. if (toys.optc < 1) error_exit("Need -p PID or CMD [ARG...]");
  69. do_uclampset(getpid());
  70. xexec(toys.optargs);
  71. } else if (FLAG(a)) {
  72. sprintf(buf, "/proc/%lu/task", TT.p);
  73. dirtree_read(buf, task_callback);
  74. } else do_uclampset(TT.p);
  75. }