Merge branch 'uclampset-v3' of https://github.com/qais-yousef/util-linux
* 'uclampset-v3' of https://github.com/qais-yousef/util-linux: uclampset: Plumb in bash-completion uclampset: Plump into the build system uclampset: Add man page Add uclampset schedutil Move sched_attr struct and syscall definitions into header file
This commit is contained in:
commit
9a823f1536
|
@ -180,3 +180,4 @@ ylwrap
|
|||
/wipefs
|
||||
/write
|
||||
/zramctl
|
||||
/uclampset
|
||||
|
|
|
@ -210,6 +210,9 @@ endif
|
|||
if BUILD_CHRT
|
||||
dist_bashcompletion_DATA += bash-completion/chrt
|
||||
endif
|
||||
if BUILD_UCLAMPSET
|
||||
dist_bashcompletion_DATA += bash-completion/uclampset
|
||||
endif
|
||||
if BUILD_IONICE
|
||||
dist_bashcompletion_DATA += bash-completion/ionice
|
||||
endif
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
_uclampset_module()
|
||||
{
|
||||
local cur prev OPTS
|
||||
COMPREPLY=()
|
||||
cur="${COMP_WORDS[COMP_CWORD]}"
|
||||
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
||||
case $prev in
|
||||
'-h'|'--help'|'-V'|'--version')
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
case $cur in
|
||||
-*)
|
||||
OPTS="
|
||||
--all-tasks
|
||||
--help
|
||||
--pid
|
||||
--system
|
||||
--reset-on-fork
|
||||
--verbose
|
||||
--version
|
||||
"
|
||||
COMPREPLY=( $(compgen -W "${OPTS[*]}" -- $cur) )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
local i
|
||||
for i in ${COMP_WORDS[*]}; do
|
||||
case $i in
|
||||
'-p'|'--pid')
|
||||
COMPREPLY=( $(compgen -W "$(cd /proc && echo [0-9]*)" -- $cur) )
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
COMPREPLY=( $(compgen -c -- $cur) )
|
||||
return 0
|
||||
}
|
||||
complete -F _uclampset_module uclampset
|
|
@ -2194,6 +2194,15 @@ AS_IF([test "x$build_chrt" = xyes], [
|
|||
UL_CHECK_SYSCALL([sched_setattr])
|
||||
])
|
||||
|
||||
UL_ENABLE_ALIAS([uclampset], [schedutils])
|
||||
UL_BUILD_INIT([uclampset])
|
||||
UL_REQUIRES_HAVE([uclampset], [schedsetter], [sched_set functions])
|
||||
AM_CONDITIONAL([BUILD_UCLAMPSET], [test "x$build_uclampset" = xyes])
|
||||
|
||||
AS_IF([test "x$build_uclampset" = xyes], [
|
||||
UL_CHECK_SYSCALL([sched_setattr])
|
||||
])
|
||||
|
||||
|
||||
AC_ARG_ENABLE([wall],
|
||||
AS_HELP_STRING([--disable-wall], [do not build wall]),
|
||||
|
|
|
@ -207,4 +207,8 @@
|
|||
#define _PATH_DEV_RFKILL "/dev/rfkill"
|
||||
#define _PATH_SYS_RFKILL "/sys/class/rfkill"
|
||||
|
||||
#define _PATH_PROC_KERNEL(file) "/proc/sys/kernel" #file
|
||||
#define _PATH_PROC_UCLAMP_MIN _PATH_PROC_KERNEL(/sched_util_clamp_min)
|
||||
#define _PATH_PROC_UCLAMP_MAX _PATH_PROC_KERNEL(/sched_util_clamp_max)
|
||||
|
||||
#endif /* PATHNAMES_H */
|
||||
|
|
|
@ -18,3 +18,10 @@ dist_man_MANS += schedutils/taskset.1
|
|||
taskset_SOURCES = schedutils/taskset.c
|
||||
taskset_LDADD = $(LDADD) libcommon.la
|
||||
endif
|
||||
|
||||
if BUILD_UCLAMPSET
|
||||
usrbin_exec_PROGRAMS += uclampset
|
||||
dist_man_MANS += schedutils/uclampset.1
|
||||
uclampset_SOURCES = schedutils/uclampset.c
|
||||
uclampset_LDADD = $(LDADD) libcommon.la
|
||||
endif
|
||||
|
|
|
@ -34,83 +34,8 @@
|
|||
#include "closestream.h"
|
||||
#include "strutils.h"
|
||||
#include "procutils.h"
|
||||
#include "sched_attr.h"
|
||||
|
||||
/* the SCHED_BATCH is supported since Linux 2.6.16
|
||||
* -- temporary workaround for people with old glibc headers
|
||||
*/
|
||||
#if defined (__linux__) && !defined(SCHED_BATCH)
|
||||
# define SCHED_BATCH 3
|
||||
#endif
|
||||
|
||||
/* the SCHED_IDLE is supported since Linux 2.6.23
|
||||
* commit id 0e6aca43e08a62a48d6770e9a159dbec167bf4c6
|
||||
* -- temporary workaround for people with old glibc headers
|
||||
*/
|
||||
#if defined (__linux__) && !defined(SCHED_IDLE)
|
||||
# define SCHED_IDLE 5
|
||||
#endif
|
||||
|
||||
/* flag by sched_getscheduler() */
|
||||
#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
|
||||
# define SCHED_RESET_ON_FORK 0x40000000
|
||||
#endif
|
||||
|
||||
/* flag by sched_getattr() */
|
||||
#if defined(__linux__) && !defined(SCHED_FLAG_RESET_ON_FORK)
|
||||
# define SCHED_FLAG_RESET_ON_FORK 0x01
|
||||
#endif
|
||||
|
||||
#if defined (__linux__)
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
/* usable kernel-headers, but old glibc-headers */
|
||||
#if defined (__linux__) && !defined(SYS_sched_setattr) && defined(__NR_sched_setattr)
|
||||
# define SYS_sched_setattr __NR_sched_setattr
|
||||
#endif
|
||||
|
||||
#if defined (__linux__) && !defined(SYS_sched_getattr) && defined(__NR_sched_getattr)
|
||||
# define SYS_sched_getattr __NR_sched_getattr
|
||||
#endif
|
||||
|
||||
#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR) && defined(SYS_sched_setattr)
|
||||
# define HAVE_SCHED_SETATTR
|
||||
|
||||
struct sched_attr {
|
||||
uint32_t size;
|
||||
uint32_t sched_policy;
|
||||
uint64_t sched_flags;
|
||||
|
||||
/* SCHED_NORMAL, SCHED_BATCH */
|
||||
int32_t sched_nice;
|
||||
|
||||
/* SCHED_FIFO, SCHED_RR */
|
||||
uint32_t sched_priority;
|
||||
|
||||
/* SCHED_DEADLINE (nsec) */
|
||||
uint64_t sched_runtime;
|
||||
uint64_t sched_deadline;
|
||||
uint64_t sched_period;
|
||||
};
|
||||
|
||||
static int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
|
||||
{
|
||||
return syscall(SYS_sched_setattr, pid, attr, flags);
|
||||
}
|
||||
|
||||
static int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags)
|
||||
{
|
||||
return syscall(SYS_sched_getattr, pid, attr, size, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* the SCHED_DEADLINE is supported since Linux 3.14
|
||||
* commit id aab03e05e8f7e26f51dee792beddcb5cca9215a5
|
||||
* -- sched_setattr() is required for this policy!
|
||||
*/
|
||||
#if defined (__linux__) && !defined(SCHED_DEADLINE) && defined(HAVE_SCHED_SETATTR)
|
||||
# define SCHED_DEADLINE 6
|
||||
#endif
|
||||
|
||||
/* control struct */
|
||||
struct chrt_ctl {
|
||||
|
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2004 Robert Love
|
||||
* Copyright (C) 2020-2021 Qais Yousef
|
||||
* Copyright (C) 2020-2021 Arm Ltd
|
||||
*/
|
||||
#ifndef UTIL_LINUX_SCHED_ATTR_H
|
||||
#define UTIL_LINUX_SCHED_ATTR_H
|
||||
|
||||
/* the SCHED_BATCH is supported since Linux 2.6.16
|
||||
* -- temporary workaround for people with old glibc headers
|
||||
*/
|
||||
#if defined (__linux__) && !defined(SCHED_BATCH)
|
||||
# define SCHED_BATCH 3
|
||||
#endif
|
||||
|
||||
/* the SCHED_IDLE is supported since Linux 2.6.23
|
||||
* commit id 0e6aca43e08a62a48d6770e9a159dbec167bf4c6
|
||||
* -- temporary workaround for people with old glibc headers
|
||||
*/
|
||||
#if defined (__linux__) && !defined(SCHED_IDLE)
|
||||
# define SCHED_IDLE 5
|
||||
#endif
|
||||
|
||||
/* flag by sched_getscheduler() */
|
||||
#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
|
||||
# define SCHED_RESET_ON_FORK 0x40000000
|
||||
#endif
|
||||
|
||||
/* flag by sched_getattr() */
|
||||
#if defined(__linux__) && !defined(SCHED_FLAG_RESET_ON_FORK)
|
||||
# define SCHED_FLAG_RESET_ON_FORK 0x01
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(SCHED_FLAG_RECLAIM)
|
||||
# define SCHED_FLAG_RECLAIM 0x02
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(SCHED_FLAG_DL_OVERRUN)
|
||||
# define SCHED_FLAG_DL_OVERRUN 0x04
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(SCHED_FLAG_KEEP_POLICY)
|
||||
# define SCHED_FLAG_KEEP_POLICY 0x08
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(SCHED_FLAG_KEEP_PARAMS)
|
||||
# define SCHED_FLAG_KEEP_PARAMS 0x10
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(SCHED_FLAG_UTIL_CLAMP_MIN)
|
||||
# define SCHED_FLAG_UTIL_CLAMP_MIN 0x20
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && !defined(SCHED_FLAG_UTIL_CLAMP_MAX)
|
||||
# define SCHED_FLAG_UTIL_CLAMP_MAX 0x40
|
||||
#endif
|
||||
|
||||
#if defined (__linux__)
|
||||
# include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
/* usable kernel-headers, but old glibc-headers */
|
||||
#if defined (__linux__) && !defined(SYS_sched_setattr) && defined(__NR_sched_setattr)
|
||||
# define SYS_sched_setattr __NR_sched_setattr
|
||||
#endif
|
||||
|
||||
#if defined (__linux__) && !defined(SYS_sched_getattr) && defined(__NR_sched_getattr)
|
||||
# define SYS_sched_getattr __NR_sched_getattr
|
||||
#endif
|
||||
|
||||
#if defined (__linux__) && !defined(HAVE_SCHED_SETATTR) && defined(SYS_sched_setattr)
|
||||
# define HAVE_SCHED_SETATTR
|
||||
|
||||
struct sched_attr {
|
||||
uint32_t size;
|
||||
uint32_t sched_policy;
|
||||
uint64_t sched_flags;
|
||||
|
||||
/* SCHED_NORMAL, SCHED_BATCH */
|
||||
int32_t sched_nice;
|
||||
|
||||
/* SCHED_FIFO, SCHED_RR */
|
||||
uint32_t sched_priority;
|
||||
|
||||
/* SCHED_DEADLINE (nsec) */
|
||||
uint64_t sched_runtime;
|
||||
uint64_t sched_deadline;
|
||||
uint64_t sched_period;
|
||||
|
||||
/* UTILIZATION CLAMPING */
|
||||
uint32_t sched_util_min;
|
||||
uint32_t sched_util_max;
|
||||
};
|
||||
|
||||
static int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags)
|
||||
{
|
||||
return syscall(SYS_sched_setattr, pid, attr, flags);
|
||||
}
|
||||
|
||||
static int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags)
|
||||
{
|
||||
return syscall(SYS_sched_getattr, pid, attr, size, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* the SCHED_DEADLINE is supported since Linux 3.14
|
||||
* commit id aab03e05e8f7e26f51dee792beddcb5cca9215a5
|
||||
* -- sched_setattr() is required for this policy!
|
||||
*/
|
||||
#if defined (__linux__) && !defined(SCHED_DEADLINE) && defined(HAVE_SCHED_SETATTR)
|
||||
# define SCHED_DEADLINE 6
|
||||
#endif
|
||||
|
||||
#endif /* UTIL_LINUX_SCHED_ATTR_H */
|
|
@ -0,0 +1,174 @@
|
|||
.\" uclampset(1) manpage
|
||||
.\"
|
||||
.\" Copyright (C) 2020-2021 Qais Yousef <qais.yousef@arm.com>
|
||||
.\" Copyright (C) 2020-2021 Arm Ltd
|
||||
.\"
|
||||
.\" This is free documentation; you can redistribute it and/or
|
||||
.\" modify it under the terms of the GNU General Public License,
|
||||
.\" version 2, as published by the Free Software Foundation.
|
||||
.\"
|
||||
.\" The GNU General Public License's references to "object code"
|
||||
.\" and "executables" are to be interpreted as the output of any
|
||||
.\" document formatting or typesetting system, including
|
||||
.\" intermediate and printed output.
|
||||
.\"
|
||||
.\" This manual is distributed in the hope that it will be useful,
|
||||
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
.\" GNU General Public License for more details.
|
||||
.\"
|
||||
.\" You should have received a copy of the GNU General Public License along
|
||||
.\" with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
.\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
.\"
|
||||
.TH UCLAMPSET 1 "August 2020" "util-linux" "User Commands"
|
||||
.SH NAME
|
||||
uclampset \- manipulate the utilization clamping attributes of the system or
|
||||
a process.
|
||||
.SH SYNOPSIS
|
||||
.B uclampset
|
||||
[options]
|
||||
.RI [ -m\ uclamp_min ]\ [ -M\ uclamp_max ]\ command\ [ argument ...]
|
||||
.br
|
||||
.B uclampset
|
||||
[options]
|
||||
.RI [ -m\ uclamp_min ]\ [ -M\ uclamp_max ]
|
||||
.B \-p
|
||||
.RI pid
|
||||
.SH DESCRIPTION
|
||||
.B uclampset
|
||||
sets or retrieves the utilization clamping attributes of an existing \fIpid\fR,
|
||||
or runs \fIcommand\fR with the given attributes.
|
||||
|
||||
Utilization clamping is a new feature added in v5.3. It gives a hint to the
|
||||
scheduler about the allowed range of utilization the task should be operating
|
||||
at.
|
||||
|
||||
The utilization of the task affects frequency selection and task placement.
|
||||
Only schedutil cpufreq governor understands handling util clamp hints at the
|
||||
time of writing. Consult your kernel docs for further info about other
|
||||
cpufreq governors support.
|
||||
|
||||
If you're running on asymmetric heterogeneous system like Arm's big.LITTLE.
|
||||
Utilization clamping can help bias task placement. If the task is boosted such
|
||||
that
|
||||
.B util_min
|
||||
value is higher than the little cores' capacity, then the scheduler will do its
|
||||
best to place it on a big core.
|
||||
|
||||
Similarly, if
|
||||
.B util_max
|
||||
is smaller than or equal the capacity of the little cores, then the scheduler
|
||||
can still choose to place it there even if the actual utilization of the task
|
||||
is at max.
|
||||
|
||||
Setting a task's
|
||||
.B uclamp_min
|
||||
to a none zero value will effectively boost the task as when it runs it'll
|
||||
always start from this utilization value.
|
||||
|
||||
By setting a task's
|
||||
.B uclamp_max
|
||||
below 1024, this will effectively cap the task as when it runs it'll never be
|
||||
able to go above this utilization value.
|
||||
|
||||
The full utilization range is: [0:1024].
|
||||
The special value -1 is used to reset to system's default.
|
||||
|
||||
.SH OPTIONS
|
||||
.TP
|
||||
.B \-m
|
||||
Set util_min value.
|
||||
.TP
|
||||
.B \-M
|
||||
Set util_max value.
|
||||
.TP
|
||||
.BR \-a ,\ \-\-all-tasks
|
||||
Set or retrieve the utilization clamping attributes of all the tasks (threads)
|
||||
for a given PID.
|
||||
.TP
|
||||
.BR \-p ,\ \-\-pid
|
||||
Operate on an existing PID and do not launch a new task.
|
||||
.TP
|
||||
.BR \-s ,\ \-\-system
|
||||
Set or retrieve the system-wide utilization clamping attributes.
|
||||
.TP
|
||||
.BR \-R ,\ \-\-reset-on-fork
|
||||
Set
|
||||
.B SCHED_FLAG_RESET_ON_FORK
|
||||
flag
|
||||
.TP
|
||||
.BR \-v ,\ \-\-verbose
|
||||
Show status information.
|
||||
.TP
|
||||
.BR \-V ,\ \-\-version
|
||||
Display version information and exit.
|
||||
.TP
|
||||
.BR \-h ,\ \-\-help
|
||||
Display help text and exit.
|
||||
.SH USAGE
|
||||
.TP
|
||||
The default behavior is to run a new command:
|
||||
.B uclampset
|
||||
.I [-m\ uclamp_min]
|
||||
.I [-M\ uclamp_max]
|
||||
.IR command\ [ arguments ]
|
||||
.TP
|
||||
You can also retrieve the utilization clamping attributes of an existing task:
|
||||
.B uclampset \-p
|
||||
.I pid
|
||||
.TP
|
||||
Or set them:
|
||||
.B uclampset \-p
|
||||
.I pid
|
||||
.I [-m\ uclamp_min]
|
||||
.I [-M\ uclamp_max]
|
||||
.TP
|
||||
Or control the system-wide attributes:
|
||||
.B uclampset \-s
|
||||
.I [-m\ uclamp_min]
|
||||
.I [-M\ uclamp_max]
|
||||
.SH PERMISSIONS
|
||||
A user must possess
|
||||
.B CAP_SYS_NICE
|
||||
to change the scheduling attributes of a process. Any user can retrieve the
|
||||
scheduling information.
|
||||
|
||||
.SH NOTES
|
||||
The system wide utilization clamp attributes are there to control the _allowed_
|
||||
range the tasks can use. By default both
|
||||
.B uclamp_min
|
||||
and
|
||||
.B uclamp_max
|
||||
are set to 1024. This means users can set the utilization clamp values for
|
||||
their task across the full range [0:1024].
|
||||
|
||||
.TP
|
||||
For example:
|
||||
.B uclampset \-s
|
||||
.I -m\ 512
|
||||
.I -M\ 700
|
||||
.PP
|
||||
will prevent any task from being boosted higher than 512. And all tasks in the
|
||||
systems are capped to a utilization of 700. Effectively rendering the maximum
|
||||
performance of the system to 700.
|
||||
|
||||
Consult your kernel docs for the exact expected behavior on that kernel.
|
||||
.SH AUTHORS
|
||||
.UR qais.yousef@arm.com
|
||||
Qais Yousef
|
||||
.UE
|
||||
.SH SEE ALSO
|
||||
.BR nice (1),
|
||||
.BR renice (1),
|
||||
.BR taskset (1),
|
||||
.BR sched (7)
|
||||
.sp
|
||||
See
|
||||
.BR sched_setscheduler (2)
|
||||
and
|
||||
.BR sched_setattr (2)
|
||||
for a description of the Linux scheduling scheme.
|
||||
.SH AVAILABILITY
|
||||
The uclampset command is part of the util-linux package and is available from
|
||||
https://www.kernel.org/pub/linux/utils/util-linux/.
|
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
* uclampset.c - change utilization clamping attributes of a task or the system
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License, version 2, as
|
||||
* published by the Free Software Foundation
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2020-2021 Qais Yousef
|
||||
* Copyright (C) 2020-2021 Arm Ltd
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include <sched.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "closestream.h"
|
||||
#include "path.h"
|
||||
#include "pathnames.h"
|
||||
#include "procutils.h"
|
||||
#include "sched_attr.h"
|
||||
#include "strutils.h"
|
||||
|
||||
#define NOT_SET -2U
|
||||
|
||||
struct uclampset {
|
||||
unsigned int util_min;
|
||||
unsigned int util_max;
|
||||
|
||||
pid_t pid;
|
||||
unsigned int all_tasks:1, /* all threads of the PID */
|
||||
system:1,
|
||||
util_min_set:1, /* indicates -m option was passed */
|
||||
util_max_set:1, /* indicates -M option was passed */
|
||||
reset_on_fork:1,
|
||||
verbose:1;
|
||||
char *cmd;
|
||||
};
|
||||
|
||||
static void __attribute__((__noreturn__)) usage(void)
|
||||
{
|
||||
FILE *out = stdout;
|
||||
|
||||
fprintf(out,
|
||||
_(" %1$s [options]\n"
|
||||
" %1$s [options] --pid <pid> | --system | <command> <arg>...\n"),
|
||||
program_invocation_short_name);
|
||||
|
||||
fputs(USAGE_SEPARATOR, out);
|
||||
fputs(_("Show or change the utilization clamping attributes of a process or the system.\n"), out);
|
||||
fputs(_("Utilization range: [0:1024]\n"), out);
|
||||
fputs(_("Use special -1 value to reset to system's default\n"), out);
|
||||
|
||||
fputs(USAGE_OPTIONS, out);
|
||||
fputs(_(" -m util_min value to set\n"), out);
|
||||
fputs(_(" -M util_max value to set\n"), out);
|
||||
fputs(_(" -a, --all-tasks operate on all the tasks (threads) for a given pid\n"), out);
|
||||
fputs(_(" -p, --pid operate on existing given pid\n"), out);
|
||||
fputs(_(" -s, --system operate on system\n"), out);
|
||||
fputs(_(" -R, --reset-on-fork set reset-on-fork flag\n"), out);
|
||||
fputs(_(" -v, --verbose display status information\n"), out);
|
||||
|
||||
fputs(USAGE_SEPARATOR, out);
|
||||
printf(USAGE_HELP_OPTIONS(22));
|
||||
|
||||
printf(USAGE_MAN_TAIL("uclampset(1)"));
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void show_uclamp_pid_info(pid_t pid, char *cmd)
|
||||
{
|
||||
struct sched_attr sa;
|
||||
char *comm;
|
||||
|
||||
/* don't display "pid 0" as that is confusing */
|
||||
if (!pid)
|
||||
pid = getpid();
|
||||
|
||||
if (sched_getattr(pid, &sa, sizeof(sa), 0) != 0)
|
||||
err(EXIT_FAILURE, _("failed to get pid %d's uclamp values"), pid);
|
||||
|
||||
if (cmd)
|
||||
comm = cmd;
|
||||
else
|
||||
comm = proc_get_command_name(pid);
|
||||
|
||||
printf(_("%s (%d) util_clamp: min: %d max: %d\n"),
|
||||
comm ? : "uknown", pid, sa.sched_util_min, sa.sched_util_max);
|
||||
|
||||
if (!cmd)
|
||||
free(comm);
|
||||
}
|
||||
|
||||
static unsigned int read_uclamp_sysfs(char *filename)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
if (ul_path_read_u32(NULL, &val, filename) != 0)
|
||||
err(EXIT_FAILURE, _("cannot read %s"), filename);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static void write_uclamp_sysfs(char *filename, unsigned int val)
|
||||
{
|
||||
if (ul_path_write_u64(NULL, val, filename) != 0)
|
||||
err(EXIT_FAILURE, _("cannot write %s"), filename);
|
||||
}
|
||||
|
||||
static void show_uclamp_system_info(void)
|
||||
{
|
||||
unsigned int min, max;
|
||||
|
||||
min = read_uclamp_sysfs(_PATH_PROC_UCLAMP_MIN);
|
||||
max = read_uclamp_sysfs(_PATH_PROC_UCLAMP_MAX);
|
||||
|
||||
printf(_("System util_clamp: min: %u max: %u\n"), min, max);
|
||||
}
|
||||
|
||||
static void show_uclamp_info(struct uclampset *ctl)
|
||||
{
|
||||
if (ctl->system) {
|
||||
show_uclamp_system_info();
|
||||
} else if (ctl->all_tasks) {
|
||||
pid_t tid;
|
||||
struct proc_tasks *ts = proc_open_tasks(ctl->pid);
|
||||
|
||||
if (!ts)
|
||||
err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
|
||||
|
||||
while (!proc_next_tid(ts, &tid))
|
||||
show_uclamp_pid_info(tid, NULL);
|
||||
|
||||
proc_close_tasks(ts);
|
||||
} else {
|
||||
show_uclamp_pid_info(ctl->pid, ctl->cmd);
|
||||
}
|
||||
}
|
||||
|
||||
static int set_uclamp_one(struct uclampset *ctl, pid_t pid)
|
||||
{
|
||||
struct sched_attr sa;
|
||||
|
||||
if (sched_getattr(pid, &sa, sizeof(sa), 0) != 0)
|
||||
err(EXIT_FAILURE, _("failed to get pid %d's uclamp values"), pid);
|
||||
|
||||
if (ctl->util_min_set)
|
||||
sa.sched_util_min = ctl->util_min;
|
||||
if (ctl->util_max_set)
|
||||
sa.sched_util_max = ctl->util_max;
|
||||
|
||||
sa.sched_flags = SCHED_FLAG_KEEP_POLICY |
|
||||
SCHED_FLAG_KEEP_PARAMS |
|
||||
SCHED_FLAG_UTIL_CLAMP_MIN |
|
||||
SCHED_FLAG_UTIL_CLAMP_MAX;
|
||||
|
||||
if (ctl->reset_on_fork)
|
||||
sa.sched_flags |= SCHED_FLAG_RESET_ON_FORK;
|
||||
|
||||
return sched_setattr(pid, &sa, 0);
|
||||
}
|
||||
|
||||
static void set_uclamp_pid(struct uclampset *ctl)
|
||||
{
|
||||
if (ctl->all_tasks) {
|
||||
pid_t tid;
|
||||
struct proc_tasks *ts = proc_open_tasks(ctl->pid);
|
||||
|
||||
if (!ts)
|
||||
err(EXIT_FAILURE, _("cannot obtain the list of tasks"));
|
||||
|
||||
while (!proc_next_tid(ts, &tid))
|
||||
if (set_uclamp_one(ctl, tid) == -1)
|
||||
err(EXIT_FAILURE, _("failed to set tid %d's uclamp values"), tid);
|
||||
|
||||
proc_close_tasks(ts);
|
||||
|
||||
} else if (set_uclamp_one(ctl, ctl->pid) == -1) {
|
||||
err(EXIT_FAILURE, _("failed to set pid %d's uclamp values"), ctl->pid);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_uclamp_system(struct uclampset *ctl)
|
||||
{
|
||||
if (!ctl->util_min_set)
|
||||
ctl->util_min = read_uclamp_sysfs(_PATH_PROC_UCLAMP_MIN);
|
||||
|
||||
if (!ctl->util_max_set)
|
||||
ctl->util_max = read_uclamp_sysfs(_PATH_PROC_UCLAMP_MAX);
|
||||
|
||||
if (ctl->util_min > ctl->util_max) {
|
||||
errno = EINVAL;
|
||||
err(EXIT_FAILURE, _("util_min must be <= util_max"));
|
||||
}
|
||||
|
||||
write_uclamp_sysfs(_PATH_PROC_UCLAMP_MIN, ctl->util_min);
|
||||
write_uclamp_sysfs(_PATH_PROC_UCLAMP_MAX, ctl->util_max);
|
||||
}
|
||||
|
||||
static void validate_util(int val)
|
||||
{
|
||||
if (val > 1024 || val < -1) {
|
||||
errno = EINVAL;
|
||||
err(EXIT_FAILURE, _("%d out of range"), val);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct uclampset _ctl = {
|
||||
.pid = -1,
|
||||
.util_min = NOT_SET,
|
||||
.util_max = NOT_SET,
|
||||
.cmd = NULL
|
||||
};
|
||||
struct uclampset *ctl = &_ctl;
|
||||
int c;
|
||||
|
||||
static const struct option longopts[] = {
|
||||
{ "all-tasks", no_argument, NULL, 'a' },
|
||||
{ "pid", required_argument, NULL, 'p' },
|
||||
{ "system", no_argument, NULL, 's' },
|
||||
{ "reset-on-fork", no_argument, NULL, 'R' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ "version", no_argument, NULL, 'V' },
|
||||
{ NULL, no_argument, NULL, 0 }
|
||||
};
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
bindtextdomain(PACKAGE, LOCALEDIR);
|
||||
textdomain(PACKAGE);
|
||||
close_stdout_atexit();
|
||||
|
||||
while((c = getopt_long(argc, argv, "+asRp:hm:M:vV", longopts, NULL)) != -1)
|
||||
{
|
||||
switch (c) {
|
||||
case 'a':
|
||||
ctl->all_tasks = 1;
|
||||
break;
|
||||
case 'p':
|
||||
errno = 0;
|
||||
ctl->pid = strtos32_or_err(optarg, _("invalid PID argument"));
|
||||
optind++;
|
||||
break;
|
||||
case 's':
|
||||
ctl->system = 1;
|
||||
break;
|
||||
case 'R':
|
||||
ctl->reset_on_fork = 1;
|
||||
break;
|
||||
case 'v':
|
||||
ctl->verbose = 1;
|
||||
break;
|
||||
case 'm':
|
||||
ctl->util_min = strtos32_or_err(optarg, _("invalid util_min argument"));
|
||||
ctl->util_min_set = 1;
|
||||
validate_util(ctl->util_min);
|
||||
optind++;
|
||||
break;
|
||||
case 'M':
|
||||
ctl->util_max = strtos32_or_err(optarg, _("invalid util_max argument"));
|
||||
ctl->util_max_set = 1;
|
||||
validate_util(ctl->util_max);
|
||||
optind++;
|
||||
break;
|
||||
case 'V':
|
||||
print_version(EXIT_SUCCESS);
|
||||
/* fallthrough */
|
||||
case 'h':
|
||||
usage();
|
||||
default:
|
||||
errtryhelp(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (argc == 1) {
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* all_tasks implies --pid */
|
||||
if (ctl->all_tasks && ctl->pid == -1) {
|
||||
errno = EINVAL;
|
||||
err(EXIT_FAILURE, _("missing -p option"));
|
||||
}
|
||||
|
||||
if (!ctl->util_min_set && !ctl->util_max_set) {
|
||||
/* -p or -s must be passed */
|
||||
if (!ctl->system && ctl->pid == -1) {
|
||||
usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
show_uclamp_info(ctl);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/* ensure there's a command to execute if no -s or -p */
|
||||
if (!ctl->system && ctl->pid == -1) {
|
||||
if (argc <= optind) {
|
||||
errno = EINVAL;
|
||||
err(EXIT_FAILURE, _("no cmd to execute"));
|
||||
}
|
||||
|
||||
argv += optind;
|
||||
ctl->cmd = argv[0];
|
||||
}
|
||||
|
||||
if (ctl->pid == -1)
|
||||
ctl->pid = 0;
|
||||
|
||||
if (ctl->system)
|
||||
set_uclamp_system(ctl);
|
||||
else
|
||||
set_uclamp_pid(ctl);
|
||||
|
||||
if (ctl->verbose)
|
||||
show_uclamp_info(ctl);
|
||||
|
||||
if (ctl->cmd) {
|
||||
execvp(ctl->cmd, argv);
|
||||
errexec(ctl->cmd);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
Loading…
Reference in New Issue