1 #include "config.h" 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include <sys/types.h> 6 #include <dirent.h> 7 #include <err.h> 8 #include <errno.h> 9 10 #include "bitmask.h" 11 #include "cpuset.h" 12 #include "common.h" 13 #include "cpuinfo.h" 14 15 #if HAVE_LINUX_MEMPOLICY_H 16 17 #define CPUINFO_FILE "/proc/cpuinfo" 18 #define SCHEDSTAT_FILE "/proc/schedstat" 19 #define CGROUPINFO_FILE "/proc/cgroups" 20 #define SYS_CPU_DIR "/sys/devices/system/cpu" 21 #define LIST_PRESENT_CPU_FILE "/sys/devices/system/cpu/present" 22 #define LIST_ONLINE_CPU_FILE "/sys/devices/system/cpu/online" 23 24 struct cpuinfo *cpus; 25 int ncpus; 26 int cpus_nbits; 27 28 /* get cpu_baseinfo from /proc/cpuinfo */ 29 static int get_cpu_baseinfo(void) 30 { 31 FILE *fp = NULL; 32 char buf[BUFFSIZE]; 33 char *istr = NULL, *valstr = NULL, *saveptr = NULL; 34 int ci = 0; 35 int data = 0; 36 37 /* get the number of cpus including offline cpus */ 38 if (!ncpus) { 39 ncpus = get_ncpus(); 40 if (ncpus <= 0) 41 return -1; 42 } 43 44 if (cpus != NULL) { 45 free(cpus); 46 cpus = NULL; 47 } 48 49 /* allocate the memory space for cpus */ 50 cpus = malloc(sizeof(*cpus) * ncpus); 51 if (cpus == NULL) 52 return -1; 53 memset(cpus, 0, sizeof(*cpus) * ncpus); 54 55 /* open file /proc/cpuinfo */ 56 if ((fp = fopen(CPUINFO_FILE, "r")) == NULL) 57 return -1; 58 59 /* get cpuinfo */ 60 while (fgets(buf, sizeof(buf), fp) != NULL) { 61 istr = strtok_r(buf, "\t", &saveptr); 62 valstr = strchr(saveptr, ':'); 63 if (valstr == NULL) 64 continue; 65 valstr++; 66 sscanf(valstr, " %d\n", &data); 67 if (!strcmp(istr, "processor")) { 68 if (data >= ncpus) { 69 warnx("Warn: wrong cpu index"); 70 fclose(fp); 71 return -1; 72 } 73 ci = data; 74 cpus[ci].online = 1; 75 } 76 } 77 78 fclose(fp); 79 return 0; 80 } 81 82 /* 83 * get the cpu bitmask of the online processors 84 * 85 * return value: 0 - success 86 * -1 - failed 87 */ 88 int online_cpumask(struct bitmask *cpumask) 89 { 90 FILE *fp = NULL; 91 char buf[BUFFSIZE]; 92 int i; 93 94 if (cpumask == NULL) 95 return -1; 96 /* 97 * open file /sys/devices/system/cpu/online and get online 98 * cpulist. 99 */ 100 if ((fp = fopen(LIST_ONLINE_CPU_FILE, "r")) == NULL) { 101 if (get_cpu_baseinfo() != 0) 102 return -1; 103 for (i = 0; i < ncpus; i++) { 104 if (cpus[i].online) 105 bitmask_setbit(cpumask, i); 106 } 107 } else { 108 if (fgets(buf, sizeof(buf), fp) == NULL) { 109 fclose(fp); 110 return -1; 111 } 112 fclose(fp); 113 114 /* parse present cpu list to bitmap */ 115 buf[strlen(buf) - 1] = '\0'; 116 if (bitmask_parselist(buf, cpumask) != 0) 117 return -1; 118 } 119 120 return 0; 121 } 122 123 /* 124 * get the cpu bitmask of the present processors including offline CPUs 125 * 126 * return value: 0 - success 127 * -1 - failed 128 */ 129 int present_cpumask(struct bitmask *cpumask) 130 { 131 FILE *fp = NULL; 132 char buf[BUFFSIZE]; 133 char c_relpath[PATH_MAX]; 134 int cpu = -1; 135 136 if (cpumask == NULL) 137 return -1; 138 /* 139 * open file /sys/devices/system/cpu/present and get present 140 * cpulist. 141 */ 142 if ((fp = fopen(LIST_PRESENT_CPU_FILE, "r")) == NULL) { 143 while_each_childdir(SYS_CPU_DIR, "/", c_relpath, 144 sizeof(c_relpath)) { 145 if (!strncmp(c_relpath + 1, "cpu", 3) 146 && sscanf(c_relpath + 4, "%d", &cpu) > 0) { 147 if (cpu >= 0) 148 bitmask_setbit(cpumask, cpu); 149 } 150 } 151 end_while_each_childdir} else { 152 if (fgets(buf, sizeof(buf), fp) == NULL) { 153 fclose(fp); 154 return -1; 155 } 156 fclose(fp); 157 158 /* parse present cpu list to bitmap */ 159 buf[strlen(buf) - 1] = '\0'; 160 if (bitmask_parselist(buf, cpumask) != 0) 161 return -1; 162 } 163 164 return 0; 165 } 166 167 /* 168 * get the number of the processors including offline CPUs 169 * We get this number from /sys/devices/system/cpu/present. 170 * By analyzing the present cpu list, we get the number of all cpus 171 */ 172 int get_ncpus(void) 173 { 174 struct bitmask *bmp = NULL; 175 int n = 0; 176 177 /* get the bitmask's len */ 178 cpus_nbits = cpuset_cpus_nbits(); 179 if (cpus_nbits <= 0) 180 return -1; 181 182 /* allocate the space for bitmask */ 183 bmp = bitmask_alloc(cpus_nbits); 184 if (bmp == NULL) 185 return -1; 186 187 if (present_cpumask(bmp)) { 188 bitmask_free(bmp); 189 return -1; 190 } 191 192 /* Number of highest set bit +1 is the number of the CPUs */ 193 n = bitmask_last(bmp) + 1; 194 bitmask_free(bmp); 195 196 return n; 197 } 198 199 /* get the sched domain's info for each cpu */ 200 static int get_sched_domains(void) 201 { 202 FILE *fp = NULL; 203 char buf[BUFFSIZE]; 204 char str1[20], str2[BUFFSIZE]; 205 int ci = 0; 206 207 /* get the bitmask's len */ 208 if (!cpus_nbits) { 209 cpus_nbits = cpuset_cpus_nbits(); 210 if (cpus_nbits <= 0) { 211 warnx("get cpus nbits failed."); 212 return -1; 213 } 214 } 215 216 /* open file /proc/schedstat */ 217 if ((fp = fopen(SCHEDSTAT_FILE, "r")) == NULL) 218 return -1; 219 220 /* get cpuinfo */ 221 while (fgets(buf, sizeof(buf), fp) != NULL) { 222 sscanf(buf, "%s %s", str1, str2); 223 if (!strncmp(str1, "cpu", 3)) { 224 ci = atoi(str1 + 3); 225 if (ci < 0 || ci >= ncpus) { 226 fprintf(stderr, "Warn: wrong cpu index"); 227 fclose(fp); 228 return -1; 229 } 230 } else if (!strncmp(str1, "domain", 6)) { 231 if (!cpus[ci].sched_domain) { 232 cpus[ci].sched_domain = 233 bitmask_alloc(cpus_nbits); 234 if (!cpus[ci].sched_domain) { 235 fclose(fp); 236 return -1; 237 } 238 } 239 if (bitmask_parsehex(str2, cpus[ci].sched_domain)) { 240 fclose(fp); 241 return -1; 242 } 243 } 244 } 245 246 fclose(fp); 247 return 0; 248 } 249 250 int getcpuinfo(void) 251 { 252 int i; 253 int node = -1; 254 255 /* get the number of cpus including offline cpus */ 256 if (!ncpus) { 257 ncpus = get_ncpus(); 258 if (ncpus <= 0) 259 return -1; 260 } 261 262 if (cpus == NULL) { 263 if (get_cpu_baseinfo() != 0) { 264 warn("get base infomation of cpus from /proc/cpuinfo " 265 "failed."); 266 return -1; 267 } 268 } 269 270 /* which node is every cpu belong to? */ 271 for (i = 0; i < ncpus; i++) { 272 node = cpuset_cpu2node(i); 273 if (node == -1) 274 warnx("cpu2node failed(cpu = %d)", i); 275 cpus[i].nodeid = node; 276 } 277 278 /* get sched domain's infomation for each cpu */ 279 if (get_sched_domains()) { 280 warnx("get sched domain's info for each cpu failed."); 281 return -1; 282 } 283 284 return 0; 285 } 286 287 /* get the number of the cpuset groups */ 288 static int get_num_cpusets(void) 289 { 290 FILE *fp = NULL; 291 char buf[BUFFSIZE]; 292 char subsys_name[BUFFSIZE]; 293 int num_cgroups = 0; 294 int hierarchy; 295 int enabled; 296 297 /* open file /proc/cgroups and get num cpusets */ 298 if ((fp = fopen(CGROUPINFO_FILE, "r")) == NULL) 299 return -1; 300 301 while (fgets(buf, sizeof(buf), fp) != NULL) { 302 if (!strncmp(buf, "cpuset", 6)) { 303 sscanf(buf, "%s\t%d\t%d\t%d\n", subsys_name, 304 &hierarchy, &num_cgroups, &enabled); 305 } 306 } 307 308 fclose(fp); 309 310 return num_cgroups; 311 } 312 313 static struct cpuset **cpusets; 314 static int ncpusets; 315 316 static int find_domain_cpusets(char *relpath) 317 { 318 struct cpuset *cp = NULL; 319 char c_relpath[PATH_MAX]; 320 int ret = 0; 321 322 if (relpath == NULL) { 323 errno = -EFAULT; 324 return -1; 325 } 326 327 cp = cpuset_alloc(); 328 if (cp == NULL) { 329 errno = -ENOMEM; 330 return -1; 331 } 332 333 if (cpuset_query(cp, relpath)) { 334 cpuset_free(cp); 335 return -1; 336 } 337 338 if (cpuset_cpus_weight(cp) == 0) 339 return 0; 340 341 if (cpuset_cpus_weight(cp) > 0 342 && cpuset_get_iopt(cp, "sched_load_balance") == 1) { 343 cpusets[ncpusets] = cp; 344 ncpusets++; 345 return 0; 346 } 347 348 while_each_childdir(cpuset_mountpoint(), relpath, c_relpath, 349 sizeof(c_relpath)) { 350 if ((ret = find_domain_cpusets(c_relpath))) 351 break; 352 } 353 end_while_each_childdir; 354 355 return ret; 356 } 357 358 struct bitmask **domains; 359 int ndomains; 360 361 int partition_domains(void) 362 { 363 int num_cpusets = 0; 364 int i, j; 365 struct bitmask *cpusa = NULL, *cpusb = NULL, *cpusc = NULL; 366 int *flg = NULL; 367 int ret = 0; 368 369 num_cpusets = get_num_cpusets(); 370 if (num_cpusets == 0) { 371 warnx("cpuset subsystem is't compiled into kernel."); 372 return -1; 373 } 374 375 if (!cpus_nbits) { 376 cpus_nbits = cpuset_cpus_nbits(); 377 if (!cpus_nbits) { 378 warnx("nbits of cpus is wrong."); 379 return -1; 380 } 381 } 382 383 cpusa = bitmask_alloc(cpus_nbits); 384 if (cpusa == NULL) { 385 warnx("bitmask_alloc for partition domains failed."); 386 return -1; 387 } 388 389 cpusb = bitmask_alloc(cpus_nbits); 390 if (cpusb == NULL) { 391 warnx("bitmask_alloc for partition domains failed."); 392 ret = -1; 393 goto errcpusb; 394 } 395 396 cpusc = bitmask_alloc(cpus_nbits); 397 if (cpusb == NULL) { 398 warnx("bitmask_alloc for partition domains failed."); 399 ret = -1; 400 goto errcpusc; 401 } 402 403 cpusets = malloc(num_cpusets * sizeof(*cpusets)); 404 if (cpusets == NULL) { 405 warnx("alloc cpusets space failed."); 406 ret = -1; 407 goto errcpusets; 408 } 409 410 if ((ret = find_domain_cpusets("/"))) { 411 warnx("find domain cpusets failed."); 412 goto errfindcpusets; 413 } 414 415 flg = malloc(num_cpusets * sizeof(int)); 416 if (flg == NULL) { 417 warnx("alloc flg failed."); 418 ret = -1; 419 goto errfindcpusets; 420 } 421 memset(flg, 0, num_cpusets * sizeof(int)); 422 423 ndomains = ncpusets; 424 restart: 425 for (i = 0; i < ncpusets; i++) { 426 struct cpuset *cpa = cpusets[i]; 427 428 if (flg[i]) 429 continue; 430 431 cpuset_getcpus(cpa, cpusa); 432 433 for (j = i + 1; j < ncpusets; j++) { 434 struct cpuset *cpb = cpusets[j]; 435 436 if (flg[j]) 437 continue; 438 439 cpuset_getcpus(cpb, cpusb); 440 if (bitmask_intersects(cpusa, cpusb)) { 441 bitmask_or(cpusc, cpusa, cpusb); 442 cpuset_setcpus(cpa, cpusc); 443 flg[j] = 1; 444 ndomains--; 445 goto restart; 446 } 447 } 448 } 449 450 domains = malloc(ndomains * sizeof(*domains)); 451 if (domains == NULL) { 452 warnx("alloc domains space failed."); 453 ret = -1; 454 goto errdomains; 455 } 456 457 for (i = 0, j = 0; i < ncpusets; i++) { 458 if (flg[i]) 459 continue; 460 domains[j] = bitmask_alloc(cpus_nbits); 461 if (cpuset_getcpus(cpusets[i], domains[j])) { 462 warnx("cpuset getcpus failed."); 463 ret = -1; 464 goto errgetdomains; 465 } 466 j++; 467 } 468 goto errdomains; 469 470 errgetdomains: 471 for (i = 0; i < j; i++) 472 bitmask_free(domains[i]); 473 free(domains); 474 domains = NULL; 475 errdomains: 476 free(flg); 477 errfindcpusets: 478 for (i = 0; i < ncpusets; i++) 479 cpuset_free(cpusets[i]); 480 free(cpusets); 481 cpusets = NULL; 482 ncpusets = 0; 483 errcpusets: 484 bitmask_free(cpusc); 485 errcpusc: 486 bitmask_free(cpusb); 487 errcpusb: 488 bitmask_free(cpusa); 489 return ret; 490 } 491 492 #endif 493