1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * lgroup interface 29 */ 30 #include <errno.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <strings.h> 34 #include <unistd.h> 35 #include <sys/bitmap.h> 36 #include <sys/pset.h> 37 #include <sys/types.h> 38 39 #include <sys/lgrp_user.h> 40 41 42 /* 43 * Fast trap for getting home lgroup of current thread 44 */ 45 extern lgrp_id_t _lgrp_home_fast(void); 46 47 /* 48 * lgroup system call 49 */ 50 extern int _lgrpsys(int subcode, long arg, void *ap); 51 52 static int lgrp_cpus_hier(lgrp_snapshot_header_t *snap, lgrp_id_t lgrp, 53 processorid_t **cpuids, uint_t *count); 54 55 56 /* 57 * Get generation ID of lgroup hierarchy given view 58 * which changes whenever the hierarchy changes (eg. DR or pset contents 59 * change for caller's view) 60 */ 61 static lgrp_gen_t 62 lgrp_generation(lgrp_view_t view) 63 { 64 return (_lgrpsys(LGRP_SYS_GENERATION, view, NULL)); 65 } 66 67 68 /* 69 * Get supported revision number of lgroup interface 70 */ 71 int 72 lgrp_version(int version) 73 { 74 return (_lgrpsys(LGRP_SYS_VERSION, version, NULL)); 75 } 76 77 78 /* 79 * Get affinity for given lgroup 80 */ 81 lgrp_affinity_t 82 lgrp_affinity_get(idtype_t idtype, id_t id, lgrp_id_t lgrp) 83 { 84 lgrp_affinity_args_t args; 85 86 args.idtype = idtype; 87 args.id = id; 88 args.lgrp = lgrp; 89 return (_lgrpsys(LGRP_SYS_AFFINITY_GET, 0, (void *)&args)); 90 } 91 92 93 /* 94 * Set affinity for given lgroup 95 */ 96 int 97 lgrp_affinity_set(idtype_t idtype, id_t id, lgrp_id_t lgrp, 98 lgrp_affinity_t aff) 99 { 100 lgrp_affinity_args_t args; 101 102 args.idtype = idtype; 103 args.id = id; 104 args.lgrp = lgrp; 105 args.aff = aff; 106 return (_lgrpsys(LGRP_SYS_AFFINITY_SET, 0, (void *)&args)); 107 } 108 109 110 /* 111 * Get home lgroup for given process or thread 112 */ 113 lgrp_id_t 114 lgrp_home(idtype_t idtype, id_t id) 115 { 116 /* 117 * Use fast trap to get home lgroup of current thread or process 118 * Otherwise, use system call for other process or thread 119 */ 120 if (id == P_MYID && (idtype == P_LWPID || idtype == P_PID)) 121 return (_lgrp_home_fast()); 122 else 123 return (_lgrpsys(LGRP_SYS_HOME, idtype, (void *)(intptr_t)id)); 124 } 125 126 127 /* 128 * Get a snapshot of the lgroup hierarchy 129 */ 130 static int 131 lgrp_snapshot(void *buf, size_t bufsize) 132 { 133 return (_lgrpsys(LGRP_SYS_SNAPSHOT, bufsize, buf)); 134 } 135 136 137 /* 138 * Find any orphan lgroups without parents and make them be children of 139 * root lgroup 140 */ 141 static int 142 parent_orphans(lgrp_snapshot_header_t *snap) 143 { 144 int i; 145 lgrp_info_t *lgrp_info; 146 int nlgrpsmax; 147 int orphan; 148 lgrp_info_t *root; 149 ulong_t *parents; 150 151 if (snap == NULL || snap->ss_info == NULL || 152 snap->ss_parents == NULL || snap->ss_root < 0 || 153 snap->ss_root >= snap->ss_nlgrps_max) 154 return (-1); 155 156 nlgrpsmax = snap->ss_nlgrps_max; 157 root = &snap->ss_info[snap->ss_root]; 158 159 for (i = 0; i < nlgrpsmax; i++) { 160 int j; 161 162 /* 163 * Skip root lgroup 164 */ 165 if (i == snap->ss_root) 166 continue; 167 168 lgrp_info = &snap->ss_info[i]; 169 if (lgrp_info == NULL || lgrp_info->info_lgrpid == LGRP_NONE) 170 continue; 171 172 /* 173 * Make sure parents bitmap is setup 174 */ 175 if (lgrp_info->info_parents == NULL) 176 lgrp_info->info_parents = 177 (ulong_t *)((uintptr_t)snap->ss_parents + 178 (i * BT_SIZEOFMAP(nlgrpsmax))); 179 180 /* 181 * Look for orphans (lgroups with no parents) 182 */ 183 orphan = 1; 184 parents = lgrp_info->info_parents; 185 for (j = 0; j < BT_BITOUL(nlgrpsmax); j++) 186 if (parents[j] != 0) { 187 orphan = 0; 188 break; 189 } 190 191 /* 192 * Make root be parent of any orphans 193 */ 194 if (orphan) { 195 BT_SET(parents, root->info_lgrpid); 196 if (root->info_children) { 197 BT_SET(root->info_children, i); 198 } 199 } 200 } 201 202 return (0); 203 } 204 205 206 /* 207 * Remove given lgroup from parent lgroup(s) 208 */ 209 static void 210 prune_child(lgrp_snapshot_header_t *snap, lgrp_id_t lgrp) 211 { 212 int i; 213 lgrp_info_t *lgrp_info; 214 ulong_t *parents; 215 216 if (snap == NULL || lgrp < 0 || lgrp > snap->ss_nlgrps_max) 217 return; 218 219 lgrp_info = &snap->ss_info[lgrp]; 220 221 parents = lgrp_info->info_parents; 222 if (parents == NULL) 223 return; 224 225 /* 226 * Update children of parents not to include given lgroup 227 */ 228 for (i = 0; i < snap->ss_nlgrps_max; i++) { 229 if (BT_TEST(parents, i)) { 230 lgrp_info = &snap->ss_info[i]; 231 BT_CLEAR(lgrp_info->info_children, lgrp); 232 } 233 } 234 } 235 236 /* 237 * Prune any CPUs not in given array from specified lgroup 238 */ 239 static void 240 prune_cpus(lgrp_snapshot_header_t *snap, lgrp_id_t lgrp, processorid_t *cpus, 241 int ncpus) 242 { 243 int count; 244 int i; 245 int j; 246 int k; 247 lgrp_info_t *lgrp_info; 248 uint_t lgrp_ncpus; 249 processorid_t *lgrp_cpus; 250 251 if (snap == NULL || lgrp < 0 || lgrp > snap->ss_nlgrps_max) 252 return; 253 254 lgrp_info = &snap->ss_info[lgrp]; 255 256 /* 257 * No CPUs to remove 258 */ 259 if (ncpus == 0 || lgrp_info->info_ncpus == 0) 260 return; 261 262 /* 263 * Remove all CPUs from lgroup 264 */ 265 if (cpus == NULL && ncpus == -1) { 266 lgrp_info->info_ncpus = 0; 267 return; 268 } 269 270 /* 271 * Remove any CPUs from lgroup not in given list of CPUs 272 */ 273 lgrp_cpus = lgrp_info->info_cpuids; 274 lgrp_ncpus = lgrp_info->info_ncpus; 275 i = 0; 276 for (count = 0; count < lgrp_ncpus; count++) { 277 /* 278 * Look for CPU in list 279 */ 280 for (j = 0; j < ncpus; j++) 281 if (lgrp_cpus[i] == cpus[j]) 282 break; 283 284 /* 285 * Go to next CPU if found this one in list 286 */ 287 if (j < ncpus) { 288 i++; 289 continue; 290 } 291 292 /* 293 * Remove this CPU and shift others into its place 294 * and decrement number of CPUs 295 */ 296 for (k = i + 1; k < lgrp_info->info_ncpus; k++) 297 lgrp_cpus[k - 1] = lgrp_cpus[k]; 298 lgrp_cpus[k - 1] = -1; 299 lgrp_info->info_ncpus--; 300 } 301 } 302 303 304 /* 305 * Prune lgroup hierarchy for caller's view 306 */ 307 static int 308 prune_tree(lgrp_snapshot_header_t *snap) 309 { 310 processorid_t *cpus; 311 int i; 312 lgrp_info_t *lgrp_info; 313 lgrp_mem_size_t nbytes; 314 uint_t ncpus; 315 int nlgrps_max; 316 317 if (snap == NULL || snap->ss_info == NULL) 318 return (-1); 319 320 /* 321 * Get CPUs in caller's pset 322 */ 323 if (pset_info(PS_MYID, NULL, &ncpus, NULL) == -1) 324 return (-1); 325 326 cpus = NULL; 327 if (ncpus > 0) { 328 cpus = malloc(ncpus * sizeof (processorid_t)); 329 if (pset_info(PS_MYID, NULL, &ncpus, cpus) == -1) { 330 free(cpus); 331 return (-1); 332 } 333 } 334 335 /* 336 * Remove any CPUs not in caller's pset from lgroup hierarchy 337 */ 338 nlgrps_max = snap->ss_nlgrps_max; 339 for (i = 0; i < nlgrps_max; i++) { 340 lgrp_info = &snap->ss_info[i]; 341 if (BT_TEST(snap->ss_lgrpset, i)) 342 prune_cpus(snap, i, cpus, ncpus); 343 else if (lgrp_info->info_lgrpid != LGRP_NONE) 344 prune_cpus(snap, i, NULL, -1); 345 } 346 347 if (ncpus > 0) 348 free(cpus); 349 350 /* 351 * Change lgroup bitmask from just reflecting lgroups overlapping 352 * caller's pset to all lgroups available to caller, starting by 353 * filling in all lgroups and then removing any empty ones below 354 */ 355 for (i = 0; i < nlgrps_max; i++) { 356 lgrp_info = &snap->ss_info[i]; 357 if (lgrp_info->info_lgrpid == LGRP_NONE) 358 continue; 359 360 BT_SET(snap->ss_lgrpset, i); 361 } 362 363 /* 364 * Remove empty lgroups from lgroup hierarchy, removing it from its 365 * parents and decrementing nlgrps 366 */ 367 for (i = 0; i < nlgrps_max; i++) { 368 lgrp_info = &snap->ss_info[i]; 369 if (lgrp_info->info_lgrpid == LGRP_NONE) 370 continue; 371 372 ncpus = lgrp_cpus_hier(snap, i, NULL, NULL); 373 nbytes = lgrp_mem_size((lgrp_cookie_t)snap, i, 374 LGRP_MEM_SZ_INSTALLED, LGRP_CONTENT_HIERARCHY); 375 if (ncpus == 0 && nbytes == 0) { 376 BT_CLEAR(snap->ss_lgrpset, i); 377 prune_child(snap, i); 378 snap->ss_nlgrps--; 379 } 380 } 381 382 return (0); 383 } 384 385 386 /* 387 * Initialize lgroup interface 388 */ 389 lgrp_cookie_t 390 lgrp_init(lgrp_view_t view) 391 { 392 ssize_t bufsize; 393 uint_t gen; 394 int i; 395 lgrp_snapshot_header_t *snap; 396 397 /* 398 * Check for legal view 399 */ 400 if (view != LGRP_VIEW_OS && view != LGRP_VIEW_CALLER) { 401 errno = EINVAL; 402 return (LGRP_COOKIE_NONE); 403 } 404 405 /* 406 * Try to take a consistent snapshot of lgroup hierarchy 407 */ 408 snap = NULL; 409 while (snap == NULL) { 410 /* 411 * Get lgroup generation number before taking snapshot 412 */ 413 gen = lgrp_generation(view); 414 415 /* 416 * Get size of buffer needed for snapshot 417 */ 418 bufsize = lgrp_snapshot(NULL, 0); 419 if (bufsize <= 0) { 420 if (errno == ENOMEM) 421 return (LGRP_COOKIE_NONE); 422 423 snap = NULL; 424 continue; 425 } 426 427 /* 428 * Allocate buffer 429 */ 430 snap = malloc(bufsize); 431 if (snap == NULL) 432 return (LGRP_COOKIE_NONE); 433 bzero(snap, bufsize); 434 435 /* 436 * Take snapshot of lgroup hierarchy 437 */ 438 bufsize = lgrp_snapshot(snap, bufsize); 439 if (bufsize <= 0) { 440 free(snap); 441 if (errno == ENOMEM) 442 return (LGRP_COOKIE_NONE); 443 444 snap = NULL; 445 continue; 446 } 447 448 /* 449 * See whether lgroup generation number changed 450 */ 451 if (gen == lgrp_generation(view)) 452 break; 453 454 free(snap); 455 snap = NULL; 456 } 457 458 /* 459 * Remember generation number and view of this snapshot 460 */ 461 snap->ss_gen = gen; 462 snap->ss_view = view; 463 464 /* 465 * Keep caller's pset ID for caller's view 466 */ 467 snap->ss_pset = 0; 468 if (view == LGRP_VIEW_CALLER) { 469 psetid_t pset; 470 471 if (pset_bind(PS_QUERY, P_LWPID, P_MYID, &pset) == -1) 472 return ((uintptr_t)-1); 473 474 snap->ss_pset = pset; 475 } 476 477 /* 478 * Find any orphan lgroups without parents and make them be children 479 * of the root lgroup 480 */ 481 if (snap->ss_levels > 1) 482 (void) parent_orphans(snap); 483 484 /* 485 * Prune snapshot of lgroup hierarchy for caller's view 486 */ 487 if (view == LGRP_VIEW_CALLER) 488 (void) prune_tree(snap); 489 else { 490 /* 491 * Change lgroup bitmask from just reflecting lgroups 492 * overlapping caller's pset to all lgroups available 493 */ 494 for (i = 0; i < snap->ss_nlgrps_max; i++) { 495 lgrp_info_t *lgrp_info; 496 497 lgrp_info = &snap->ss_info[i]; 498 if (lgrp_info->info_lgrpid == LGRP_NONE) 499 continue; 500 501 BT_SET(snap->ss_lgrpset, i); 502 } 503 } 504 505 return ((uintptr_t)snap); 506 } 507 508 509 /* 510 * Return whether given cookie is out-of-date (stale) or not 511 */ 512 int 513 lgrp_cookie_stale(lgrp_cookie_t cookie) 514 { 515 psetid_t pset; 516 lgrp_snapshot_header_t *snap; 517 518 /* 519 * Check for bad cookie 520 */ 521 snap = (lgrp_snapshot_header_t *)cookie; 522 if (snap == NULL || snap->ss_magic != cookie) { 523 errno = EINVAL; 524 return (-1); 525 } 526 527 /* 528 * Check generation number which changes when lgroup hierarchy changes 529 * or pset contents change for caller's view 530 */ 531 if (snap->ss_gen != lgrp_generation(snap->ss_view)) 532 return (1); 533 534 /* 535 * See whether pset binding has changed for caller's view 536 */ 537 if (snap->ss_view == LGRP_VIEW_CALLER) { 538 if (pset_bind(PS_QUERY, P_LWPID, P_MYID, &pset) == -1) 539 return (-1); 540 if (snap->ss_pset != pset) 541 return (1); 542 } 543 544 return (0); /* cookie isn't stale */ 545 } 546 547 548 /* 549 * Get view of lgroup hierarchy from snapshot represented by given cookie 550 */ 551 lgrp_view_t 552 lgrp_view(lgrp_cookie_t cookie) 553 { 554 lgrp_snapshot_header_t *snap; 555 556 snap = (lgrp_snapshot_header_t *)cookie; 557 if (snap == NULL || snap->ss_magic != cookie) { 558 errno = EINVAL; 559 return (-1); 560 } 561 562 return (snap->ss_view); 563 } 564 565 566 /* 567 * Get number of lgroups 568 */ 569 int 570 lgrp_nlgrps(lgrp_cookie_t cookie) 571 { 572 lgrp_snapshot_header_t *snap; 573 574 snap = (lgrp_snapshot_header_t *)cookie; 575 576 if (snap == NULL || snap->ss_magic != cookie) { 577 errno = EINVAL; 578 return (-1); 579 } 580 581 return (snap->ss_nlgrps); 582 } 583 584 585 /* 586 * Return root lgroup ID 587 */ 588 lgrp_id_t 589 lgrp_root(lgrp_cookie_t cookie) 590 { 591 lgrp_snapshot_header_t *snap; 592 593 snap = (lgrp_snapshot_header_t *)cookie; 594 595 if (snap == NULL || snap->ss_magic != cookie) { 596 errno = EINVAL; 597 return (-1); 598 } 599 600 return (snap->ss_root); 601 } 602 603 604 /* 605 * Get parent lgroups of given lgroup 606 */ 607 int 608 lgrp_parents(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_id_t *parents, 609 uint_t count) 610 { 611 int i; 612 ulong_t *lgrp_parents; 613 lgrp_snapshot_header_t *snap; 614 int nlgrps_max; 615 int nparents; 616 617 snap = (lgrp_snapshot_header_t *)cookie; 618 619 /* 620 * Check for valid arguments 621 */ 622 if (snap == NULL || snap->ss_magic != cookie || 623 lgrp < 0 || lgrp == LGRP_NONE) { 624 errno = EINVAL; 625 return (-1); 626 } 627 628 /* 629 * See whether given lgroup exists 630 */ 631 nlgrps_max = snap->ss_nlgrps_max; 632 if (lgrp >= nlgrps_max || !BT_TEST(snap->ss_lgrpset, lgrp)) { 633 errno = ESRCH; 634 return (-1); 635 } 636 637 /* 638 * No parents, since given lgroup is root lgroup or 639 * only one level in lgroup hierarchy (ie. SMP) 640 */ 641 if (lgrp == snap->ss_root || snap->ss_levels == 1) { 642 if (parents == NULL || count < 1) 643 return (0); 644 return (0); 645 } 646 647 /* 648 * Make sure that parents exist 649 */ 650 if (snap->ss_parents == NULL) { 651 errno = ESRCH; 652 return (-1); 653 } 654 655 /* 656 * Given lgroup should have a parent 657 */ 658 lgrp_parents = &snap->ss_parents[lgrp * BT_BITOUL(nlgrps_max)]; 659 if (lgrp_parents == NULL) { 660 errno = ESRCH; 661 return (-1); 662 } 663 664 /* 665 * Check lgroup parents bitmask, fill in parents array, and return 666 * number of parents 667 */ 668 nparents = 0; 669 for (i = 0; i < nlgrps_max; i++) { 670 if (BT_TEST(lgrp_parents, i)) { 671 if (parents != NULL && nparents < count) { 672 parents[nparents] = i; 673 } 674 nparents++; 675 } 676 } 677 return (nparents); 678 } 679 680 681 /* 682 * Get children lgroups of given lgroup 683 */ 684 int 685 lgrp_children(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_id_t *children, 686 uint_t count) 687 { 688 int i; 689 ulong_t *lgrp_children; 690 int nlgrps_max; 691 int nchildren; 692 lgrp_snapshot_header_t *snap; 693 694 snap = (lgrp_snapshot_header_t *)cookie; 695 696 /* 697 * Check for valid arguments 698 */ 699 if (snap == NULL || snap->ss_magic != cookie || 700 lgrp < 0 || lgrp == LGRP_NONE) { 701 errno = EINVAL; 702 return (-1); 703 } 704 705 /* 706 * See whether given lgroup exists 707 */ 708 nlgrps_max = snap->ss_nlgrps_max; 709 if (lgrp >= nlgrps_max || !BT_TEST(snap->ss_lgrpset, lgrp)) { 710 errno = ESRCH; 711 return (-1); 712 } 713 714 /* 715 * No children, since only one level in lgroup hierarchy (ie. SMP) 716 */ 717 if (snap->ss_levels == 1) { 718 if (children == NULL || count < 1) 719 return (0); 720 return (0); 721 } 722 723 /* 724 * Make sure that children exist 725 */ 726 if (snap->ss_children == NULL) { 727 errno = ESRCH; 728 return (-1); 729 } 730 731 /* 732 * Given lgroup may not have any children 733 */ 734 lgrp_children = &snap->ss_children[lgrp * BT_BITOUL(nlgrps_max)]; 735 736 if (lgrp_children == NULL) 737 return (0); 738 739 /* 740 * Check lgroup children bitmask, fill in children array, and return 741 * number of children 742 */ 743 nchildren = 0; 744 for (i = 0; i < nlgrps_max; i++) { 745 if (BT_TEST(lgrp_children, i)) { 746 if (children != NULL && nchildren < count) 747 children[nchildren] = i; 748 nchildren++; 749 } 750 } 751 return (nchildren); 752 } 753 754 755 /* 756 * Get all CPUs within given lgroup (hierarchy) 757 */ 758 static int 759 lgrp_cpus_hier(lgrp_snapshot_header_t *snap, lgrp_id_t lgrp, 760 processorid_t **cpuids, uint_t *count) 761 { 762 processorid_t *cpus; 763 int i; 764 int j; 765 lgrp_info_t *lgrp_info; 766 int ncpus; 767 int nlgrps_max; 768 ulong_t *rset; 769 int total; 770 771 /* 772 * Get lgroup info 773 */ 774 lgrp_info = &snap->ss_info[lgrp]; 775 776 if (lgrp_info == NULL) { 777 errno = ESRCH; 778 return (-1); 779 } 780 781 /* 782 * Check whether given lgroup contains any lgroups with CPU resources 783 */ 784 if (lgrp_info->info_rset == NULL) 785 return (0); 786 787 nlgrps_max = snap->ss_nlgrps_max; 788 rset = &lgrp_info->info_rset[LGRP_RSRC_CPU * BT_BITOUL(nlgrps_max)]; 789 790 /* 791 * Get all CPUs within this lgroup 792 */ 793 total = 0; 794 for (i = 0; i < nlgrps_max; i++) { 795 if (!BT_TEST(rset, i)) 796 continue; 797 798 lgrp_info = &snap->ss_info[i]; 799 800 /* 801 * Get all CPUs within lgroup 802 */ 803 cpus = lgrp_info->info_cpuids; 804 ncpus = lgrp_info->info_ncpus; 805 total += ncpus; 806 807 /* 808 * Copy as many CPU IDs into array that will fit 809 * and decrement count and increment array pointer 810 * as we go 811 */ 812 if (cpuids && *cpuids && count) { 813 for (j = 0; j < ncpus; j++) { 814 if (*count) { 815 **cpuids = cpus[j]; 816 (*cpuids)++; 817 (*count)--; 818 } 819 } 820 } 821 } 822 823 return (total); 824 } 825 826 827 /* 828 * Get CPUs in given lgroup 829 */ 830 int 831 lgrp_cpus(lgrp_cookie_t cookie, lgrp_id_t lgrp, processorid_t *cpuids, 832 uint_t count, lgrp_content_t content) 833 { 834 int i; 835 processorid_t *cpus; 836 lgrp_info_t *lgrp_info; 837 int ncpus; 838 lgrp_snapshot_header_t *snap; 839 840 snap = (lgrp_snapshot_header_t *)cookie; 841 842 /* 843 * Check for valid arguments 844 */ 845 if (snap == NULL || snap->ss_magic != cookie || 846 lgrp < 0 || lgrp == LGRP_NONE || 847 (content != LGRP_CONTENT_DIRECT && 848 content != LGRP_CONTENT_HIERARCHY)) { 849 errno = EINVAL; 850 return (-1); 851 } 852 853 /* 854 * See whether given lgroup exists 855 */ 856 if (lgrp >= snap->ss_nlgrps_max || snap->ss_info == NULL || 857 !BT_TEST(snap->ss_lgrpset, lgrp)) { 858 errno = ESRCH; 859 return (-1); 860 } 861 862 /* 863 * Get lgroup info 864 */ 865 lgrp_info = &snap->ss_info[lgrp]; 866 867 /* 868 * Get contents of lgroup 869 */ 870 switch (content) { 871 case LGRP_CONTENT_DIRECT: 872 /* 873 * Get CPUs contained directly within given lgroup 874 */ 875 cpus = lgrp_info->info_cpuids; 876 ncpus = lgrp_info->info_ncpus; 877 878 /* 879 * No array to copy CPU IDs into, 880 * so just return number of CPUs. 881 */ 882 if (cpuids == NULL) 883 return (ncpus); 884 885 /* 886 * Copy as many CPU IDs into array that will fit 887 */ 888 for (i = 0; i < ncpus; i++) 889 if (i < count) 890 cpuids[i] = cpus[i]; 891 892 return (ncpus); 893 894 case LGRP_CONTENT_ALL: 895 return (lgrp_cpus_hier(snap, lgrp, &cpuids, &count)); 896 897 default: 898 errno = EINVAL; 899 return (-1); 900 } 901 } 902 903 904 /* 905 * Return physical memory size in pages for given lgroup 906 */ 907 lgrp_mem_size_t 908 lgrp_mem_size(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_mem_size_flag_t type, 909 lgrp_content_t content) 910 { 911 int i; 912 lgrp_info_t *lgrp_info; 913 int nlgrps_max; 914 int pgsz; 915 ulong_t *rset; 916 lgrp_mem_size_t size; 917 lgrp_snapshot_header_t *snap; 918 919 snap = (lgrp_snapshot_header_t *)cookie; 920 921 /* 922 * Check for valid arguments 923 */ 924 if (snap == NULL || snap->ss_magic != cookie || 925 lgrp < 0 || lgrp == LGRP_NONE) { 926 errno = EINVAL; 927 return (-1); 928 } 929 930 /* 931 * See whether given lgroup exists 932 */ 933 nlgrps_max = snap->ss_nlgrps_max; 934 if (lgrp >= nlgrps_max || snap->ss_info == NULL || 935 !BT_TEST(snap->ss_lgrpset, lgrp)) { 936 errno = ESRCH; 937 return (-1); 938 } 939 940 pgsz = getpagesize(); 941 942 /* 943 * Get lgroup info 944 */ 945 lgrp_info = &snap->ss_info[lgrp]; 946 947 switch (content) { 948 case LGRP_CONTENT_DIRECT: 949 /* 950 * Get memory contained directly in this lgroup 951 */ 952 switch (type) { 953 case LGRP_MEM_SZ_FREE: 954 size = (lgrp_mem_size_t)pgsz * 955 lgrp_info->info_mem_free; 956 return (size); 957 case LGRP_MEM_SZ_INSTALLED: 958 size = (lgrp_mem_size_t)pgsz * 959 lgrp_info->info_mem_install; 960 return (size); 961 default: 962 errno = EINVAL; 963 return (-1); 964 } 965 966 case LGRP_CONTENT_ALL: 967 /* 968 * Get memory contained within this lgroup (and its children) 969 */ 970 /* 971 * Check whether given lgroup contains any lgroups with CPU 972 * resources 973 */ 974 if (lgrp_info->info_rset == NULL) 975 return (0); 976 977 rset = &lgrp_info->info_rset[LGRP_RSRC_MEM * 978 BT_BITOUL(nlgrps_max)]; 979 980 /* 981 * Add up memory in lgroup resources 982 */ 983 size = 0; 984 for (i = 0; i < nlgrps_max; i++) { 985 if (!BT_TEST(rset, i)) 986 continue; 987 988 lgrp_info = &snap->ss_info[i]; 989 switch (type) { 990 case LGRP_MEM_SZ_FREE: 991 size += (lgrp_mem_size_t)pgsz * 992 lgrp_info->info_mem_free; 993 break; 994 case LGRP_MEM_SZ_INSTALLED: 995 size += (lgrp_mem_size_t)pgsz * 996 lgrp_info->info_mem_install; 997 break; 998 default: 999 errno = EINVAL; 1000 return (-1); 1001 } 1002 1003 } 1004 1005 return (size); 1006 1007 default: 1008 errno = EINVAL; 1009 return (-1); 1010 } 1011 } 1012 1013 1014 /* 1015 * Get resources for a particuliar lgroup 1016 */ 1017 int 1018 lgrp_resources(lgrp_cookie_t cookie, lgrp_id_t lgrp, lgrp_id_t *lgrps, 1019 uint_t count, lgrp_rsrc_t type) 1020 { 1021 int i; 1022 lgrp_info_t *lgrp_info; 1023 int nlgrps; 1024 int nlgrps_max; 1025 ulong_t *rset; 1026 lgrp_snapshot_header_t *snap; 1027 1028 snap = (lgrp_snapshot_header_t *)cookie; 1029 1030 /* 1031 * Check for valid arguments 1032 */ 1033 if (snap == NULL || snap->ss_magic != cookie || 1034 lgrp < 0 || lgrp == LGRP_NONE || 1035 (type != LGRP_RSRC_CPU && type != LGRP_RSRC_MEM)) { 1036 errno = EINVAL; 1037 return (-1); 1038 } 1039 1040 /* 1041 * See whether given lgroup exists 1042 */ 1043 nlgrps_max = snap->ss_nlgrps_max; 1044 if (lgrp >= nlgrps_max || snap->ss_info == NULL || 1045 !BT_TEST(snap->ss_lgrpset, lgrp)) { 1046 errno = ESRCH; 1047 return (-1); 1048 } 1049 1050 /* 1051 * Get lgroup info 1052 */ 1053 lgrp_info = &snap->ss_info[lgrp]; 1054 1055 /* 1056 * Count number lgroups contained within this lgroup and 1057 * copy as many lgroup IDs into array that will fit 1058 */ 1059 rset = &lgrp_info->info_rset[type * BT_BITOUL(nlgrps_max)]; 1060 nlgrps = 0; 1061 for (i = 0; i < snap->ss_nlgrps_max; i++) 1062 if (BT_TEST(rset, i)) { 1063 if (lgrps != NULL && nlgrps < count) 1064 lgrps[nlgrps] = i; 1065 nlgrps++; 1066 } 1067 1068 return (nlgrps); 1069 } 1070 1071 1072 /* 1073 * Finish using lgroup interface 1074 */ 1075 int 1076 lgrp_fini(lgrp_cookie_t cookie) 1077 { 1078 lgrp_snapshot_header_t *snap; 1079 1080 snap = (lgrp_snapshot_header_t *)cookie; 1081 1082 if (snap == NULL || snap->ss_magic != cookie) { 1083 errno = EINVAL; 1084 return (-1); 1085 } 1086 1087 bzero(snap, snap->ss_size); 1088 free(snap); 1089 snap = NULL; 1090 1091 return (0); 1092 } 1093 1094 1095 /* 1096 * Return latency between "from" and "to" lgroups 1097 * 1098 * This latency number can only be used for relative comparison 1099 * between lgroups on the running system, cannot be used across platforms, 1100 * and may not reflect the actual latency. It is platform and implementation 1101 * specific, so platform gets to decide its value. It would be nice if the 1102 * number was at least proportional to make comparisons more meaningful though. 1103 */ 1104 int 1105 lgrp_latency(lgrp_id_t from, lgrp_id_t to) 1106 { 1107 lgrp_cookie_t cookie; 1108 int latency; 1109 1110 cookie = lgrp_init(LGRP_VIEW_OS); 1111 latency = lgrp_latency_cookie(cookie, from, to, LGRP_LAT_CPU_TO_MEM); 1112 (void) lgrp_fini(cookie); 1113 1114 return (latency); 1115 } 1116 1117 1118 /* 1119 * Return latency between "from" and "to" lgroups 1120 * 1121 * This latency number can only be used for relative comparison 1122 * between lgroups on the running system, cannot be used across platforms, 1123 * and may not reflect the actual latency. It is platform and implementation 1124 * specific, so platform gets to decide its value. It would be nice if the 1125 * number was at least proportional to make comparisons more meaningful though. 1126 */ 1127 int 1128 lgrp_latency_cookie(lgrp_cookie_t cookie, lgrp_id_t from, lgrp_id_t to, 1129 lgrp_lat_between_t between) 1130 { 1131 lgrp_info_t *lgrp_info; 1132 lgrp_mem_size_t nbytes; 1133 int ncpus; 1134 int nlgrps_max; 1135 lgrp_snapshot_header_t *snap; 1136 1137 snap = (lgrp_snapshot_header_t *)cookie; 1138 1139 /* 1140 * Check for valid snapshot, lgroup, and between flag 1141 */ 1142 if (snap == NULL || snap->ss_magic != cookie || from < 0 || to < 0 || 1143 between != LGRP_LAT_CPU_TO_MEM) { 1144 errno = EINVAL; 1145 return (-1); 1146 } 1147 1148 /* 1149 * Check whether lgroups exist 1150 */ 1151 nlgrps_max = snap->ss_nlgrps_max; 1152 if (from >= nlgrps_max || to >= nlgrps_max) { 1153 errno = ESRCH; 1154 return (-1); 1155 } 1156 1157 /* 1158 * Check whether "from" lgroup has any CPUs 1159 */ 1160 ncpus = lgrp_cpus(cookie, from, NULL, 0, LGRP_CONTENT_HIERARCHY); 1161 if (ncpus <= 0) { 1162 if (ncpus == 0) 1163 errno = ESRCH; 1164 return (-1); 1165 } 1166 1167 /* 1168 * Check whether "to" lgroup has any memory 1169 */ 1170 nbytes = lgrp_mem_size(cookie, to, LGRP_MEM_SZ_INSTALLED, 1171 LGRP_CONTENT_HIERARCHY); 1172 if (nbytes <= 0) { 1173 if (nbytes == 0) 1174 errno = ESRCH; 1175 return (-1); 1176 } 1177 1178 if (from == to) { 1179 lgrp_info = &snap->ss_info[from]; 1180 return (lgrp_info->info_latency); 1181 } 1182 1183 return (snap->ss_latencies[from][to]); 1184 } 1185