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 2005 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 int 471 lgrp_walk_step(mdb_walk_state_t *wsp) 472 { 473 lgrp_walk_data_t *lwd = wsp->walk_data; 474 lgrp_t lgrp; 475 int status; 476 477 478 if (mdb_vread(&lgrp, sizeof (struct lgrp), 479 wsp->walk_addr) == -1) { 480 mdb_warn("unable to read lgrp at %p", 481 wsp->walk_addr); 482 return (WALK_ERR); 483 } 484 485 status = wsp->walk_callback(wsp->walk_addr, &lgrp, 486 wsp->walk_cbdata); 487 488 if (status != WALK_NEXT) 489 return (status); 490 491 lwd->lwd_iter++; 492 493 if (lwd->lwd_iter >= lwd->lwd_nlgrps) 494 return (WALK_DONE); 495 496 wsp->walk_addr = lwd->lwd_lgrp_tbl[lwd->lwd_iter]; 497 498 if (wsp->walk_addr == NULL) { 499 mdb_warn("NULL lgrp pointer in lgrp_table[%d]", 500 lwd->lwd_iter); 501 return (WALK_ERR); 502 } 503 504 return (WALK_NEXT); 505 } 506