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