1 /* $NetBSD: schedctl.c,v 1.13 2009/01/18 10:18:32 lukem Exp $ */
4 * Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * schedctl(8) - a program to control scheduling of processes and threads.
33 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: schedctl.c,v 1.13 2009/01/18 10:18:32 lukem Exp $");
49 #include <sys/sched.h>
50 #include <sys/sysctl.h>
51 #include <sys/types.h>
53 static const char *class_str
[] = {
60 static void sched_set(pid_t
, lwpid_t
, int, struct sched_param
*, cpuset_t
*);
61 static void thread_info(pid_t
, lwpid_t
);
62 static cpuset_t
*makecpuset(char *);
63 static char *showcpuset(cpuset_t
*);
64 static void usage(void);
69 main(int argc
, char **argv
)
72 struct kinfo_lwp
*lwp_list
, *lwp
;
73 struct sched_param
*sp
;
75 int i
, count
, ch
, policy
;
80 ncpu
= sysconf(_SC_NPROCESSORS_CONF
);
86 sp
= calloc(1, sizeof(struct sched_param
));
88 err(EXIT_FAILURE
, "calloc");
90 sp
->sched_priority
= PRI_NONE
;
93 while ((ch
= getopt(argc
, argv
, "A:C:P:p:t:")) != -1) {
100 /* Thread (LWP) ID */
105 cpuset
= makecpuset(optarg
);
106 if (cpuset
== NULL
) {
107 fprintf(stderr
, "%s: invalid CPU value\n",
113 /* Scheduling class */
114 for (policy
= 0; class_str
[policy
] != NULL
; policy
++) {
115 if (strcasecmp(optarg
, class_str
[policy
]) == 0)
118 if (class_str
[policy
] == NULL
)
119 policy
= atoi(optarg
);
120 if (policy
< SCHED_OTHER
|| policy
> SCHED_RR
) {
122 "%s: invalid scheduling class\n",
130 sp
->sched_priority
= atoi(optarg
);
131 if (sp
->sched_priority
< sysconf(_SC_SCHED_PRI_MIN
) ||
132 sp
->sched_priority
> sysconf(_SC_SCHED_PRI_MAX
)) {
133 fprintf(stderr
, "%s: invalid priority\n",
144 /* At least PID must be specified */
146 if (argv
[optind
] == NULL
|| lid
!= 0)
150 if (argv
[optind
] != NULL
)
154 /* Set the scheduling information for thread/process */
155 sched_set(pid
, lid
, policy
, set
? sp
: NULL
, cpuset
);
157 /* Show information about each thread */
158 if (pid
!= getpid()) {
159 kd
= kvm_open(NULL
, NULL
, NULL
, KVM_NO_FILES
, "kvm_open");
161 err(EXIT_FAILURE
, "kvm_open");
162 lwp_list
= kvm_getlwps(kd
, pid
, 0, sizeof(struct kinfo_lwp
), &count
);
163 if (lwp_list
== NULL
)
164 err(EXIT_FAILURE
, "kvm_getlwps");
165 for (lwp
= lwp_list
, i
= 0; i
< count
; lwp
++, i
++) {
166 if (lid
&& lid
!= lwp
->l_lid
)
168 if (lwp
->l_stat
== LSIDL
|| lwp
->l_stat
== LSZOMB
)
170 thread_info(pid
, lwp
->l_lid
);
174 cpuset_destroy(cpuset
);
178 (void)execvp(argv
[optind
], argv
+ optind
);
179 err(EXIT_FAILURE
, "execvp");
183 sched_set(pid_t pid
, lwpid_t lid
, int policy
,
184 struct sched_param
*sp
, cpuset_t
*cpuset
)
189 /* Set the scheduling parameters for the thread */
190 error
= _sched_setparam(pid
, lid
, policy
, sp
);
192 err(EXIT_FAILURE
, "_sched_setparam");
195 /* Set the CPU-set for affinity */
196 error
= _sched_setaffinity(pid
, lid
,
197 cpuset_size(cpuset
), cpuset
);
199 err(EXIT_FAILURE
, "_sched_setaffinity");
204 thread_info(pid_t pid
, lwpid_t lid
)
206 struct sched_param sp
;
211 cpuset
= cpuset_create();
213 err(EXIT_FAILURE
, "cpuset_create");
215 error
= _sched_getparam(pid
, lid
, &policy
, &sp
);
217 err(EXIT_FAILURE
, "_sched_getparam");
219 error
= _sched_getaffinity(pid
, lid
, cpuset_size(cpuset
), cpuset
);
221 err(EXIT_FAILURE
, "_sched_getaffinity");
223 printf(" LID: %d\n", lid
);
224 printf(" Priority: %d\n", sp
.sched_priority
);
225 printf(" Class: %s\n", class_str
[policy
]);
227 cpus
= showcpuset(cpuset
);
228 printf(" Affinity (CPUs): %s\n", cpus
);
231 cpuset_destroy(cpuset
);
235 makecpuset(char *str
)
243 cpuset
= cpuset_create();
245 err(EXIT_FAILURE
, "cpuset_create");
248 cpustr
= strdup(str
);
250 err(EXIT_FAILURE
, "strdup");
257 /* Get the CPU number and validate the range */
260 cpuset_destroy(cpuset
);
269 if ((unsigned int)i
>= ncpu
) {
270 cpuset_destroy(cpuset
);
276 cpuset_set(i
, cpuset
);
284 showcpuset(cpuset_t
*cpuset
)
290 size
= 3 * ncpu
; /* XXX */
291 buf
= malloc(size
+ 1);
293 err(EXIT_FAILURE
, "malloc");
294 memset(buf
, '\0', size
+ 1);
296 for (i
= 0; i
< ncpu
; i
++)
297 if (cpuset_isset(i
, cpuset
))
298 snprintf(buf
, size
, "%s%d,", buf
, i
);
304 strncpy(buf
, "<none>", size
);
314 fprintf(stderr
, "usage: %s [-A processor] [-C class] "
315 "[-P priority] [-t lid] {-p pid|command}\n", getprogname());