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