| .. | .. |
|---|
| 79 | 79 | int sort_active; |
|---|
| 80 | 80 | int set_debug; |
|---|
| 81 | 81 | int show_ops; |
|---|
| 82 | +int sort_partial; |
|---|
| 82 | 83 | int show_activity; |
|---|
| 83 | 84 | int output_lines = -1; |
|---|
| 84 | 85 | int sort_loss; |
|---|
| .. | .. |
|---|
| 110 | 111 | static void usage(void) |
|---|
| 111 | 112 | { |
|---|
| 112 | 113 | printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n" |
|---|
| 113 | | - "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" |
|---|
| 114 | + "slabinfo [-aABDefhilLnoPrsStTUvXz1] [N=K] [-dafzput] [slab-regexp]\n" |
|---|
| 114 | 115 | "-a|--aliases Show aliases\n" |
|---|
| 115 | 116 | "-A|--activity Most active slabs first\n" |
|---|
| 116 | | - "-d<options>|--debug=<options> Set/Clear Debug options\n" |
|---|
| 117 | + "-B|--Bytes Show size in bytes\n" |
|---|
| 117 | 118 | "-D|--display-active Switch line format to activity\n" |
|---|
| 118 | 119 | "-e|--empty Show empty slabs\n" |
|---|
| 119 | 120 | "-f|--first-alias Show first alias\n" |
|---|
| 120 | 121 | "-h|--help Show usage information\n" |
|---|
| 121 | 122 | "-i|--inverted Inverted list\n" |
|---|
| 122 | 123 | "-l|--slabs Show slabs\n" |
|---|
| 124 | + "-L|--Loss Sort by loss\n" |
|---|
| 123 | 125 | "-n|--numa Show NUMA information\n" |
|---|
| 124 | | - "-o|--ops Show kmem_cache_ops\n" |
|---|
| 126 | + "-N|--lines=K Show the first K slabs\n" |
|---|
| 127 | + "-o|--ops Show kmem_cache_ops\n" |
|---|
| 128 | + "-P|--partial Sort by number of partial slabs\n" |
|---|
| 129 | + "-r|--report Detailed report on single slabs\n" |
|---|
| 125 | 130 | "-s|--shrink Shrink slabs\n" |
|---|
| 126 | | - "-r|--report Detailed report on single slabs\n" |
|---|
| 127 | 131 | "-S|--Size Sort by size\n" |
|---|
| 128 | 132 | "-t|--tracking Show alloc/free information\n" |
|---|
| 129 | 133 | "-T|--Totals Show summary information\n" |
|---|
| 134 | + "-U|--Unreclaim Show unreclaimable slabs only\n" |
|---|
| 130 | 135 | "-v|--validate Validate slabs\n" |
|---|
| 136 | + "-X|--Xtotals Show extended summary information\n" |
|---|
| 131 | 137 | "-z|--zero Include empty slabs\n" |
|---|
| 132 | 138 | "-1|--1ref Single reference\n" |
|---|
| 133 | | - "-N|--lines=K Show the first K slabs\n" |
|---|
| 134 | | - "-L|--Loss Sort by loss\n" |
|---|
| 135 | | - "-X|--Xtotals Show extended summary information\n" |
|---|
| 136 | | - "-B|--Bytes Show size in bytes\n" |
|---|
| 137 | | - "-U|--Unreclaim Show unreclaimable slabs only\n" |
|---|
| 138 | | - "\nValid debug options (FZPUT may be combined)\n" |
|---|
| 139 | | - "a / A Switch on all debug options (=FZUP)\n" |
|---|
| 140 | | - "- Switch off all debug options\n" |
|---|
| 141 | | - "f / F Sanity Checks (SLAB_CONSISTENCY_CHECKS)\n" |
|---|
| 142 | | - "z / Z Redzoning\n" |
|---|
| 143 | | - "p / P Poisoning\n" |
|---|
| 144 | | - "u / U Tracking\n" |
|---|
| 145 | | - "t / T Tracing\n" |
|---|
| 139 | + |
|---|
| 140 | + "\n" |
|---|
| 141 | + "-d | --debug Switch off all debug options\n" |
|---|
| 142 | + "-da | --debug=a Switch on all debug options (--debug=FZPU)\n" |
|---|
| 143 | + |
|---|
| 144 | + "\n" |
|---|
| 145 | + "-d[afzput] | --debug=[afzput]\n" |
|---|
| 146 | + " f | F Sanity Checks (SLAB_CONSISTENCY_CHECKS)\n" |
|---|
| 147 | + " z | Z Redzoning\n" |
|---|
| 148 | + " p | P Poisoning\n" |
|---|
| 149 | + " u | U Tracking\n" |
|---|
| 150 | + " t | T Tracing\n" |
|---|
| 151 | + |
|---|
| 152 | + "\nSorting options (--Loss, --Size, --Partial) are mutually exclusive\n" |
|---|
| 146 | 153 | ); |
|---|
| 147 | 154 | } |
|---|
| 148 | 155 | |
|---|
| .. | .. |
|---|
| 226 | 233 | return l; |
|---|
| 227 | 234 | } |
|---|
| 228 | 235 | |
|---|
| 236 | +static unsigned long read_debug_slab_obj(struct slabinfo *s, const char *name) |
|---|
| 237 | +{ |
|---|
| 238 | + char x[128]; |
|---|
| 239 | + FILE *f; |
|---|
| 240 | + size_t l; |
|---|
| 241 | + |
|---|
| 242 | + snprintf(x, 128, "/sys/kernel/debug/slab/%s/%s", s->name, name); |
|---|
| 243 | + f = fopen(x, "r"); |
|---|
| 244 | + if (!f) { |
|---|
| 245 | + buffer[0] = 0; |
|---|
| 246 | + l = 0; |
|---|
| 247 | + } else { |
|---|
| 248 | + l = fread(buffer, 1, sizeof(buffer), f); |
|---|
| 249 | + buffer[l] = 0; |
|---|
| 250 | + fclose(f); |
|---|
| 251 | + } |
|---|
| 252 | + return l; |
|---|
| 253 | +} |
|---|
| 229 | 254 | |
|---|
| 230 | 255 | /* |
|---|
| 231 | 256 | * Put a size string together |
|---|
| .. | .. |
|---|
| 402 | 427 | { |
|---|
| 403 | 428 | printf("\n%s: Kernel object allocation\n", s->name); |
|---|
| 404 | 429 | printf("-----------------------------------------------------------------------\n"); |
|---|
| 405 | | - if (read_slab_obj(s, "alloc_calls")) |
|---|
| 430 | + if (read_debug_slab_obj(s, "alloc_traces")) |
|---|
| 431 | + printf("%s", buffer); |
|---|
| 432 | + else if (read_slab_obj(s, "alloc_calls")) |
|---|
| 406 | 433 | printf("%s", buffer); |
|---|
| 407 | 434 | else |
|---|
| 408 | 435 | printf("No Data\n"); |
|---|
| 409 | 436 | |
|---|
| 410 | 437 | printf("\n%s: Kernel object freeing\n", s->name); |
|---|
| 411 | 438 | printf("------------------------------------------------------------------------\n"); |
|---|
| 412 | | - if (read_slab_obj(s, "free_calls")) |
|---|
| 439 | + if (read_debug_slab_obj(s, "free_traces")) |
|---|
| 440 | + printf("%s", buffer); |
|---|
| 441 | + else if (read_slab_obj(s, "free_calls")) |
|---|
| 413 | 442 | printf("%s", buffer); |
|---|
| 414 | 443 | else |
|---|
| 415 | 444 | printf("No Data\n"); |
|---|
| .. | .. |
|---|
| 713 | 742 | return; |
|---|
| 714 | 743 | |
|---|
| 715 | 744 | if (sanity && !s->sanity_checks) { |
|---|
| 716 | | - set_obj(s, "sanity", 1); |
|---|
| 745 | + set_obj(s, "sanity_checks", 1); |
|---|
| 717 | 746 | } |
|---|
| 718 | 747 | if (!sanity && s->sanity_checks) { |
|---|
| 719 | 748 | if (slab_empty(s)) |
|---|
| 720 | | - set_obj(s, "sanity", 0); |
|---|
| 749 | + set_obj(s, "sanity_checks", 0); |
|---|
| 721 | 750 | else |
|---|
| 722 | 751 | fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name); |
|---|
| 723 | 752 | } |
|---|
| .. | .. |
|---|
| 1038 | 1067 | for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) { |
|---|
| 1039 | 1068 | int result; |
|---|
| 1040 | 1069 | |
|---|
| 1041 | | - if (sort_size) |
|---|
| 1042 | | - result = slab_size(s1) < slab_size(s2); |
|---|
| 1043 | | - else if (sort_active) |
|---|
| 1044 | | - result = slab_activity(s1) < slab_activity(s2); |
|---|
| 1045 | | - else if (sort_loss) |
|---|
| 1046 | | - result = slab_waste(s1) < slab_waste(s2); |
|---|
| 1047 | | - else |
|---|
| 1070 | + if (sort_size) { |
|---|
| 1071 | + if (slab_size(s1) == slab_size(s2)) |
|---|
| 1072 | + result = strcasecmp(s1->name, s2->name); |
|---|
| 1073 | + else |
|---|
| 1074 | + result = slab_size(s1) < slab_size(s2); |
|---|
| 1075 | + } else if (sort_active) { |
|---|
| 1076 | + if (slab_activity(s1) == slab_activity(s2)) |
|---|
| 1077 | + result = strcasecmp(s1->name, s2->name); |
|---|
| 1078 | + else |
|---|
| 1079 | + result = slab_activity(s1) < slab_activity(s2); |
|---|
| 1080 | + } else if (sort_loss) { |
|---|
| 1081 | + if (slab_waste(s1) == slab_waste(s2)) |
|---|
| 1082 | + result = strcasecmp(s1->name, s2->name); |
|---|
| 1083 | + else |
|---|
| 1084 | + result = slab_waste(s1) < slab_waste(s2); |
|---|
| 1085 | + } else if (sort_partial) { |
|---|
| 1086 | + if (s1->partial == s2->partial) |
|---|
| 1087 | + result = strcasecmp(s1->name, s2->name); |
|---|
| 1088 | + else |
|---|
| 1089 | + result = s1->partial < s2->partial; |
|---|
| 1090 | + } else |
|---|
| 1048 | 1091 | result = strcasecmp(s1->name, s2->name); |
|---|
| 1049 | 1092 | |
|---|
| 1050 | 1093 | if (show_inverted) |
|---|
| .. | .. |
|---|
| 1304 | 1347 | } |
|---|
| 1305 | 1348 | } |
|---|
| 1306 | 1349 | |
|---|
| 1350 | +static void _xtotals(char *heading, char *underline, |
|---|
| 1351 | + int loss, int size, int partial) |
|---|
| 1352 | +{ |
|---|
| 1353 | + printf("%s%s", heading, underline); |
|---|
| 1354 | + line = 0; |
|---|
| 1355 | + sort_loss = loss; |
|---|
| 1356 | + sort_size = size; |
|---|
| 1357 | + sort_partial = partial; |
|---|
| 1358 | + sort_slabs(); |
|---|
| 1359 | + output_slabs(); |
|---|
| 1360 | +} |
|---|
| 1361 | + |
|---|
| 1307 | 1362 | static void xtotals(void) |
|---|
| 1308 | 1363 | { |
|---|
| 1364 | + char *heading, *underline; |
|---|
| 1365 | + |
|---|
| 1309 | 1366 | totals(); |
|---|
| 1310 | 1367 | |
|---|
| 1311 | 1368 | link_slabs(); |
|---|
| 1312 | 1369 | rename_slabs(); |
|---|
| 1313 | 1370 | |
|---|
| 1314 | | - printf("\nSlabs sorted by size\n"); |
|---|
| 1315 | | - printf("--------------------\n"); |
|---|
| 1316 | | - sort_loss = 0; |
|---|
| 1317 | | - sort_size = 1; |
|---|
| 1318 | | - sort_slabs(); |
|---|
| 1319 | | - output_slabs(); |
|---|
| 1371 | + heading = "\nSlabs sorted by size\n"; |
|---|
| 1372 | + underline = "--------------------\n"; |
|---|
| 1373 | + _xtotals(heading, underline, 0, 1, 0); |
|---|
| 1320 | 1374 | |
|---|
| 1321 | | - printf("\nSlabs sorted by loss\n"); |
|---|
| 1322 | | - printf("--------------------\n"); |
|---|
| 1323 | | - line = 0; |
|---|
| 1324 | | - sort_loss = 1; |
|---|
| 1325 | | - sort_size = 0; |
|---|
| 1326 | | - sort_slabs(); |
|---|
| 1327 | | - output_slabs(); |
|---|
| 1375 | + heading = "\nSlabs sorted by loss\n"; |
|---|
| 1376 | + underline = "--------------------\n"; |
|---|
| 1377 | + _xtotals(heading, underline, 1, 0, 0); |
|---|
| 1378 | + |
|---|
| 1379 | + heading = "\nSlabs sorted by number of partial slabs\n"; |
|---|
| 1380 | + underline = "---------------------------------------\n"; |
|---|
| 1381 | + _xtotals(heading, underline, 0, 0, 1); |
|---|
| 1382 | + |
|---|
| 1328 | 1383 | printf("\n"); |
|---|
| 1329 | 1384 | } |
|---|
| 1330 | 1385 | |
|---|
| 1331 | 1386 | struct option opts[] = { |
|---|
| 1332 | 1387 | { "aliases", no_argument, NULL, 'a' }, |
|---|
| 1333 | 1388 | { "activity", no_argument, NULL, 'A' }, |
|---|
| 1389 | + { "Bytes", no_argument, NULL, 'B'}, |
|---|
| 1334 | 1390 | { "debug", optional_argument, NULL, 'd' }, |
|---|
| 1335 | 1391 | { "display-activity", no_argument, NULL, 'D' }, |
|---|
| 1336 | 1392 | { "empty", no_argument, NULL, 'e' }, |
|---|
| .. | .. |
|---|
| 1338 | 1394 | { "help", no_argument, NULL, 'h' }, |
|---|
| 1339 | 1395 | { "inverted", no_argument, NULL, 'i'}, |
|---|
| 1340 | 1396 | { "slabs", no_argument, NULL, 'l' }, |
|---|
| 1397 | + { "Loss", no_argument, NULL, 'L'}, |
|---|
| 1341 | 1398 | { "numa", no_argument, NULL, 'n' }, |
|---|
| 1399 | + { "lines", required_argument, NULL, 'N'}, |
|---|
| 1342 | 1400 | { "ops", no_argument, NULL, 'o' }, |
|---|
| 1343 | | - { "shrink", no_argument, NULL, 's' }, |
|---|
| 1401 | + { "partial", no_argument, NULL, 'p'}, |
|---|
| 1344 | 1402 | { "report", no_argument, NULL, 'r' }, |
|---|
| 1403 | + { "shrink", no_argument, NULL, 's' }, |
|---|
| 1345 | 1404 | { "Size", no_argument, NULL, 'S'}, |
|---|
| 1346 | 1405 | { "tracking", no_argument, NULL, 't'}, |
|---|
| 1347 | 1406 | { "Totals", no_argument, NULL, 'T'}, |
|---|
| 1407 | + { "Unreclaim", no_argument, NULL, 'U'}, |
|---|
| 1348 | 1408 | { "validate", no_argument, NULL, 'v' }, |
|---|
| 1409 | + { "Xtotals", no_argument, NULL, 'X'}, |
|---|
| 1349 | 1410 | { "zero", no_argument, NULL, 'z' }, |
|---|
| 1350 | 1411 | { "1ref", no_argument, NULL, '1'}, |
|---|
| 1351 | | - { "lines", required_argument, NULL, 'N'}, |
|---|
| 1352 | | - { "Loss", no_argument, NULL, 'L'}, |
|---|
| 1353 | | - { "Xtotals", no_argument, NULL, 'X'}, |
|---|
| 1354 | | - { "Bytes", no_argument, NULL, 'B'}, |
|---|
| 1355 | | - { "Unreclaim", no_argument, NULL, 'U'}, |
|---|
| 1356 | 1412 | { NULL, 0, NULL, 0 } |
|---|
| 1357 | 1413 | }; |
|---|
| 1358 | 1414 | |
|---|
| .. | .. |
|---|
| 1364 | 1420 | |
|---|
| 1365 | 1421 | page_size = getpagesize(); |
|---|
| 1366 | 1422 | |
|---|
| 1367 | | - while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTSN:LXBU", |
|---|
| 1423 | + while ((c = getopt_long(argc, argv, "aABd::DefhilLnN:oPrsStTUvXz1", |
|---|
| 1368 | 1424 | opts, NULL)) != -1) |
|---|
| 1369 | 1425 | switch (c) { |
|---|
| 1370 | | - case '1': |
|---|
| 1371 | | - show_single_ref = 1; |
|---|
| 1372 | | - break; |
|---|
| 1373 | 1426 | case 'a': |
|---|
| 1374 | 1427 | show_alias = 1; |
|---|
| 1375 | 1428 | break; |
|---|
| 1376 | 1429 | case 'A': |
|---|
| 1377 | 1430 | sort_active = 1; |
|---|
| 1431 | + break; |
|---|
| 1432 | + case 'B': |
|---|
| 1433 | + show_bytes = 1; |
|---|
| 1378 | 1434 | break; |
|---|
| 1379 | 1435 | case 'd': |
|---|
| 1380 | 1436 | set_debug = 1; |
|---|
| .. | .. |
|---|
| 1396 | 1452 | case 'i': |
|---|
| 1397 | 1453 | show_inverted = 1; |
|---|
| 1398 | 1454 | break; |
|---|
| 1399 | | - case 'n': |
|---|
| 1400 | | - show_numa = 1; |
|---|
| 1401 | | - break; |
|---|
| 1402 | | - case 'o': |
|---|
| 1403 | | - show_ops = 1; |
|---|
| 1404 | | - break; |
|---|
| 1405 | | - case 'r': |
|---|
| 1406 | | - show_report = 1; |
|---|
| 1407 | | - break; |
|---|
| 1408 | | - case 's': |
|---|
| 1409 | | - shrink = 1; |
|---|
| 1410 | | - break; |
|---|
| 1411 | 1455 | case 'l': |
|---|
| 1412 | 1456 | show_slab = 1; |
|---|
| 1413 | 1457 | break; |
|---|
| 1414 | | - case 't': |
|---|
| 1415 | | - show_track = 1; |
|---|
| 1458 | + case 'L': |
|---|
| 1459 | + sort_loss = 1; |
|---|
| 1416 | 1460 | break; |
|---|
| 1417 | | - case 'v': |
|---|
| 1418 | | - validate = 1; |
|---|
| 1419 | | - break; |
|---|
| 1420 | | - case 'z': |
|---|
| 1421 | | - skip_zero = 0; |
|---|
| 1422 | | - break; |
|---|
| 1423 | | - case 'T': |
|---|
| 1424 | | - show_totals = 1; |
|---|
| 1425 | | - break; |
|---|
| 1426 | | - case 'S': |
|---|
| 1427 | | - sort_size = 1; |
|---|
| 1461 | + case 'n': |
|---|
| 1462 | + show_numa = 1; |
|---|
| 1428 | 1463 | break; |
|---|
| 1429 | 1464 | case 'N': |
|---|
| 1430 | 1465 | if (optarg) { |
|---|
| .. | .. |
|---|
| 1433 | 1468 | output_lines = 1; |
|---|
| 1434 | 1469 | } |
|---|
| 1435 | 1470 | break; |
|---|
| 1436 | | - case 'L': |
|---|
| 1437 | | - sort_loss = 1; |
|---|
| 1471 | + case 'o': |
|---|
| 1472 | + show_ops = 1; |
|---|
| 1473 | + break; |
|---|
| 1474 | + case 'r': |
|---|
| 1475 | + show_report = 1; |
|---|
| 1476 | + break; |
|---|
| 1477 | + case 'P': |
|---|
| 1478 | + sort_partial = 1; |
|---|
| 1479 | + break; |
|---|
| 1480 | + case 's': |
|---|
| 1481 | + shrink = 1; |
|---|
| 1482 | + break; |
|---|
| 1483 | + case 'S': |
|---|
| 1484 | + sort_size = 1; |
|---|
| 1485 | + break; |
|---|
| 1486 | + case 't': |
|---|
| 1487 | + show_track = 1; |
|---|
| 1488 | + break; |
|---|
| 1489 | + case 'T': |
|---|
| 1490 | + show_totals = 1; |
|---|
| 1491 | + break; |
|---|
| 1492 | + case 'U': |
|---|
| 1493 | + unreclaim_only = 1; |
|---|
| 1494 | + break; |
|---|
| 1495 | + case 'v': |
|---|
| 1496 | + validate = 1; |
|---|
| 1438 | 1497 | break; |
|---|
| 1439 | 1498 | case 'X': |
|---|
| 1440 | 1499 | if (output_lines == -1) |
|---|
| .. | .. |
|---|
| 1442 | 1501 | extended_totals = 1; |
|---|
| 1443 | 1502 | show_bytes = 1; |
|---|
| 1444 | 1503 | break; |
|---|
| 1445 | | - case 'B': |
|---|
| 1446 | | - show_bytes = 1; |
|---|
| 1504 | + case 'z': |
|---|
| 1505 | + skip_zero = 0; |
|---|
| 1447 | 1506 | break; |
|---|
| 1448 | | - case 'U': |
|---|
| 1449 | | - unreclaim_only = 1; |
|---|
| 1507 | + case '1': |
|---|
| 1508 | + show_single_ref = 1; |
|---|
| 1450 | 1509 | break; |
|---|
| 1451 | 1510 | default: |
|---|
| 1452 | 1511 | fatal("%s: Invalid option '%c'\n", argv[0], optopt); |
|---|