1*e3566c1bSdholland /* $NetBSD: schedctl.c,v 1.16 2014/07/27 04:46:48 dholland Exp $ */
25c71a4d4Srmind
35c71a4d4Srmind /*
45c71a4d4Srmind * Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
55c71a4d4Srmind * All rights reserved.
65c71a4d4Srmind *
75c71a4d4Srmind * Redistribution and use in source and binary forms, with or without
85c71a4d4Srmind * modification, are permitted provided that the following conditions
95c71a4d4Srmind * are met:
105c71a4d4Srmind * 1. Redistributions of source code must retain the above copyright
115c71a4d4Srmind * notice, this list of conditions and the following disclaimer.
125c71a4d4Srmind * 2. Redistributions in binary form must reproduce the above copyright
135c71a4d4Srmind * notice, this list of conditions and the following disclaimer in the
145c71a4d4Srmind * documentation and/or other materials provided with the distribution.
155c71a4d4Srmind *
16d5ea013eSrmind * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17d5ea013eSrmind * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18d5ea013eSrmind * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19d5ea013eSrmind * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20d5ea013eSrmind * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21d5ea013eSrmind * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22d5ea013eSrmind * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23d5ea013eSrmind * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24d5ea013eSrmind * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25d5ea013eSrmind * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26d5ea013eSrmind * SUCH DAMAGE.
275c71a4d4Srmind */
285c71a4d4Srmind
295c71a4d4Srmind /*
305c71a4d4Srmind * schedctl(8) - a program to control scheduling of processes and threads.
315c71a4d4Srmind */
325c71a4d4Srmind
335c71a4d4Srmind #include <sys/cdefs.h>
345c71a4d4Srmind
355c71a4d4Srmind #ifndef lint
36*e3566c1bSdholland __RCSID("$NetBSD: schedctl.c,v 1.16 2014/07/27 04:46:48 dholland Exp $");
375c71a4d4Srmind #endif
385c71a4d4Srmind
39*e3566c1bSdholland #include <stdbool.h>
405c71a4d4Srmind #include <stdio.h>
415c71a4d4Srmind #include <stdlib.h>
425c71a4d4Srmind #include <string.h>
435c71a4d4Srmind
445c71a4d4Srmind #include <err.h>
455c71a4d4Srmind #include <fcntl.h>
465c71a4d4Srmind #include <kvm.h>
475c71a4d4Srmind #include <unistd.h>
485c71a4d4Srmind
495c71a4d4Srmind #include <sys/pset.h>
505c71a4d4Srmind #include <sys/sched.h>
515c71a4d4Srmind #include <sys/sysctl.h>
525c71a4d4Srmind #include <sys/types.h>
535c71a4d4Srmind
545c71a4d4Srmind static const char *class_str[] = {
555c71a4d4Srmind "SCHED_OTHER",
565c71a4d4Srmind "SCHED_FIFO",
571f959cb4Sad "SCHED_RR",
581f959cb4Sad NULL
595c71a4d4Srmind };
605c71a4d4Srmind
61603e4b9aSyamt static void sched_set(pid_t, lwpid_t, int, struct sched_param *, cpuset_t *);
625c71a4d4Srmind static void thread_info(pid_t, lwpid_t);
635c71a4d4Srmind static cpuset_t *makecpuset(char *);
64*e3566c1bSdholland static void printcpuset(cpuset_t *);
65bec77c5fSjoerg __dead static void usage(void);
665c71a4d4Srmind
67ef515ac1Srmind static u_int ncpu;
68ef515ac1Srmind
695c71a4d4Srmind int
main(int argc,char ** argv)705c71a4d4Srmind main(int argc, char **argv)
715c71a4d4Srmind {
725c71a4d4Srmind kvm_t *kd;
735c71a4d4Srmind struct kinfo_lwp *lwp_list, *lwp;
745c71a4d4Srmind struct sched_param *sp;
755c71a4d4Srmind cpuset_t *cpuset;
76603e4b9aSyamt int i, count, ch, policy;
775c71a4d4Srmind pid_t pid;
785c71a4d4Srmind lwpid_t lid;
795c71a4d4Srmind bool set;
805c71a4d4Srmind
81ef515ac1Srmind ncpu = sysconf(_SC_NPROCESSORS_CONF);
82ef515ac1Srmind
835c71a4d4Srmind pid = lid = 0;
845c71a4d4Srmind cpuset = NULL;
855c71a4d4Srmind set = false;
865c71a4d4Srmind
87fc83e8aaSxtraeme sp = calloc(1, sizeof(struct sched_param));
885c71a4d4Srmind if (sp == NULL)
89fc83e8aaSxtraeme err(EXIT_FAILURE, "calloc");
905c71a4d4Srmind
915c71a4d4Srmind sp->sched_priority = PRI_NONE;
92603e4b9aSyamt policy = SCHED_NONE;
935c71a4d4Srmind
945c71a4d4Srmind while ((ch = getopt(argc, argv, "A:C:P:p:t:")) != -1) {
955c71a4d4Srmind switch (ch) {
965c71a4d4Srmind case 'p':
975c71a4d4Srmind /* PID */
985c71a4d4Srmind pid = atoi(optarg);
995c71a4d4Srmind break;
1005c71a4d4Srmind case 't':
1015c71a4d4Srmind /* Thread (LWP) ID */
1025c71a4d4Srmind lid = atoi(optarg);
1035c71a4d4Srmind break;
1045c71a4d4Srmind case 'A':
1055c71a4d4Srmind /* Affinity */
1065c71a4d4Srmind cpuset = makecpuset(optarg);
1075c71a4d4Srmind if (cpuset == NULL) {
1085c71a4d4Srmind fprintf(stderr, "%s: invalid CPU value\n",
1095c71a4d4Srmind getprogname());
1105c71a4d4Srmind exit(EXIT_FAILURE);
1115c71a4d4Srmind }
1125c71a4d4Srmind break;
1135c71a4d4Srmind case 'C':
1145c71a4d4Srmind /* Scheduling class */
1151f959cb4Sad for (policy = 0; class_str[policy] != NULL; policy++) {
1161f959cb4Sad if (strcasecmp(optarg, class_str[policy]) == 0)
1171f959cb4Sad break;
1181f959cb4Sad }
1191f959cb4Sad if (class_str[policy] == NULL)
120603e4b9aSyamt policy = atoi(optarg);
121603e4b9aSyamt if (policy < SCHED_OTHER || policy > SCHED_RR) {
1225c71a4d4Srmind fprintf(stderr,
1235c71a4d4Srmind "%s: invalid scheduling class\n",
1245c71a4d4Srmind getprogname());
1255c71a4d4Srmind exit(EXIT_FAILURE);
1265c71a4d4Srmind }
1275c71a4d4Srmind set = true;
1285c71a4d4Srmind break;
1295c71a4d4Srmind case 'P':
1305c71a4d4Srmind /* Priority */
1315c71a4d4Srmind sp->sched_priority = atoi(optarg);
1325c71a4d4Srmind if (sp->sched_priority < sysconf(_SC_SCHED_PRI_MIN) ||
1335c71a4d4Srmind sp->sched_priority > sysconf(_SC_SCHED_PRI_MAX)) {
1345c71a4d4Srmind fprintf(stderr, "%s: invalid priority\n",
1355c71a4d4Srmind getprogname());
1365c71a4d4Srmind exit(EXIT_FAILURE);
1375c71a4d4Srmind }
1385c71a4d4Srmind set = true;
1395c71a4d4Srmind break;
1405c71a4d4Srmind default:
1415c71a4d4Srmind usage();
1425c71a4d4Srmind }
1435c71a4d4Srmind }
1445c71a4d4Srmind
1455c71a4d4Srmind /* At least PID must be specified */
146e25a4f7eSad if (pid == 0) {
147355c5b9eSad if (argv[optind] == NULL || lid != 0)
1485c71a4d4Srmind usage();
149e25a4f7eSad pid = getpid();
150e25a4f7eSad } else {
151355c5b9eSad if (argv[optind] != NULL)
152e25a4f7eSad usage();
153e25a4f7eSad }
1545c71a4d4Srmind
1555c71a4d4Srmind /* Set the scheduling information for thread/process */
156603e4b9aSyamt sched_set(pid, lid, policy, set ? sp : NULL, cpuset);
1575c71a4d4Srmind
1585c71a4d4Srmind /* Show information about each thread */
159e25a4f7eSad if (pid != getpid()) {
1605c71a4d4Srmind kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
1615c71a4d4Srmind if (kd == NULL)
1625c71a4d4Srmind err(EXIT_FAILURE, "kvm_open");
1635c71a4d4Srmind lwp_list = kvm_getlwps(kd, pid, 0, sizeof(struct kinfo_lwp), &count);
1645c71a4d4Srmind if (lwp_list == NULL)
1655c71a4d4Srmind err(EXIT_FAILURE, "kvm_getlwps");
1665c71a4d4Srmind for (lwp = lwp_list, i = 0; i < count; lwp++, i++) {
1675c71a4d4Srmind if (lid && lid != lwp->l_lid)
1685c71a4d4Srmind continue;
169c873419dSrmind if (lwp->l_stat == LSIDL || lwp->l_stat == LSZOMB)
170c873419dSrmind continue;
1715c71a4d4Srmind thread_info(pid, lwp->l_lid);
1725c71a4d4Srmind }
1735c71a4d4Srmind kvm_close(kd);
1745c71a4d4Srmind free(sp);
175481ae155Srmind cpuset_destroy(cpuset);
1765c71a4d4Srmind return 0;
1775c71a4d4Srmind }
1785c71a4d4Srmind
179e25a4f7eSad (void)execvp(argv[optind], argv + optind);
180e25a4f7eSad err(EXIT_FAILURE, "execvp");
181e25a4f7eSad }
182e25a4f7eSad
1835c71a4d4Srmind static void
sched_set(pid_t pid,lwpid_t lid,int policy,struct sched_param * sp,cpuset_t * cpuset)184603e4b9aSyamt sched_set(pid_t pid, lwpid_t lid, int policy,
185603e4b9aSyamt struct sched_param *sp, cpuset_t *cpuset)
1865c71a4d4Srmind {
1875c71a4d4Srmind int error;
1885c71a4d4Srmind
1895c71a4d4Srmind if (sp) {
1905c71a4d4Srmind /* Set the scheduling parameters for the thread */
191603e4b9aSyamt error = _sched_setparam(pid, lid, policy, sp);
1925c71a4d4Srmind if (error < 0)
1935c71a4d4Srmind err(EXIT_FAILURE, "_sched_setparam");
1945c71a4d4Srmind }
1955c71a4d4Srmind if (cpuset) {
1965c71a4d4Srmind /* Set the CPU-set for affinity */
1975c71a4d4Srmind error = _sched_setaffinity(pid, lid,
198481ae155Srmind cpuset_size(cpuset), cpuset);
1995c71a4d4Srmind if (error < 0)
2005c71a4d4Srmind err(EXIT_FAILURE, "_sched_setaffinity");
2015c71a4d4Srmind }
2025c71a4d4Srmind }
2035c71a4d4Srmind
2045c71a4d4Srmind static void
thread_info(pid_t pid,lwpid_t lid)2055c71a4d4Srmind thread_info(pid_t pid, lwpid_t lid)
2065c71a4d4Srmind {
2075c71a4d4Srmind struct sched_param sp;
2085c71a4d4Srmind cpuset_t *cpuset;
209603e4b9aSyamt int error, policy;
2105c71a4d4Srmind
211481ae155Srmind cpuset = cpuset_create();
2125c71a4d4Srmind if (cpuset == NULL)
213481ae155Srmind err(EXIT_FAILURE, "cpuset_create");
2145c71a4d4Srmind
215603e4b9aSyamt error = _sched_getparam(pid, lid, &policy, &sp);
2165c71a4d4Srmind if (error < 0)
2175c71a4d4Srmind err(EXIT_FAILURE, "_sched_getparam");
2185c71a4d4Srmind
219481ae155Srmind error = _sched_getaffinity(pid, lid, cpuset_size(cpuset), cpuset);
2205c71a4d4Srmind if (error < 0)
2215c71a4d4Srmind err(EXIT_FAILURE, "_sched_getaffinity");
2225c71a4d4Srmind
2235c71a4d4Srmind printf(" LID: %d\n", lid);
2245c71a4d4Srmind printf(" Priority: %d\n", sp.sched_priority);
225603e4b9aSyamt printf(" Class: %s\n", class_str[policy]);
2265c71a4d4Srmind
227*e3566c1bSdholland printf(" Affinity (CPUs): ");
228*e3566c1bSdholland printcpuset(cpuset);
229*e3566c1bSdholland printf("\n");
2305c71a4d4Srmind
231481ae155Srmind cpuset_destroy(cpuset);
2325c71a4d4Srmind }
2335c71a4d4Srmind
2345c71a4d4Srmind static cpuset_t *
makecpuset(char * str)2355c71a4d4Srmind makecpuset(char *str)
2365c71a4d4Srmind {
2375c71a4d4Srmind cpuset_t *cpuset;
2385c71a4d4Srmind char *cpustr, *s;
2395c71a4d4Srmind
2405c71a4d4Srmind if (str == NULL)
2415c71a4d4Srmind return NULL;
2425c71a4d4Srmind
243481ae155Srmind cpuset = cpuset_create();
2445c71a4d4Srmind if (cpuset == NULL)
245481ae155Srmind err(EXIT_FAILURE, "cpuset_create");
246481ae155Srmind cpuset_zero(cpuset);
2475c71a4d4Srmind
2485c71a4d4Srmind cpustr = strdup(str);
2495c71a4d4Srmind if (cpustr == NULL)
2505c71a4d4Srmind err(EXIT_FAILURE, "strdup");
2515c71a4d4Srmind s = cpustr;
2525c71a4d4Srmind
2535c71a4d4Srmind while (s != NULL) {
2545c71a4d4Srmind char *p;
2555c71a4d4Srmind int i;
2565c71a4d4Srmind
2575c71a4d4Srmind /* Get the CPU number and validate the range */
2585c71a4d4Srmind p = strsep(&s, ",");
2595c71a4d4Srmind if (p == NULL) {
260481ae155Srmind cpuset_destroy(cpuset);
2615c71a4d4Srmind cpuset = NULL;
2625c71a4d4Srmind break;
2635c71a4d4Srmind }
2645c71a4d4Srmind i = atoi(p);
2655c71a4d4Srmind if (i == -1) {
266481ae155Srmind cpuset_zero(cpuset);
2675c71a4d4Srmind break;
2685c71a4d4Srmind }
269ef515ac1Srmind if ((unsigned int)i >= ncpu) {
270481ae155Srmind cpuset_destroy(cpuset);
2715c71a4d4Srmind cpuset = NULL;
2725c71a4d4Srmind break;
2735c71a4d4Srmind }
2745c71a4d4Srmind
2755c71a4d4Srmind /* Set the bit */
276481ae155Srmind cpuset_set(i, cpuset);
2775c71a4d4Srmind }
2785c71a4d4Srmind
2795c71a4d4Srmind free(cpustr);
2805c71a4d4Srmind return cpuset;
2815c71a4d4Srmind }
2825c71a4d4Srmind
283*e3566c1bSdholland static void
printcpuset(cpuset_t * cpuset)284*e3566c1bSdholland printcpuset(cpuset_t *cpuset)
2855c71a4d4Srmind {
2863cafe960Slukem unsigned int i;
287*e3566c1bSdholland bool seen;
2885c71a4d4Srmind
289*e3566c1bSdholland seen = false;
290*e3566c1bSdholland for (i = 0; i < ncpu; i++) {
291*e3566c1bSdholland if (cpuset_isset(i, cpuset)) {
292*e3566c1bSdholland if (seen) {
293*e3566c1bSdholland putchar(',');
294*e3566c1bSdholland }
295*e3566c1bSdholland printf("%d", i);
296*e3566c1bSdholland seen = true;
297*e3566c1bSdholland }
2985c71a4d4Srmind }
2995c71a4d4Srmind
300*e3566c1bSdholland if (!seen) {
301*e3566c1bSdholland printf("<none>");
302*e3566c1bSdholland }
3035c71a4d4Srmind }
3045c71a4d4Srmind
3055c71a4d4Srmind static void
usage(void)3065c71a4d4Srmind usage(void)
3075c71a4d4Srmind {
308e25a4f7eSad
30920eb39d3Swiz fprintf(stderr, "usage: %s [-A processor] [-C class] "
31020eb39d3Swiz "[-P priority] [-t lid] {-p pid|command}\n", getprogname());
3115c71a4d4Srmind exit(EXIT_FAILURE);
3125c71a4d4Srmind }
313