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