android13/external/toybox/toys/other/uclampset.c

90 lines
2.5 KiB
C

/* uclampset.c - The quota version of "nice".
*
* Copyright 2021 The Android Open Source Project
*
* See https://man7.org/linux/man-pages/man1/uclampset.1.html
USE_UCLAMPSET(NEWTOY(uclampset, "p#am#<-1>1024M#<-1>1024R", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
config UCLAMPSET
bool "uclampset"
default y
help
usage: uclampset [-m MIN] [-M MAX] {-p PID | COMMAND...}
Set or query process utilization limits ranging from 0 to 1024, or -1 to
reset to system default. With no arguments, prints current values.
-m MIN Reserve at least this much CPU utilization for task
-M MAX Limit task to at most this much CPU utilization
-p PID Apply to PID rather than new COMMAND
-R Reset child processes to default values on fork
-a Apply to all threads for the given PID
*/
#define FOR_uclampset
#include "toys.h"
GLOBALS(
long M, m, p;
)
// Added to 5.3 kernel (commit a509a7cd7974): too new to rely on headers
#ifndef SCHED_FLAG_RESET_ON_FORK
#define SCHED_FLAG_RESET_ON_FORK 0x01
#define SCHED_FLAG_KEEP_POLICY 0x08
#define SCHED_FLAG_KEEP_PARAMS 0x10
#define SCHED_FLAG_UTIL_CLAMP_MIN 0x20
#define SCHED_FLAG_UTIL_CLAMP_MAX 0x40
#endif
static void do_uclampset(pid_t pid)
{
unsigned *sa = (void *)toybuf; // sa[12] is min, sa[13] is max
char *comm, buf[32];
if (FLAG(R)|FLAG(m)|FLAG(M)) {
if (syscall(__NR_sched_setattr, pid, sa, 0))
perror_exit("sched_setattr for pid %d", pid);
} else {
sprintf(buf, "/proc/%u/comm", pid);
comm = chomp(xreadfile(buf, 0, 0));
if (syscall(__NR_sched_getattr, pid, sa, *sa, 0))
perror_exit("sched_getattr for pid %d", pid);
printf("%s (%d) util_clamp: min: %u max: %u\n", comm, pid, sa[12], sa[13]);
free(comm);
}
}
static int task_callback(struct dirtree *new)
{
if (!new->parent) return DIRTREE_RECURSE;
if (isdigit(*new->name)) do_uclampset(atoi(new->name));
return 0;
}
void uclampset_main(void)
{
unsigned *sa = (void *)toybuf;
long long *flags = (void *)(sa+2);
char buf[32];
sa[0] = 14*4; // size
sa[12] = TT.m;
sa[13] = TT.M;
*flags = SCHED_FLAG_KEEP_POLICY | SCHED_FLAG_KEEP_PARAMS;
if (FLAG(R)) *flags |= SCHED_FLAG_RESET_ON_FORK;
if (FLAG(m)) *flags |= SCHED_FLAG_UTIL_CLAMP_MIN;
if (FLAG(M)) *flags |= SCHED_FLAG_UTIL_CLAMP_MAX;
if (!FLAG(p)) {
if (toys.optc < 1) error_exit("Need -p PID or CMD [ARG...]");
do_uclampset(getpid());
xexec(toys.optargs);
} else if (FLAG(a)) {
sprintf(buf, "/proc/%lu/task", TT.p);
dirtree_read(buf, task_callback);
} else do_uclampset(TT.p);
}