1 1.16 dholland /* $NetBSD: schedctl.c,v 1.16 2014/07/27 04:46:48 dholland Exp $ */ 2 1.1 rmind 3 1.1 rmind /* 4 1.1 rmind * Copyright (c) 2008, Mindaugas Rasiukevicius <rmind at NetBSD org> 5 1.1 rmind * All rights reserved. 6 1.1 rmind * 7 1.1 rmind * Redistribution and use in source and binary forms, with or without 8 1.1 rmind * modification, are permitted provided that the following conditions 9 1.1 rmind * are met: 10 1.1 rmind * 1. Redistributions of source code must retain the above copyright 11 1.1 rmind * notice, this list of conditions and the following disclaimer. 12 1.1 rmind * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 rmind * notice, this list of conditions and the following disclaimer in the 14 1.1 rmind * documentation and/or other materials provided with the distribution. 15 1.1 rmind * 16 1.12 rmind * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.12 rmind * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.12 rmind * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.12 rmind * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.12 rmind * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.12 rmind * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.12 rmind * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.12 rmind * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.12 rmind * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.12 rmind * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.12 rmind * SUCH DAMAGE. 27 1.1 rmind */ 28 1.1 rmind 29 1.1 rmind /* 30 1.1 rmind * schedctl(8) - a program to control scheduling of processes and threads. 31 1.1 rmind */ 32 1.1 rmind 33 1.1 rmind #include <sys/cdefs.h> 34 1.1 rmind 35 1.1 rmind #ifndef lint 36 1.16 dholland __RCSID("$NetBSD: schedctl.c,v 1.16 2014/07/27 04:46:48 dholland Exp $"); 37 1.1 rmind #endif 38 1.1 rmind 39 1.16 dholland #include <stdbool.h> 40 1.1 rmind #include <stdio.h> 41 1.1 rmind #include <stdlib.h> 42 1.1 rmind #include <string.h> 43 1.1 rmind 44 1.1 rmind #include <err.h> 45 1.1 rmind #include <fcntl.h> 46 1.1 rmind #include <kvm.h> 47 1.1 rmind #include <unistd.h> 48 1.1 rmind 49 1.1 rmind #include <sys/pset.h> 50 1.1 rmind #include <sys/sched.h> 51 1.1 rmind #include <sys/sysctl.h> 52 1.1 rmind #include <sys/types.h> 53 1.1 rmind 54 1.1 rmind static const char *class_str[] = { 55 1.1 rmind "SCHED_OTHER", 56 1.1 rmind "SCHED_FIFO", 57 1.6 ad "SCHED_RR", 58 1.6 ad NULL 59 1.1 rmind }; 60 1.1 rmind 61 1.3 yamt static void sched_set(pid_t, lwpid_t, int, struct sched_param *, cpuset_t *); 62 1.1 rmind static void thread_info(pid_t, lwpid_t); 63 1.1 rmind static cpuset_t *makecpuset(char *); 64 1.16 dholland static void printcpuset(cpuset_t *); 65 1.15 joerg __dead static void usage(void); 66 1.1 rmind 67 1.2 rmind static u_int ncpu; 68 1.2 rmind 69 1.1 rmind int 70 1.1 rmind main(int argc, char **argv) 71 1.1 rmind { 72 1.1 rmind kvm_t *kd; 73 1.1 rmind struct kinfo_lwp *lwp_list, *lwp; 74 1.1 rmind struct sched_param *sp; 75 1.1 rmind cpuset_t *cpuset; 76 1.3 yamt int i, count, ch, policy; 77 1.1 rmind pid_t pid; 78 1.1 rmind lwpid_t lid; 79 1.1 rmind bool set; 80 1.1 rmind 81 1.2 rmind ncpu = sysconf(_SC_NPROCESSORS_CONF); 82 1.2 rmind 83 1.1 rmind pid = lid = 0; 84 1.1 rmind cpuset = NULL; 85 1.1 rmind set = false; 86 1.1 rmind 87 1.4 xtraeme sp = calloc(1, sizeof(struct sched_param)); 88 1.1 rmind if (sp == NULL) 89 1.4 xtraeme err(EXIT_FAILURE, "calloc"); 90 1.1 rmind 91 1.1 rmind sp->sched_priority = PRI_NONE; 92 1.3 yamt policy = SCHED_NONE; 93 1.1 rmind 94 1.1 rmind while ((ch = getopt(argc, argv, "A:C:P:p:t:")) != -1) { 95 1.1 rmind switch (ch) { 96 1.1 rmind case 'p': 97 1.1 rmind /* PID */ 98 1.1 rmind pid = atoi(optarg); 99 1.1 rmind break; 100 1.1 rmind case 't': 101 1.1 rmind /* Thread (LWP) ID */ 102 1.1 rmind lid = atoi(optarg); 103 1.1 rmind break; 104 1.1 rmind case 'A': 105 1.1 rmind /* Affinity */ 106 1.1 rmind cpuset = makecpuset(optarg); 107 1.1 rmind if (cpuset == NULL) { 108 1.1 rmind fprintf(stderr, "%s: invalid CPU value\n", 109 1.1 rmind getprogname()); 110 1.1 rmind exit(EXIT_FAILURE); 111 1.1 rmind } 112 1.1 rmind break; 113 1.1 rmind case 'C': 114 1.1 rmind /* Scheduling class */ 115 1.6 ad for (policy = 0; class_str[policy] != NULL; policy++) { 116 1.6 ad if (strcasecmp(optarg, class_str[policy]) == 0) 117 1.6 ad break; 118 1.6 ad } 119 1.6 ad if (class_str[policy] == NULL) 120 1.6 ad policy = atoi(optarg); 121 1.3 yamt if (policy < SCHED_OTHER || policy > SCHED_RR) { 122 1.1 rmind fprintf(stderr, 123 1.1 rmind "%s: invalid scheduling class\n", 124 1.1 rmind getprogname()); 125 1.1 rmind exit(EXIT_FAILURE); 126 1.1 rmind } 127 1.1 rmind set = true; 128 1.1 rmind break; 129 1.1 rmind case 'P': 130 1.1 rmind /* Priority */ 131 1.1 rmind sp->sched_priority = atoi(optarg); 132 1.1 rmind if (sp->sched_priority < sysconf(_SC_SCHED_PRI_MIN) || 133 1.1 rmind sp->sched_priority > sysconf(_SC_SCHED_PRI_MAX)) { 134 1.1 rmind fprintf(stderr, "%s: invalid priority\n", 135 1.1 rmind getprogname()); 136 1.1 rmind exit(EXIT_FAILURE); 137 1.1 rmind } 138 1.1 rmind set = true; 139 1.1 rmind break; 140 1.1 rmind default: 141 1.1 rmind usage(); 142 1.1 rmind } 143 1.1 rmind } 144 1.1 rmind 145 1.1 rmind /* At least PID must be specified */ 146 1.7 ad if (pid == 0) { 147 1.9 ad if (argv[optind] == NULL || lid != 0) 148 1.7 ad usage(); 149 1.7 ad pid = getpid(); 150 1.7 ad } else { 151 1.9 ad if (argv[optind] != NULL) 152 1.7 ad usage(); 153 1.7 ad } 154 1.1 rmind 155 1.1 rmind /* Set the scheduling information for thread/process */ 156 1.3 yamt sched_set(pid, lid, policy, set ? sp : NULL, cpuset); 157 1.1 rmind 158 1.1 rmind /* Show information about each thread */ 159 1.7 ad if (pid != getpid()) { 160 1.7 ad kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open"); 161 1.7 ad if (kd == NULL) 162 1.7 ad err(EXIT_FAILURE, "kvm_open"); 163 1.7 ad lwp_list = kvm_getlwps(kd, pid, 0, sizeof(struct kinfo_lwp), &count); 164 1.7 ad if (lwp_list == NULL) 165 1.7 ad err(EXIT_FAILURE, "kvm_getlwps"); 166 1.7 ad for (lwp = lwp_list, i = 0; i < count; lwp++, i++) { 167 1.7 ad if (lid && lid != lwp->l_lid) 168 1.7 ad continue; 169 1.14 rmind if (lwp->l_stat == LSIDL || lwp->l_stat == LSZOMB) 170 1.14 rmind continue; 171 1.7 ad thread_info(pid, lwp->l_lid); 172 1.7 ad } 173 1.7 ad kvm_close(kd); 174 1.7 ad free(sp); 175 1.11 rmind cpuset_destroy(cpuset); 176 1.7 ad return 0; 177 1.1 rmind } 178 1.1 rmind 179 1.7 ad (void)execvp(argv[optind], argv + optind); 180 1.7 ad err(EXIT_FAILURE, "execvp"); 181 1.1 rmind } 182 1.1 rmind 183 1.1 rmind static void 184 1.3 yamt sched_set(pid_t pid, lwpid_t lid, int policy, 185 1.3 yamt struct sched_param *sp, cpuset_t *cpuset) 186 1.1 rmind { 187 1.1 rmind int error; 188 1.1 rmind 189 1.1 rmind if (sp) { 190 1.1 rmind /* Set the scheduling parameters for the thread */ 191 1.3 yamt error = _sched_setparam(pid, lid, policy, sp); 192 1.1 rmind if (error < 0) 193 1.1 rmind err(EXIT_FAILURE, "_sched_setparam"); 194 1.1 rmind } 195 1.1 rmind if (cpuset) { 196 1.1 rmind /* Set the CPU-set for affinity */ 197 1.1 rmind error = _sched_setaffinity(pid, lid, 198 1.11 rmind cpuset_size(cpuset), cpuset); 199 1.1 rmind if (error < 0) 200 1.1 rmind err(EXIT_FAILURE, "_sched_setaffinity"); 201 1.1 rmind } 202 1.1 rmind } 203 1.1 rmind 204 1.1 rmind static void 205 1.1 rmind thread_info(pid_t pid, lwpid_t lid) 206 1.1 rmind { 207 1.1 rmind struct sched_param sp; 208 1.1 rmind cpuset_t *cpuset; 209 1.3 yamt int error, policy; 210 1.1 rmind 211 1.11 rmind cpuset = cpuset_create(); 212 1.1 rmind if (cpuset == NULL) 213 1.11 rmind err(EXIT_FAILURE, "cpuset_create"); 214 1.1 rmind 215 1.3 yamt error = _sched_getparam(pid, lid, &policy, &sp); 216 1.1 rmind if (error < 0) 217 1.1 rmind err(EXIT_FAILURE, "_sched_getparam"); 218 1.1 rmind 219 1.11 rmind error = _sched_getaffinity(pid, lid, cpuset_size(cpuset), cpuset); 220 1.1 rmind if (error < 0) 221 1.1 rmind err(EXIT_FAILURE, "_sched_getaffinity"); 222 1.1 rmind 223 1.1 rmind printf(" LID: %d\n", lid); 224 1.1 rmind printf(" Priority: %d\n", sp.sched_priority); 225 1.3 yamt printf(" Class: %s\n", class_str[policy]); 226 1.1 rmind 227 1.16 dholland printf(" Affinity (CPUs): "); 228 1.16 dholland printcpuset(cpuset); 229 1.16 dholland printf("\n"); 230 1.1 rmind 231 1.11 rmind cpuset_destroy(cpuset); 232 1.1 rmind } 233 1.1 rmind 234 1.1 rmind static cpuset_t * 235 1.1 rmind makecpuset(char *str) 236 1.1 rmind { 237 1.1 rmind cpuset_t *cpuset; 238 1.1 rmind char *cpustr, *s; 239 1.1 rmind 240 1.1 rmind if (str == NULL) 241 1.1 rmind return NULL; 242 1.1 rmind 243 1.11 rmind cpuset = cpuset_create(); 244 1.1 rmind if (cpuset == NULL) 245 1.11 rmind err(EXIT_FAILURE, "cpuset_create"); 246 1.11 rmind cpuset_zero(cpuset); 247 1.1 rmind 248 1.1 rmind cpustr = strdup(str); 249 1.1 rmind if (cpustr == NULL) 250 1.1 rmind err(EXIT_FAILURE, "strdup"); 251 1.1 rmind s = cpustr; 252 1.1 rmind 253 1.1 rmind while (s != NULL) { 254 1.1 rmind char *p; 255 1.1 rmind int i; 256 1.1 rmind 257 1.1 rmind /* Get the CPU number and validate the range */ 258 1.1 rmind p = strsep(&s, ","); 259 1.1 rmind if (p == NULL) { 260 1.11 rmind cpuset_destroy(cpuset); 261 1.1 rmind cpuset = NULL; 262 1.1 rmind break; 263 1.1 rmind } 264 1.1 rmind i = atoi(p); 265 1.1 rmind if (i == -1) { 266 1.11 rmind cpuset_zero(cpuset); 267 1.1 rmind break; 268 1.1 rmind } 269 1.2 rmind if ((unsigned int)i >= ncpu) { 270 1.11 rmind cpuset_destroy(cpuset); 271 1.1 rmind cpuset = NULL; 272 1.1 rmind break; 273 1.1 rmind } 274 1.1 rmind 275 1.1 rmind /* Set the bit */ 276 1.11 rmind cpuset_set(i, cpuset); 277 1.1 rmind } 278 1.1 rmind 279 1.1 rmind free(cpustr); 280 1.1 rmind return cpuset; 281 1.1 rmind } 282 1.1 rmind 283 1.16 dholland static void 284 1.16 dholland printcpuset(cpuset_t *cpuset) 285 1.1 rmind { 286 1.13 lukem unsigned int i; 287 1.16 dholland bool seen; 288 1.1 rmind 289 1.16 dholland seen = false; 290 1.16 dholland for (i = 0; i < ncpu; i++) { 291 1.16 dholland if (cpuset_isset(i, cpuset)) { 292 1.16 dholland if (seen) { 293 1.16 dholland putchar(','); 294 1.16 dholland } 295 1.16 dholland printf("%d", i); 296 1.16 dholland seen = true; 297 1.16 dholland } 298 1.1 rmind } 299 1.1 rmind 300 1.16 dholland if (!seen) { 301 1.16 dholland printf("<none>"); 302 1.16 dholland } 303 1.1 rmind } 304 1.1 rmind 305 1.1 rmind static void 306 1.1 rmind usage(void) 307 1.1 rmind { 308 1.7 ad 309 1.8 wiz fprintf(stderr, "usage: %s [-A processor] [-C class] " 310 1.8 wiz "[-P priority] [-t lid] {-p pid|command}\n", getprogname()); 311 1.1 rmind exit(EXIT_FAILURE); 312 1.1 rmind } 313