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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2006 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 #include "lgrp.h" 30 31 #include <mdb/mdb_modapi.h> 32 #include <sys/cpuvar.h> 33 #include <sys/lgrp.h> 34 #include <sys/cpupart.h> 35 36 int 37 print_range(int start, int end, int separator) 38 { 39 int count; 40 char tmp; 41 char *format; 42 43 if (start == end) { 44 /* Unfortunately, mdb_printf returns void */ 45 format = separator ? ", %d" : "%d"; 46 mdb_printf(format, start); 47 count = mdb_snprintf(&tmp, 1, format, start); 48 } else { 49 format = separator ? ", %d-%d" : "%d-%d"; 50 mdb_printf(format, start, end); 51 count = mdb_snprintf(&tmp, 1, format, start, end); 52 } 53 54 return (count); 55 } 56 57 void 58 print_cpuset_range(ulong_t *cs, int words, int width) 59 { 60 int i, j; 61 ulong_t m; 62 int in = 0; 63 int start; 64 int end; 65 int count = 0; 66 int sep = 0; 67 68 for (i = 0; i < words; i++) 69 for (j = 0, m = 1; j < BT_NBIPUL; j++, m <<= 1) 70 if (cs[i] & m) { 71 if (in == 0) { 72 start = i * BT_NBIPUL + j; 73 in = 1; 74 } 75 } else { 76 if (in == 1) { 77 end = i * BT_NBIPUL + j - 1; 78 count += print_range(start, end, sep); 79 sep = 1; 80 in = 0; 81 } 82 } 83 if (in == 1) { 84 end = i * BT_NBIPUL - 1; 85 count += print_range(start, end, sep); 86 } 87 88 /* 89 * print width - count spaces 90 */ 91 92 if (width > count) 93 mdb_printf("%*s", width - count, ""); 94 } 95 typedef struct lgrp_cpu_walk { 96 uintptr_t lcw_firstcpu; 97 int lcw_cpusleft; 98 } lgrp_cpu_walk_t; 99 100 int 101 lgrp_cpulist_walk_init(mdb_walk_state_t *wsp) 102 { 103 lgrp_cpu_walk_t *lcw; 104 lgrp_t lgrp; 105 106 lcw = mdb_alloc(sizeof (lgrp_cpu_walk_t), UM_SLEEP | UM_GC); 107 108 if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) { 109 mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr); 110 return (WALK_ERR); 111 } 112 113 lcw->lcw_firstcpu = (uintptr_t)lgrp.lgrp_cpu; 114 lcw->lcw_cpusleft = lgrp.lgrp_cpucnt; 115 116 wsp->walk_data = lcw; 117 wsp->walk_addr = lcw->lcw_firstcpu; 118 119 return (WALK_NEXT); 120 } 121 122 int 123 lgrp_cpulist_walk_step(mdb_walk_state_t *wsp) 124 { 125 lgrp_cpu_walk_t *lcw = (lgrp_cpu_walk_t *)wsp->walk_data; 126 uintptr_t addr = (uintptr_t)wsp->walk_addr; 127 cpu_t cpu; 128 int status; 129 130 if (lcw->lcw_cpusleft-- == 0) 131 return (WALK_DONE); 132 133 if (mdb_vread(&cpu, sizeof (cpu_t), addr) == -1) { 134 mdb_warn("couldn't read 'cpu' at %p", addr); 135 return (WALK_ERR); 136 } 137 138 status = wsp->walk_callback(addr, &cpu, wsp->walk_cbdata); 139 140 if (status != WALK_NEXT) 141 return (status); 142 143 addr = (uintptr_t)cpu.cpu_next_lgrp; 144 wsp->walk_addr = addr; 145 146 if (lcw->lcw_cpusleft == NULL && addr != lcw->lcw_firstcpu) { 147 mdb_warn("number of cpus in lgroup cpu != lgroup cpucnt\n"); 148 return (WALK_ERR); 149 } 150 151 return (WALK_NEXT); 152 } 153 154 typedef struct lgrp_cpuwalk_cbdata { 155 uint_t lcc_opt_p; 156 uint_t lcc_count; 157 uint_t lcc_used; 158 uint_t *lcc_psrsetid; 159 ulong_t **lcc_cpuset; 160 uint_t *lcc_cpucnt; 161 int *lcc_loadavg; 162 } lgrp_cpuwalk_cbdata_t; 163 164 /* ARGSUSED */ 165 static int 166 lgrp_cpuwalk_callback(uintptr_t addr, const void *arg, void *cb_data) 167 { 168 cpu_t *cpu = (cpu_t *)arg; 169 lgrp_cpuwalk_cbdata_t *lcc = (lgrp_cpuwalk_cbdata_t *)cb_data; 170 uint_t opt_p = lcc->lcc_opt_p; 171 172 int offset = 0; 173 174 /* 175 * if opt_p is set, we're going to break up info for 176 * each lgrp by processor set. 177 */ 178 179 if (opt_p != 0) { 180 cpupartid_t cp_id; 181 cpupart_t cpupart; 182 lpl_t lpl; 183 184 185 if (mdb_vread(&cpupart, sizeof (cpupart_t), 186 (uintptr_t)cpu->cpu_part) == -1) { 187 mdb_warn("cannot read cpu partition at %p", 188 cpu->cpu_part); 189 return (WALK_ERR); 190 } 191 cp_id = cpupart.cp_id; 192 193 for (offset = 0; offset < lcc->lcc_used; offset++) 194 if (cp_id == lcc->lcc_psrsetid[offset]) { 195 goto found; 196 } 197 198 if (offset >= lcc->lcc_count) { 199 mdb_warn( 200 "number of cpu partitions changed during walk"); 201 return (WALK_ERR); 202 } 203 204 lcc->lcc_psrsetid[offset] = cp_id; 205 lcc->lcc_used++; 206 207 if (mdb_vread(&lpl, sizeof (lpl_t), (uintptr_t)cpu->cpu_lpl) 208 == -1) { 209 mdb_warn("Cannot read lpl at %p", cpu->cpu_lpl); 210 return (WALK_ERR); 211 } 212 213 lcc->lcc_loadavg[offset] = lpl.lpl_loadavg; 214 } 215 216 found: lcc->lcc_cpucnt[offset]++; 217 BT_SET(lcc->lcc_cpuset[offset], cpu->cpu_id); 218 219 return (WALK_NEXT); 220 } 221 222 223 /* ARGSUSED */ 224 int 225 lgrp(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 226 { 227 lgrp_t lgrp; 228 lgrp_cpuwalk_cbdata_t lcc; 229 int cpusetsize; 230 int lcpu; /* cpus in lgrp */ 231 int _ncpu; 232 int opt_p = 0; /* display partition fraction loads */ 233 int opt_q = 0; /* display only address. */ 234 int i; 235 const char *s_index = NULL, *s_handle = NULL, *s_parent = NULL; 236 uintptr_t index; 237 uintptr_t handle; 238 uintptr_t parent; 239 int filters = 0; 240 241 if (!(flags & DCMD_ADDRSPEC)) { 242 if (mdb_walk_dcmd("lgrptbl", "lgrp", argc, argv) == -1) { 243 mdb_warn("can't walk 'lgrps'"); 244 return (DCMD_ERR); 245 } 246 return (DCMD_OK); 247 } 248 249 if (mdb_getopts(argc, argv, 250 'p', MDB_OPT_SETBITS, TRUE, &opt_p, 251 'q', MDB_OPT_SETBITS, TRUE, &opt_q, 252 'P', MDB_OPT_STR, &s_parent, 253 'i', MDB_OPT_STR, &s_index, 254 'h', MDB_OPT_STR, &s_handle, 255 NULL) != argc) 256 return (DCMD_USAGE); 257 258 if (s_index != NULL) 259 filters++; 260 if (s_handle != NULL) 261 filters++; 262 if (s_parent != NULL) 263 filters++; 264 265 if (flags & DCMD_PIPE_OUT) 266 opt_q = B_TRUE; 267 268 if (s_index != NULL) 269 index = mdb_strtoull(s_index); 270 271 if (s_parent != NULL) 272 parent = mdb_strtoull(s_parent); 273 274 if (s_handle != NULL) { 275 if (strcmp(s_handle, "NULL") == 0) 276 handle = (uintptr_t)LGRP_NULL_HANDLE; 277 else if (strcmp(s_handle, "DEFAULT") == 0) 278 handle = (uintptr_t)LGRP_DEFAULT_HANDLE; 279 else 280 handle = mdb_strtoull(s_handle); 281 } 282 283 if (DCMD_HDRSPEC(flags) && !opt_q) { 284 if (opt_p == 0) 285 mdb_printf("%9s %?s %?s %?s %9s %9s\n", 286 "LGRPID", 287 "ADDR", 288 "PARENT", 289 "PLATHAND", 290 "#CPU", 291 "CPUS"); 292 else 293 mdb_printf("%9s %9s %9s %9s %9s\n", 294 "LGRPID", 295 "PSRSETID", 296 "LOAD", 297 "#CPU", 298 "CPUS"); 299 } 300 301 if (mdb_vread(&lgrp, sizeof (struct lgrp), addr) == -1) { 302 mdb_warn("unable to read 'lgrp' at %p", addr); 303 return (DCMD_ERR); 304 } 305 306 /* 307 * Do not report free lgrp unless specifically asked for. 308 */ 309 if ((lgrp.lgrp_id == LGRP_NONE) && 310 ((s_index == NULL) || ((int)index != LGRP_NONE))) 311 return (DCMD_OK); 312 313 /* 314 * If lgrp doesn't pass filtering criteria, don't print anything and 315 * just return. 316 */ 317 if (filters) { 318 if ((s_parent != NULL) && 319 parent != (uintptr_t)lgrp.lgrp_parent) 320 return (DCMD_OK); 321 if ((s_index != NULL) && index != (uintptr_t)lgrp.lgrp_id) 322 return (DCMD_OK); 323 if ((s_handle != NULL) && 324 handle != (uintptr_t)lgrp.lgrp_plathand) 325 return (DCMD_OK); 326 } 327 328 if (opt_q) { 329 mdb_printf("%0?p\n", addr); 330 return (DCMD_OK); 331 } 332 333 334 /* 335 * figure out what cpus we've got 336 */ 337 if (mdb_readsym(&_ncpu, sizeof (int), "_ncpu") == -1) { 338 mdb_warn("symbol '_ncpu' not found"); 339 return (DCMD_ERR); 340 } 341 342 /* 343 * allocate enough space for set of longs to hold cpuid bitfield 344 */ 345 if (opt_p) 346 lcpu = lgrp.lgrp_cpucnt; 347 else 348 lcpu = 1; 349 350 cpusetsize = BT_BITOUL(_ncpu) * sizeof (uintptr_t); 351 352 lcc.lcc_used = 0; 353 lcc.lcc_cpucnt = mdb_zalloc(sizeof (uint_t) * lcpu, 354 UM_SLEEP | UM_GC); 355 lcc.lcc_psrsetid = mdb_zalloc(sizeof (uint_t) * lcpu, 356 UM_SLEEP | UM_GC); 357 lcc.lcc_cpuset = mdb_zalloc(sizeof (uintptr_t) * lcpu, 358 UM_SLEEP | UM_GC); 359 for (i = 0; i < lcpu; i++) 360 lcc.lcc_cpuset[i] = mdb_zalloc(cpusetsize, 361 UM_SLEEP | UM_GC); 362 lcc.lcc_loadavg = mdb_zalloc(sizeof (int) * lcpu, 363 UM_SLEEP | UM_GC); 364 lcc.lcc_count = lcpu; 365 lcc.lcc_opt_p = opt_p; 366 367 if (mdb_pwalk("lgrp_cpulist", lgrp_cpuwalk_callback, &lcc, 368 addr) == -1) { 369 mdb_warn("unable to walk lgrp_cpulist"); 370 } 371 372 if (opt_p == 0) { 373 if (lgrp.lgrp_plathand == LGRP_NULL_HANDLE) { 374 mdb_printf("%9d %?p %?p %?s %9d ", 375 lgrp.lgrp_id, 376 addr, 377 lgrp.lgrp_parent, 378 "NULL", 379 lgrp.lgrp_cpucnt); 380 } else if (lgrp.lgrp_plathand == LGRP_DEFAULT_HANDLE) { 381 mdb_printf("%9d %?p %?p %?s %9d ", 382 lgrp.lgrp_id, 383 addr, 384 lgrp.lgrp_parent, 385 "DEFAULT", 386 lgrp.lgrp_cpucnt); 387 } else { 388 mdb_printf("%9d %?p %?p %?p %9d ", 389 lgrp.lgrp_id, 390 addr, 391 lgrp.lgrp_parent, 392 lgrp.lgrp_plathand, 393 lgrp.lgrp_cpucnt); 394 } 395 396 if (lgrp.lgrp_cpucnt != 0) { 397 print_cpuset_range(lcc.lcc_cpuset[0], 398 cpusetsize/sizeof (ulong_t), 0); 399 } 400 mdb_printf("\n"); 401 } else { 402 for (i = 0; i < lcc.lcc_used; i++) { 403 mdb_printf("%9d %9d %9d %9d ", 404 lgrp.lgrp_id, 405 lcc.lcc_psrsetid[i], 406 lcc.lcc_loadavg[i], 407 lcc.lcc_cpucnt[i]); 408 if (lcc.lcc_cpucnt[i]) 409 print_cpuset_range(lcc.lcc_cpuset[i], 410 cpusetsize/sizeof (ulong_t), 0); 411 mdb_printf("\n"); 412 } 413 } 414 return (DCMD_OK); 415 416 } 417 418 typedef struct lgrp_walk_data { 419 int lwd_nlgrps; 420 uintptr_t *lwd_lgrp_tbl; 421 int lwd_iter; 422 } lgrp_walk_data_t; 423 424 int 425 lgrp_walk_init(mdb_walk_state_t *wsp) 426 { 427 lgrp_walk_data_t *lwd; 428 GElf_Sym sym; 429 430 lwd = mdb_zalloc(sizeof (lgrp_walk_data_t), UM_SLEEP | UM_GC); 431 432 if (mdb_readsym(&lwd->lwd_nlgrps, sizeof (int), 433 "lgrp_alloc_max") == -1) { 434 mdb_warn("symbol 'lgrp_alloc_max' not found"); 435 return (WALK_ERR); 436 } 437 438 if (lwd->lwd_nlgrps < 0) { 439 mdb_warn("lgrp_alloc_max of bounds (%d)\n", lwd->lwd_nlgrps); 440 return (WALK_ERR); 441 } 442 443 lwd->lwd_nlgrps++; 444 445 if (mdb_lookup_by_name("lgrp_table", &sym) == -1) { 446 mdb_warn("failed to find 'lgrp_table'"); 447 return (WALK_ERR); 448 } 449 450 /* Get number of valid entries in lgrp_table */ 451 if (sym.st_size < lwd->lwd_nlgrps * sizeof (lgrp_t *)) { 452 mdb_warn("lgrp_table size inconsistent with lgrp_alloc_max"); 453 return (WALK_ERR); 454 } 455 456 lwd->lwd_lgrp_tbl = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC); 457 458 if (mdb_readsym(lwd->lwd_lgrp_tbl, lwd->lwd_nlgrps * sizeof (lgrp_t *), 459 "lgrp_table") == -1) { 460 mdb_warn("unable to read lgrp_table"); 461 return (WALK_ERR); 462 } 463 464 465 wsp->walk_data = lwd; 466 wsp->walk_addr = lwd->lwd_lgrp_tbl[0]; 467 468 return (WALK_NEXT); 469 } 470 471 /* 472 * Common routine for several walkers. 473 * Read lgroup from wsp->walk_addr and call wsp->walk_callback for it. 474 * Normally returns the result of the callback. 475 * Returns WALK_DONE if walk_addr is NULL and WALK_ERR if cannot read the 476 * lgroup. 477 */ 478 static int 479 lgrp_walk_step_common(mdb_walk_state_t *wsp) 480 { 481 lgrp_t lgrp; 482 483 if (wsp->walk_addr == NULL) 484 return (WALK_DONE); 485 486 if (mdb_vread(&lgrp, sizeof (lgrp_t), wsp->walk_addr) == -1) { 487 mdb_warn("unable to read lgrp at %p", wsp->walk_addr); 488 return (WALK_ERR); 489 } 490 491 return (wsp->walk_callback(wsp->walk_addr, &lgrp, wsp->walk_cbdata)); 492 } 493 494 /* 495 * Get one lgroup from the lgroup table and adjust lwd_iter to point to the next 496 * one. 497 */ 498 int 499 lgrp_walk_step(mdb_walk_state_t *wsp) 500 { 501 lgrp_walk_data_t *lwd = wsp->walk_data; 502 int status = lgrp_walk_step_common(wsp); 503 504 if (status == WALK_NEXT) { 505 lwd->lwd_iter++; 506 507 if (lwd->lwd_iter >= lwd->lwd_nlgrps) { 508 status = WALK_DONE; 509 } else { 510 wsp->walk_addr = lwd->lwd_lgrp_tbl[lwd->lwd_iter]; 511 512 if (wsp->walk_addr == NULL) { 513 mdb_warn("NULL lgrp pointer in lgrp_table[%d]", 514 lwd->lwd_iter); 515 return (WALK_ERR); 516 } 517 } 518 } 519 520 return (status); 521 } 522 523 /* 524 * Initialize walker to traverse parents of lgroups. Nothing to do here. 525 */ 526 /* ARGSUSED */ 527 int 528 lgrp_parents_walk_init(mdb_walk_state_t *wsp) 529 { 530 return (WALK_NEXT); 531 } 532 533 /* 534 * Call wsp callback on current lgroup in wsp and replace the lgroup with its 535 * parent. 536 */ 537 int 538 lgrp_parents_walk_step(mdb_walk_state_t *wsp) 539 { 540 lgrp_t lgrp; 541 int status; 542 543 if (wsp->walk_addr == NULL) 544 return (WALK_DONE); 545 546 if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) { 547 mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr); 548 return (WALK_ERR); 549 } 550 551 status = wsp->walk_callback(wsp->walk_addr, &lgrp, wsp->walk_cbdata); 552 553 if (status == WALK_NEXT) 554 wsp->walk_addr = (uintptr_t)lgrp.lgrp_parent; 555 556 return (status); 557 } 558 559 /* 560 * Given the set return the ID of the first member of the set. 561 * Returns LGRP_NONE if the set has no elements smaller than max_lgrp. 562 */ 563 static lgrp_id_t 564 lgrp_set_get_first(klgrpset_t set, int max_lgrp) 565 { 566 lgrp_id_t id; 567 klgrpset_t bit = 1; 568 569 if (set == (klgrpset_t)0) 570 return (LGRP_NONE); 571 572 for (id = 0; (id < max_lgrp) && !(set & bit); id++, bit <<= 1) 573 ; 574 575 if (id >= max_lgrp) 576 id = LGRP_NONE; 577 578 return (id); 579 } 580 581 /* 582 * lgrp_set_walk_data is used to walk lgroups specified by a set. 583 * On every iteration one element is removed from the set. 584 */ 585 typedef struct lgrp_set_walk_data { 586 int lswd_nlgrps; /* Number of lgroups */ 587 uintptr_t *lwsd_lgrp_tbl; /* Full lgroup table */ 588 klgrpset_t lwsd_set; /* Set of lgroups to walk */ 589 } lgrp_set_walk_data_t; 590 591 /* 592 * Initialize iterator for walkers over a set of lgroups 593 */ 594 static int 595 lgrp_set_walk_init(mdb_walk_state_t *wsp, klgrpset_t set) 596 { 597 lgrp_set_walk_data_t *lwsd; 598 int nlgrps; 599 lgrp_id_t id; 600 GElf_Sym sym; 601 602 /* Nothing to do if the set is empty */ 603 if (set == (klgrpset_t)0) 604 return (WALK_DONE); 605 606 lwsd = mdb_zalloc(sizeof (lgrp_set_walk_data_t), UM_SLEEP | UM_GC); 607 608 /* Get the total number of lgroups */ 609 if (mdb_readsym(&nlgrps, sizeof (int), "lgrp_alloc_max") == -1) { 610 mdb_warn("symbol 'lgrp_alloc_max' not found"); 611 return (WALK_ERR); 612 } 613 614 if (nlgrps < 0) { 615 mdb_warn("lgrp_alloc_max of bounds (%d)\n", nlgrps); 616 return (WALK_ERR); 617 } 618 619 nlgrps++; 620 621 /* Find ID of the first lgroup in the set */ 622 if ((id = lgrp_set_get_first(set, nlgrps)) == LGRP_NONE) { 623 mdb_warn("No set elements within %d lgroups\n", nlgrps); 624 return (WALK_ERR); 625 } 626 627 /* Read lgroup_table and copy it to lwsd_lgrp_tbl */ 628 if (mdb_lookup_by_name("lgrp_table", &sym) == -1) { 629 mdb_warn("failed to find 'lgrp_table'"); 630 return (WALK_ERR); 631 } 632 633 /* Get number of valid entries in lgrp_table */ 634 if (sym.st_size < nlgrps * sizeof (lgrp_t *)) { 635 mdb_warn("lgrp_table size inconsistent with lgrp_alloc_max"); 636 return (WALK_ERR); 637 } 638 639 lwsd->lwsd_lgrp_tbl = mdb_alloc(sym.st_size, UM_SLEEP | UM_GC); 640 lwsd->lswd_nlgrps = nlgrps; 641 642 if (mdb_readsym(lwsd->lwsd_lgrp_tbl, nlgrps * sizeof (lgrp_t *), 643 "lgrp_table") == -1) { 644 mdb_warn("unable to read lgrp_table"); 645 return (WALK_ERR); 646 } 647 648 wsp->walk_data = lwsd; 649 650 /* Save the first lgroup from the set and remove it from the set */ 651 wsp->walk_addr = lwsd->lwsd_lgrp_tbl[id]; 652 lwsd->lwsd_set = set & ~(1 << id); 653 654 return (WALK_NEXT); 655 } 656 657 /* 658 * Get current lgroup and advance the lgroup to the next one in the lwsd_set. 659 */ 660 int 661 lgrp_set_walk_step(mdb_walk_state_t *wsp) 662 { 663 lgrp_id_t id = 0; 664 lgrp_set_walk_data_t *lwsd = wsp->walk_data; 665 int status = lgrp_walk_step_common(wsp); 666 667 if (status == WALK_NEXT) { 668 id = lgrp_set_get_first(lwsd->lwsd_set, lwsd->lswd_nlgrps); 669 if (id == LGRP_NONE) { 670 status = WALK_DONE; 671 } else { 672 /* Move to the next lgroup in the set */ 673 wsp->walk_addr = lwsd->lwsd_lgrp_tbl[id]; 674 675 /* Remove id from the set */ 676 lwsd->lwsd_set = lwsd->lwsd_set & ~(1 << id); 677 } 678 } 679 680 return (status); 681 } 682 683 /* 684 * Initialize resource walker for a given lgroup and resource. The lgroup 685 * address is specified in walk_addr. 686 */ 687 static int 688 lgrp_rsrc_walk_init(mdb_walk_state_t *wsp, int resource) 689 { 690 lgrp_t lgrp; 691 692 if (mdb_vread(&lgrp, sizeof (struct lgrp), wsp->walk_addr) == -1) { 693 mdb_warn("couldn't read 'lgrp' at %p", wsp->walk_addr); 694 return (WALK_ERR); 695 } 696 697 return (lgrp_set_walk_init(wsp, lgrp.lgrp_set[resource])); 698 } 699 700 /* 701 * Initialize CPU resource walker 702 */ 703 int 704 lgrp_rsrc_cpu_walk_init(mdb_walk_state_t *wsp) 705 { 706 return (lgrp_rsrc_walk_init(wsp, LGRP_RSRC_CPU)); 707 } 708 709 /* 710 * Initialize memory resource walker 711 */ 712 int 713 lgrp_rsrc_mem_walk_init(mdb_walk_state_t *wsp) 714 { 715 return (lgrp_rsrc_walk_init(wsp, LGRP_RSRC_MEM)); 716 } 717 718 /* 719 * Display bitmap as a list of integers 720 */ 721 /* ARGSUSED */ 722 int 723 lgrp_set(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 724 { 725 uint64_t set = (uint64_t)addr; 726 uint64_t mask = 1; 727 int i = 0; 728 729 if (!(flags & DCMD_ADDRSPEC)) { 730 return (DCMD_USAGE); 731 } 732 733 if (set == 0) 734 return (DCMD_OK); 735 736 for (; set != (uint64_t)0; i++, mask <<= 1) { 737 if (set & mask) { 738 mdb_printf("%d ", i); 739 set &= ~mask; 740 } 741 } 742 mdb_printf("\n"); 743 return (DCMD_OK); 744 } 745