PageRenderTime 58ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/tools/slub/slabinfo.c

https://github.com/ab3416/linux-2.6
C | 1385 lines | 1163 code | 181 blank | 41 comment | 252 complexity | b94418122e45eaf7c2463a9f62b65ad0 MD5 | raw file
  1. /*
  2. * Slabinfo: Tool to get reports about slabs
  3. *
  4. * (C) 2007 sgi, Christoph Lameter
  5. * (C) 2011 Linux Foundation, Christoph Lameter
  6. *
  7. * Compile with:
  8. *
  9. * gcc -o slabinfo slabinfo.c
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <sys/types.h>
  14. #include <dirent.h>
  15. #include <strings.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include <stdarg.h>
  19. #include <getopt.h>
  20. #include <regex.h>
  21. #include <errno.h>
  22. #define MAX_SLABS 500
  23. #define MAX_ALIASES 500
  24. #define MAX_NODES 1024
  25. struct slabinfo {
  26. char *name;
  27. int alias;
  28. int refs;
  29. int aliases, align, cache_dma, cpu_slabs, destroy_by_rcu;
  30. int hwcache_align, object_size, objs_per_slab;
  31. int sanity_checks, slab_size, store_user, trace;
  32. int order, poison, reclaim_account, red_zone;
  33. unsigned long partial, objects, slabs, objects_partial, objects_total;
  34. unsigned long alloc_fastpath, alloc_slowpath;
  35. unsigned long free_fastpath, free_slowpath;
  36. unsigned long free_frozen, free_add_partial, free_remove_partial;
  37. unsigned long alloc_from_partial, alloc_slab, free_slab, alloc_refill;
  38. unsigned long cpuslab_flush, deactivate_full, deactivate_empty;
  39. unsigned long deactivate_to_head, deactivate_to_tail;
  40. unsigned long deactivate_remote_frees, order_fallback;
  41. unsigned long cmpxchg_double_cpu_fail, cmpxchg_double_fail;
  42. unsigned long alloc_node_mismatch, deactivate_bypass;
  43. int numa[MAX_NODES];
  44. int numa_partial[MAX_NODES];
  45. } slabinfo[MAX_SLABS];
  46. struct aliasinfo {
  47. char *name;
  48. char *ref;
  49. struct slabinfo *slab;
  50. } aliasinfo[MAX_ALIASES];
  51. int slabs = 0;
  52. int actual_slabs = 0;
  53. int aliases = 0;
  54. int alias_targets = 0;
  55. int highest_node = 0;
  56. char buffer[4096];
  57. int show_empty = 0;
  58. int show_report = 0;
  59. int show_alias = 0;
  60. int show_slab = 0;
  61. int skip_zero = 1;
  62. int show_numa = 0;
  63. int show_track = 0;
  64. int show_first_alias = 0;
  65. int validate = 0;
  66. int shrink = 0;
  67. int show_inverted = 0;
  68. int show_single_ref = 0;
  69. int show_totals = 0;
  70. int sort_size = 0;
  71. int sort_active = 0;
  72. int set_debug = 0;
  73. int show_ops = 0;
  74. int show_activity = 0;
  75. /* Debug options */
  76. int sanity = 0;
  77. int redzone = 0;
  78. int poison = 0;
  79. int tracking = 0;
  80. int tracing = 0;
  81. int page_size;
  82. regex_t pattern;
  83. static void fatal(const char *x, ...)
  84. {
  85. va_list ap;
  86. va_start(ap, x);
  87. vfprintf(stderr, x, ap);
  88. va_end(ap);
  89. exit(EXIT_FAILURE);
  90. }
  91. static void usage(void)
  92. {
  93. printf("slabinfo 4/15/2011. (c) 2007 sgi/(c) 2011 Linux Foundation.\n\n"
  94. "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n"
  95. "-a|--aliases Show aliases\n"
  96. "-A|--activity Most active slabs first\n"
  97. "-d<options>|--debug=<options> Set/Clear Debug options\n"
  98. "-D|--display-active Switch line format to activity\n"
  99. "-e|--empty Show empty slabs\n"
  100. "-f|--first-alias Show first alias\n"
  101. "-h|--help Show usage information\n"
  102. "-i|--inverted Inverted list\n"
  103. "-l|--slabs Show slabs\n"
  104. "-n|--numa Show NUMA information\n"
  105. "-o|--ops Show kmem_cache_ops\n"
  106. "-s|--shrink Shrink slabs\n"
  107. "-r|--report Detailed report on single slabs\n"
  108. "-S|--Size Sort by size\n"
  109. "-t|--tracking Show alloc/free information\n"
  110. "-T|--Totals Show summary information\n"
  111. "-v|--validate Validate slabs\n"
  112. "-z|--zero Include empty slabs\n"
  113. "-1|--1ref Single reference\n"
  114. "\nValid debug options (FZPUT may be combined)\n"
  115. "a / A Switch on all debug options (=FZUP)\n"
  116. "- Switch off all debug options\n"
  117. "f / F Sanity Checks (SLAB_DEBUG_FREE)\n"
  118. "z / Z Redzoning\n"
  119. "p / P Poisoning\n"
  120. "u / U Tracking\n"
  121. "t / T Tracing\n"
  122. );
  123. }
  124. static unsigned long read_obj(const char *name)
  125. {
  126. FILE *f = fopen(name, "r");
  127. if (!f)
  128. buffer[0] = 0;
  129. else {
  130. if (!fgets(buffer, sizeof(buffer), f))
  131. buffer[0] = 0;
  132. fclose(f);
  133. if (buffer[strlen(buffer)] == '\n')
  134. buffer[strlen(buffer)] = 0;
  135. }
  136. return strlen(buffer);
  137. }
  138. /*
  139. * Get the contents of an attribute
  140. */
  141. static unsigned long get_obj(const char *name)
  142. {
  143. if (!read_obj(name))
  144. return 0;
  145. return atol(buffer);
  146. }
  147. static unsigned long get_obj_and_str(const char *name, char **x)
  148. {
  149. unsigned long result = 0;
  150. char *p;
  151. *x = NULL;
  152. if (!read_obj(name)) {
  153. x = NULL;
  154. return 0;
  155. }
  156. result = strtoul(buffer, &p, 10);
  157. while (*p == ' ')
  158. p++;
  159. if (*p)
  160. *x = strdup(p);
  161. return result;
  162. }
  163. static void set_obj(struct slabinfo *s, const char *name, int n)
  164. {
  165. char x[100];
  166. FILE *f;
  167. snprintf(x, 100, "%s/%s", s->name, name);
  168. f = fopen(x, "w");
  169. if (!f)
  170. fatal("Cannot write to %s\n", x);
  171. fprintf(f, "%d\n", n);
  172. fclose(f);
  173. }
  174. static unsigned long read_slab_obj(struct slabinfo *s, const char *name)
  175. {
  176. char x[100];
  177. FILE *f;
  178. size_t l;
  179. snprintf(x, 100, "%s/%s", s->name, name);
  180. f = fopen(x, "r");
  181. if (!f) {
  182. buffer[0] = 0;
  183. l = 0;
  184. } else {
  185. l = fread(buffer, 1, sizeof(buffer), f);
  186. buffer[l] = 0;
  187. fclose(f);
  188. }
  189. return l;
  190. }
  191. /*
  192. * Put a size string together
  193. */
  194. static int store_size(char *buffer, unsigned long value)
  195. {
  196. unsigned long divisor = 1;
  197. char trailer = 0;
  198. int n;
  199. if (value > 1000000000UL) {
  200. divisor = 100000000UL;
  201. trailer = 'G';
  202. } else if (value > 1000000UL) {
  203. divisor = 100000UL;
  204. trailer = 'M';
  205. } else if (value > 1000UL) {
  206. divisor = 100;
  207. trailer = 'K';
  208. }
  209. value /= divisor;
  210. n = sprintf(buffer, "%ld",value);
  211. if (trailer) {
  212. buffer[n] = trailer;
  213. n++;
  214. buffer[n] = 0;
  215. }
  216. if (divisor != 1) {
  217. memmove(buffer + n - 2, buffer + n - 3, 4);
  218. buffer[n-2] = '.';
  219. n++;
  220. }
  221. return n;
  222. }
  223. static void decode_numa_list(int *numa, char *t)
  224. {
  225. int node;
  226. int nr;
  227. memset(numa, 0, MAX_NODES * sizeof(int));
  228. if (!t)
  229. return;
  230. while (*t == 'N') {
  231. t++;
  232. node = strtoul(t, &t, 10);
  233. if (*t == '=') {
  234. t++;
  235. nr = strtoul(t, &t, 10);
  236. numa[node] = nr;
  237. if (node > highest_node)
  238. highest_node = node;
  239. }
  240. while (*t == ' ')
  241. t++;
  242. }
  243. }
  244. static void slab_validate(struct slabinfo *s)
  245. {
  246. if (strcmp(s->name, "*") == 0)
  247. return;
  248. set_obj(s, "validate", 1);
  249. }
  250. static void slab_shrink(struct slabinfo *s)
  251. {
  252. if (strcmp(s->name, "*") == 0)
  253. return;
  254. set_obj(s, "shrink", 1);
  255. }
  256. int line = 0;
  257. static void first_line(void)
  258. {
  259. if (show_activity)
  260. printf("Name Objects Alloc Free %%Fast Fallb O CmpX UL\n");
  261. else
  262. printf("Name Objects Objsize Space "
  263. "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n");
  264. }
  265. /*
  266. * Find the shortest alias of a slab
  267. */
  268. static struct aliasinfo *find_one_alias(struct slabinfo *find)
  269. {
  270. struct aliasinfo *a;
  271. struct aliasinfo *best = NULL;
  272. for(a = aliasinfo;a < aliasinfo + aliases; a++) {
  273. if (a->slab == find &&
  274. (!best || strlen(best->name) < strlen(a->name))) {
  275. best = a;
  276. if (strncmp(a->name,"kmall", 5) == 0)
  277. return best;
  278. }
  279. }
  280. return best;
  281. }
  282. static unsigned long slab_size(struct slabinfo *s)
  283. {
  284. return s->slabs * (page_size << s->order);
  285. }
  286. static unsigned long slab_activity(struct slabinfo *s)
  287. {
  288. return s->alloc_fastpath + s->free_fastpath +
  289. s->alloc_slowpath + s->free_slowpath;
  290. }
  291. static void slab_numa(struct slabinfo *s, int mode)
  292. {
  293. int node;
  294. if (strcmp(s->name, "*") == 0)
  295. return;
  296. if (!highest_node) {
  297. printf("\n%s: No NUMA information available.\n", s->name);
  298. return;
  299. }
  300. if (skip_zero && !s->slabs)
  301. return;
  302. if (!line) {
  303. printf("\n%-21s:", mode ? "NUMA nodes" : "Slab");
  304. for(node = 0; node <= highest_node; node++)
  305. printf(" %4d", node);
  306. printf("\n----------------------");
  307. for(node = 0; node <= highest_node; node++)
  308. printf("-----");
  309. printf("\n");
  310. }
  311. printf("%-21s ", mode ? "All slabs" : s->name);
  312. for(node = 0; node <= highest_node; node++) {
  313. char b[20];
  314. store_size(b, s->numa[node]);
  315. printf(" %4s", b);
  316. }
  317. printf("\n");
  318. if (mode) {
  319. printf("%-21s ", "Partial slabs");
  320. for(node = 0; node <= highest_node; node++) {
  321. char b[20];
  322. store_size(b, s->numa_partial[node]);
  323. printf(" %4s", b);
  324. }
  325. printf("\n");
  326. }
  327. line++;
  328. }
  329. static void show_tracking(struct slabinfo *s)
  330. {
  331. printf("\n%s: Kernel object allocation\n", s->name);
  332. printf("-----------------------------------------------------------------------\n");
  333. if (read_slab_obj(s, "alloc_calls"))
  334. printf("%s", buffer);
  335. else
  336. printf("No Data\n");
  337. printf("\n%s: Kernel object freeing\n", s->name);
  338. printf("------------------------------------------------------------------------\n");
  339. if (read_slab_obj(s, "free_calls"))
  340. printf("%s", buffer);
  341. else
  342. printf("No Data\n");
  343. }
  344. static void ops(struct slabinfo *s)
  345. {
  346. if (strcmp(s->name, "*") == 0)
  347. return;
  348. if (read_slab_obj(s, "ops")) {
  349. printf("\n%s: kmem_cache operations\n", s->name);
  350. printf("--------------------------------------------\n");
  351. printf("%s", buffer);
  352. } else
  353. printf("\n%s has no kmem_cache operations\n", s->name);
  354. }
  355. static const char *onoff(int x)
  356. {
  357. if (x)
  358. return "On ";
  359. return "Off";
  360. }
  361. static void slab_stats(struct slabinfo *s)
  362. {
  363. unsigned long total_alloc;
  364. unsigned long total_free;
  365. unsigned long total;
  366. if (!s->alloc_slab)
  367. return;
  368. total_alloc = s->alloc_fastpath + s->alloc_slowpath;
  369. total_free = s->free_fastpath + s->free_slowpath;
  370. if (!total_alloc)
  371. return;
  372. printf("\n");
  373. printf("Slab Perf Counter Alloc Free %%Al %%Fr\n");
  374. printf("--------------------------------------------------\n");
  375. printf("Fastpath %8lu %8lu %3lu %3lu\n",
  376. s->alloc_fastpath, s->free_fastpath,
  377. s->alloc_fastpath * 100 / total_alloc,
  378. s->free_fastpath * 100 / total_free);
  379. printf("Slowpath %8lu %8lu %3lu %3lu\n",
  380. total_alloc - s->alloc_fastpath, s->free_slowpath,
  381. (total_alloc - s->alloc_fastpath) * 100 / total_alloc,
  382. s->free_slowpath * 100 / total_free);
  383. printf("Page Alloc %8lu %8lu %3lu %3lu\n",
  384. s->alloc_slab, s->free_slab,
  385. s->alloc_slab * 100 / total_alloc,
  386. s->free_slab * 100 / total_free);
  387. printf("Add partial %8lu %8lu %3lu %3lu\n",
  388. s->deactivate_to_head + s->deactivate_to_tail,
  389. s->free_add_partial,
  390. (s->deactivate_to_head + s->deactivate_to_tail) * 100 / total_alloc,
  391. s->free_add_partial * 100 / total_free);
  392. printf("Remove partial %8lu %8lu %3lu %3lu\n",
  393. s->alloc_from_partial, s->free_remove_partial,
  394. s->alloc_from_partial * 100 / total_alloc,
  395. s->free_remove_partial * 100 / total_free);
  396. printf("RemoteObj/SlabFrozen %8lu %8lu %3lu %3lu\n",
  397. s->deactivate_remote_frees, s->free_frozen,
  398. s->deactivate_remote_frees * 100 / total_alloc,
  399. s->free_frozen * 100 / total_free);
  400. printf("Total %8lu %8lu\n\n", total_alloc, total_free);
  401. if (s->cpuslab_flush)
  402. printf("Flushes %8lu\n", s->cpuslab_flush);
  403. total = s->deactivate_full + s->deactivate_empty +
  404. s->deactivate_to_head + s->deactivate_to_tail + s->deactivate_bypass;
  405. if (total) {
  406. printf("\nSlab Deactivation Ocurrences %%\n");
  407. printf("-------------------------------------------------\n");
  408. printf("Slab full %7lu %3lu%%\n",
  409. s->deactivate_full, (s->deactivate_full * 100) / total);
  410. printf("Slab empty %7lu %3lu%%\n",
  411. s->deactivate_empty, (s->deactivate_empty * 100) / total);
  412. printf("Moved to head of partial list %7lu %3lu%%\n",
  413. s->deactivate_to_head, (s->deactivate_to_head * 100) / total);
  414. printf("Moved to tail of partial list %7lu %3lu%%\n",
  415. s->deactivate_to_tail, (s->deactivate_to_tail * 100) / total);
  416. printf("Deactivation bypass %7lu %3lu%%\n",
  417. s->deactivate_bypass, (s->deactivate_bypass * 100) / total);
  418. printf("Refilled from foreign frees %7lu %3lu%%\n",
  419. s->alloc_refill, (s->alloc_refill * 100) / total);
  420. printf("Node mismatch %7lu %3lu%%\n",
  421. s->alloc_node_mismatch, (s->alloc_node_mismatch * 100) / total);
  422. }
  423. if (s->cmpxchg_double_fail || s->cmpxchg_double_cpu_fail)
  424. printf("\nCmpxchg_double Looping\n------------------------\n");
  425. printf("Locked Cmpxchg Double redos %lu\nUnlocked Cmpxchg Double redos %lu\n",
  426. s->cmpxchg_double_fail, s->cmpxchg_double_cpu_fail);
  427. }
  428. static void report(struct slabinfo *s)
  429. {
  430. if (strcmp(s->name, "*") == 0)
  431. return;
  432. printf("\nSlabcache: %-20s Aliases: %2d Order : %2d Objects: %lu\n",
  433. s->name, s->aliases, s->order, s->objects);
  434. if (s->hwcache_align)
  435. printf("** Hardware cacheline aligned\n");
  436. if (s->cache_dma)
  437. printf("** Memory is allocated in a special DMA zone\n");
  438. if (s->destroy_by_rcu)
  439. printf("** Slabs are destroyed via RCU\n");
  440. if (s->reclaim_account)
  441. printf("** Reclaim accounting active\n");
  442. printf("\nSizes (bytes) Slabs Debug Memory\n");
  443. printf("------------------------------------------------------------------------\n");
  444. printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n",
  445. s->object_size, s->slabs, onoff(s->sanity_checks),
  446. s->slabs * (page_size << s->order));
  447. printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n",
  448. s->slab_size, s->slabs - s->partial - s->cpu_slabs,
  449. onoff(s->red_zone), s->objects * s->object_size);
  450. printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n",
  451. page_size << s->order, s->partial, onoff(s->poison),
  452. s->slabs * (page_size << s->order) - s->objects * s->object_size);
  453. printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n",
  454. s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user),
  455. (s->slab_size - s->object_size) * s->objects);
  456. printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n",
  457. s->align, s->objs_per_slab, onoff(s->trace),
  458. ((page_size << s->order) - s->objs_per_slab * s->slab_size) *
  459. s->slabs);
  460. ops(s);
  461. show_tracking(s);
  462. slab_numa(s, 1);
  463. slab_stats(s);
  464. }
  465. static void slabcache(struct slabinfo *s)
  466. {
  467. char size_str[20];
  468. char dist_str[40];
  469. char flags[20];
  470. char *p = flags;
  471. if (strcmp(s->name, "*") == 0)
  472. return;
  473. if (actual_slabs == 1) {
  474. report(s);
  475. return;
  476. }
  477. if (skip_zero && !show_empty && !s->slabs)
  478. return;
  479. if (show_empty && s->slabs)
  480. return;
  481. store_size(size_str, slab_size(s));
  482. snprintf(dist_str, 40, "%lu/%lu/%d", s->slabs - s->cpu_slabs,
  483. s->partial, s->cpu_slabs);
  484. if (!line++)
  485. first_line();
  486. if (s->aliases)
  487. *p++ = '*';
  488. if (s->cache_dma)
  489. *p++ = 'd';
  490. if (s->hwcache_align)
  491. *p++ = 'A';
  492. if (s->poison)
  493. *p++ = 'P';
  494. if (s->reclaim_account)
  495. *p++ = 'a';
  496. if (s->red_zone)
  497. *p++ = 'Z';
  498. if (s->sanity_checks)
  499. *p++ = 'F';
  500. if (s->store_user)
  501. *p++ = 'U';
  502. if (s->trace)
  503. *p++ = 'T';
  504. *p = 0;
  505. if (show_activity) {
  506. unsigned long total_alloc;
  507. unsigned long total_free;
  508. total_alloc = s->alloc_fastpath + s->alloc_slowpath;
  509. total_free = s->free_fastpath + s->free_slowpath;
  510. printf("%-21s %8ld %10ld %10ld %3ld %3ld %5ld %1d %4ld %4ld\n",
  511. s->name, s->objects,
  512. total_alloc, total_free,
  513. total_alloc ? (s->alloc_fastpath * 100 / total_alloc) : 0,
  514. total_free ? (s->free_fastpath * 100 / total_free) : 0,
  515. s->order_fallback, s->order, s->cmpxchg_double_fail,
  516. s->cmpxchg_double_cpu_fail);
  517. }
  518. else
  519. printf("%-21s %8ld %7d %8s %14s %4d %1d %3ld %3ld %s\n",
  520. s->name, s->objects, s->object_size, size_str, dist_str,
  521. s->objs_per_slab, s->order,
  522. s->slabs ? (s->partial * 100) / s->slabs : 100,
  523. s->slabs ? (s->objects * s->object_size * 100) /
  524. (s->slabs * (page_size << s->order)) : 100,
  525. flags);
  526. }
  527. /*
  528. * Analyze debug options. Return false if something is amiss.
  529. */
  530. static int debug_opt_scan(char *opt)
  531. {
  532. if (!opt || !opt[0] || strcmp(opt, "-") == 0)
  533. return 1;
  534. if (strcasecmp(opt, "a") == 0) {
  535. sanity = 1;
  536. poison = 1;
  537. redzone = 1;
  538. tracking = 1;
  539. return 1;
  540. }
  541. for ( ; *opt; opt++)
  542. switch (*opt) {
  543. case 'F' : case 'f':
  544. if (sanity)
  545. return 0;
  546. sanity = 1;
  547. break;
  548. case 'P' : case 'p':
  549. if (poison)
  550. return 0;
  551. poison = 1;
  552. break;
  553. case 'Z' : case 'z':
  554. if (redzone)
  555. return 0;
  556. redzone = 1;
  557. break;
  558. case 'U' : case 'u':
  559. if (tracking)
  560. return 0;
  561. tracking = 1;
  562. break;
  563. case 'T' : case 't':
  564. if (tracing)
  565. return 0;
  566. tracing = 1;
  567. break;
  568. default:
  569. return 0;
  570. }
  571. return 1;
  572. }
  573. static int slab_empty(struct slabinfo *s)
  574. {
  575. if (s->objects > 0)
  576. return 0;
  577. /*
  578. * We may still have slabs even if there are no objects. Shrinking will
  579. * remove them.
  580. */
  581. if (s->slabs != 0)
  582. set_obj(s, "shrink", 1);
  583. return 1;
  584. }
  585. static void slab_debug(struct slabinfo *s)
  586. {
  587. if (strcmp(s->name, "*") == 0)
  588. return;
  589. if (sanity && !s->sanity_checks) {
  590. set_obj(s, "sanity", 1);
  591. }
  592. if (!sanity && s->sanity_checks) {
  593. if (slab_empty(s))
  594. set_obj(s, "sanity", 0);
  595. else
  596. fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name);
  597. }
  598. if (redzone && !s->red_zone) {
  599. if (slab_empty(s))
  600. set_obj(s, "red_zone", 1);
  601. else
  602. fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name);
  603. }
  604. if (!redzone && s->red_zone) {
  605. if (slab_empty(s))
  606. set_obj(s, "red_zone", 0);
  607. else
  608. fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name);
  609. }
  610. if (poison && !s->poison) {
  611. if (slab_empty(s))
  612. set_obj(s, "poison", 1);
  613. else
  614. fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name);
  615. }
  616. if (!poison && s->poison) {
  617. if (slab_empty(s))
  618. set_obj(s, "poison", 0);
  619. else
  620. fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name);
  621. }
  622. if (tracking && !s->store_user) {
  623. if (slab_empty(s))
  624. set_obj(s, "store_user", 1);
  625. else
  626. fprintf(stderr, "%s not empty cannot enable tracking\n", s->name);
  627. }
  628. if (!tracking && s->store_user) {
  629. if (slab_empty(s))
  630. set_obj(s, "store_user", 0);
  631. else
  632. fprintf(stderr, "%s not empty cannot disable tracking\n", s->name);
  633. }
  634. if (tracing && !s->trace) {
  635. if (slabs == 1)
  636. set_obj(s, "trace", 1);
  637. else
  638. fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name);
  639. }
  640. if (!tracing && s->trace)
  641. set_obj(s, "trace", 1);
  642. }
  643. static void totals(void)
  644. {
  645. struct slabinfo *s;
  646. int used_slabs = 0;
  647. char b1[20], b2[20], b3[20], b4[20];
  648. unsigned long long max = 1ULL << 63;
  649. /* Object size */
  650. unsigned long long min_objsize = max, max_objsize = 0, avg_objsize;
  651. /* Number of partial slabs in a slabcache */
  652. unsigned long long min_partial = max, max_partial = 0,
  653. avg_partial, total_partial = 0;
  654. /* Number of slabs in a slab cache */
  655. unsigned long long min_slabs = max, max_slabs = 0,
  656. avg_slabs, total_slabs = 0;
  657. /* Size of the whole slab */
  658. unsigned long long min_size = max, max_size = 0,
  659. avg_size, total_size = 0;
  660. /* Bytes used for object storage in a slab */
  661. unsigned long long min_used = max, max_used = 0,
  662. avg_used, total_used = 0;
  663. /* Waste: Bytes used for alignment and padding */
  664. unsigned long long min_waste = max, max_waste = 0,
  665. avg_waste, total_waste = 0;
  666. /* Number of objects in a slab */
  667. unsigned long long min_objects = max, max_objects = 0,
  668. avg_objects, total_objects = 0;
  669. /* Waste per object */
  670. unsigned long long min_objwaste = max,
  671. max_objwaste = 0, avg_objwaste,
  672. total_objwaste = 0;
  673. /* Memory per object */
  674. unsigned long long min_memobj = max,
  675. max_memobj = 0, avg_memobj,
  676. total_objsize = 0;
  677. /* Percentage of partial slabs per slab */
  678. unsigned long min_ppart = 100, max_ppart = 0,
  679. avg_ppart, total_ppart = 0;
  680. /* Number of objects in partial slabs */
  681. unsigned long min_partobj = max, max_partobj = 0,
  682. avg_partobj, total_partobj = 0;
  683. /* Percentage of partial objects of all objects in a slab */
  684. unsigned long min_ppartobj = 100, max_ppartobj = 0,
  685. avg_ppartobj, total_ppartobj = 0;
  686. for (s = slabinfo; s < slabinfo + slabs; s++) {
  687. unsigned long long size;
  688. unsigned long used;
  689. unsigned long long wasted;
  690. unsigned long long objwaste;
  691. unsigned long percentage_partial_slabs;
  692. unsigned long percentage_partial_objs;
  693. if (!s->slabs || !s->objects)
  694. continue;
  695. used_slabs++;
  696. size = slab_size(s);
  697. used = s->objects * s->object_size;
  698. wasted = size - used;
  699. objwaste = s->slab_size - s->object_size;
  700. percentage_partial_slabs = s->partial * 100 / s->slabs;
  701. if (percentage_partial_slabs > 100)
  702. percentage_partial_slabs = 100;
  703. percentage_partial_objs = s->objects_partial * 100
  704. / s->objects;
  705. if (percentage_partial_objs > 100)
  706. percentage_partial_objs = 100;
  707. if (s->object_size < min_objsize)
  708. min_objsize = s->object_size;
  709. if (s->partial < min_partial)
  710. min_partial = s->partial;
  711. if (s->slabs < min_slabs)
  712. min_slabs = s->slabs;
  713. if (size < min_size)
  714. min_size = size;
  715. if (wasted < min_waste)
  716. min_waste = wasted;
  717. if (objwaste < min_objwaste)
  718. min_objwaste = objwaste;
  719. if (s->objects < min_objects)
  720. min_objects = s->objects;
  721. if (used < min_used)
  722. min_used = used;
  723. if (s->objects_partial < min_partobj)
  724. min_partobj = s->objects_partial;
  725. if (percentage_partial_slabs < min_ppart)
  726. min_ppart = percentage_partial_slabs;
  727. if (percentage_partial_objs < min_ppartobj)
  728. min_ppartobj = percentage_partial_objs;
  729. if (s->slab_size < min_memobj)
  730. min_memobj = s->slab_size;
  731. if (s->object_size > max_objsize)
  732. max_objsize = s->object_size;
  733. if (s->partial > max_partial)
  734. max_partial = s->partial;
  735. if (s->slabs > max_slabs)
  736. max_slabs = s->slabs;
  737. if (size > max_size)
  738. max_size = size;
  739. if (wasted > max_waste)
  740. max_waste = wasted;
  741. if (objwaste > max_objwaste)
  742. max_objwaste = objwaste;
  743. if (s->objects > max_objects)
  744. max_objects = s->objects;
  745. if (used > max_used)
  746. max_used = used;
  747. if (s->objects_partial > max_partobj)
  748. max_partobj = s->objects_partial;
  749. if (percentage_partial_slabs > max_ppart)
  750. max_ppart = percentage_partial_slabs;
  751. if (percentage_partial_objs > max_ppartobj)
  752. max_ppartobj = percentage_partial_objs;
  753. if (s->slab_size > max_memobj)
  754. max_memobj = s->slab_size;
  755. total_partial += s->partial;
  756. total_slabs += s->slabs;
  757. total_size += size;
  758. total_waste += wasted;
  759. total_objects += s->objects;
  760. total_used += used;
  761. total_partobj += s->objects_partial;
  762. total_ppart += percentage_partial_slabs;
  763. total_ppartobj += percentage_partial_objs;
  764. total_objwaste += s->objects * objwaste;
  765. total_objsize += s->objects * s->slab_size;
  766. }
  767. if (!total_objects) {
  768. printf("No objects\n");
  769. return;
  770. }
  771. if (!used_slabs) {
  772. printf("No slabs\n");
  773. return;
  774. }
  775. /* Per slab averages */
  776. avg_partial = total_partial / used_slabs;
  777. avg_slabs = total_slabs / used_slabs;
  778. avg_size = total_size / used_slabs;
  779. avg_waste = total_waste / used_slabs;
  780. avg_objects = total_objects / used_slabs;
  781. avg_used = total_used / used_slabs;
  782. avg_partobj = total_partobj / used_slabs;
  783. avg_ppart = total_ppart / used_slabs;
  784. avg_ppartobj = total_ppartobj / used_slabs;
  785. /* Per object object sizes */
  786. avg_objsize = total_used / total_objects;
  787. avg_objwaste = total_objwaste / total_objects;
  788. avg_partobj = total_partobj * 100 / total_objects;
  789. avg_memobj = total_objsize / total_objects;
  790. printf("Slabcache Totals\n");
  791. printf("----------------\n");
  792. printf("Slabcaches : %3d Aliases : %3d->%-3d Active: %3d\n",
  793. slabs, aliases, alias_targets, used_slabs);
  794. store_size(b1, total_size);store_size(b2, total_waste);
  795. store_size(b3, total_waste * 100 / total_used);
  796. printf("Memory used: %6s # Loss : %6s MRatio:%6s%%\n", b1, b2, b3);
  797. store_size(b1, total_objects);store_size(b2, total_partobj);
  798. store_size(b3, total_partobj * 100 / total_objects);
  799. printf("# Objects : %6s # PartObj: %6s ORatio:%6s%%\n", b1, b2, b3);
  800. printf("\n");
  801. printf("Per Cache Average Min Max Total\n");
  802. printf("---------------------------------------------------------\n");
  803. store_size(b1, avg_objects);store_size(b2, min_objects);
  804. store_size(b3, max_objects);store_size(b4, total_objects);
  805. printf("#Objects %10s %10s %10s %10s\n",
  806. b1, b2, b3, b4);
  807. store_size(b1, avg_slabs);store_size(b2, min_slabs);
  808. store_size(b3, max_slabs);store_size(b4, total_slabs);
  809. printf("#Slabs %10s %10s %10s %10s\n",
  810. b1, b2, b3, b4);
  811. store_size(b1, avg_partial);store_size(b2, min_partial);
  812. store_size(b3, max_partial);store_size(b4, total_partial);
  813. printf("#PartSlab %10s %10s %10s %10s\n",
  814. b1, b2, b3, b4);
  815. store_size(b1, avg_ppart);store_size(b2, min_ppart);
  816. store_size(b3, max_ppart);
  817. store_size(b4, total_partial * 100 / total_slabs);
  818. printf("%%PartSlab%10s%% %10s%% %10s%% %10s%%\n",
  819. b1, b2, b3, b4);
  820. store_size(b1, avg_partobj);store_size(b2, min_partobj);
  821. store_size(b3, max_partobj);
  822. store_size(b4, total_partobj);
  823. printf("PartObjs %10s %10s %10s %10s\n",
  824. b1, b2, b3, b4);
  825. store_size(b1, avg_ppartobj);store_size(b2, min_ppartobj);
  826. store_size(b3, max_ppartobj);
  827. store_size(b4, total_partobj * 100 / total_objects);
  828. printf("%% PartObj%10s%% %10s%% %10s%% %10s%%\n",
  829. b1, b2, b3, b4);
  830. store_size(b1, avg_size);store_size(b2, min_size);
  831. store_size(b3, max_size);store_size(b4, total_size);
  832. printf("Memory %10s %10s %10s %10s\n",
  833. b1, b2, b3, b4);
  834. store_size(b1, avg_used);store_size(b2, min_used);
  835. store_size(b3, max_used);store_size(b4, total_used);
  836. printf("Used %10s %10s %10s %10s\n",
  837. b1, b2, b3, b4);
  838. store_size(b1, avg_waste);store_size(b2, min_waste);
  839. store_size(b3, max_waste);store_size(b4, total_waste);
  840. printf("Loss %10s %10s %10s %10s\n",
  841. b1, b2, b3, b4);
  842. printf("\n");
  843. printf("Per Object Average Min Max\n");
  844. printf("---------------------------------------------\n");
  845. store_size(b1, avg_memobj);store_size(b2, min_memobj);
  846. store_size(b3, max_memobj);
  847. printf("Memory %10s %10s %10s\n",
  848. b1, b2, b3);
  849. store_size(b1, avg_objsize);store_size(b2, min_objsize);
  850. store_size(b3, max_objsize);
  851. printf("User %10s %10s %10s\n",
  852. b1, b2, b3);
  853. store_size(b1, avg_objwaste);store_size(b2, min_objwaste);
  854. store_size(b3, max_objwaste);
  855. printf("Loss %10s %10s %10s\n",
  856. b1, b2, b3);
  857. }
  858. static void sort_slabs(void)
  859. {
  860. struct slabinfo *s1,*s2;
  861. for (s1 = slabinfo; s1 < slabinfo + slabs; s1++) {
  862. for (s2 = s1 + 1; s2 < slabinfo + slabs; s2++) {
  863. int result;
  864. if (sort_size)
  865. result = slab_size(s1) < slab_size(s2);
  866. else if (sort_active)
  867. result = slab_activity(s1) < slab_activity(s2);
  868. else
  869. result = strcasecmp(s1->name, s2->name);
  870. if (show_inverted)
  871. result = -result;
  872. if (result > 0) {
  873. struct slabinfo t;
  874. memcpy(&t, s1, sizeof(struct slabinfo));
  875. memcpy(s1, s2, sizeof(struct slabinfo));
  876. memcpy(s2, &t, sizeof(struct slabinfo));
  877. }
  878. }
  879. }
  880. }
  881. static void sort_aliases(void)
  882. {
  883. struct aliasinfo *a1,*a2;
  884. for (a1 = aliasinfo; a1 < aliasinfo + aliases; a1++) {
  885. for (a2 = a1 + 1; a2 < aliasinfo + aliases; a2++) {
  886. char *n1, *n2;
  887. n1 = a1->name;
  888. n2 = a2->name;
  889. if (show_alias && !show_inverted) {
  890. n1 = a1->ref;
  891. n2 = a2->ref;
  892. }
  893. if (strcasecmp(n1, n2) > 0) {
  894. struct aliasinfo t;
  895. memcpy(&t, a1, sizeof(struct aliasinfo));
  896. memcpy(a1, a2, sizeof(struct aliasinfo));
  897. memcpy(a2, &t, sizeof(struct aliasinfo));
  898. }
  899. }
  900. }
  901. }
  902. static void link_slabs(void)
  903. {
  904. struct aliasinfo *a;
  905. struct slabinfo *s;
  906. for (a = aliasinfo; a < aliasinfo + aliases; a++) {
  907. for (s = slabinfo; s < slabinfo + slabs; s++)
  908. if (strcmp(a->ref, s->name) == 0) {
  909. a->slab = s;
  910. s->refs++;
  911. break;
  912. }
  913. if (s == slabinfo + slabs)
  914. fatal("Unresolved alias %s\n", a->ref);
  915. }
  916. }
  917. static void alias(void)
  918. {
  919. struct aliasinfo *a;
  920. char *active = NULL;
  921. sort_aliases();
  922. link_slabs();
  923. for(a = aliasinfo; a < aliasinfo + aliases; a++) {
  924. if (!show_single_ref && a->slab->refs == 1)
  925. continue;
  926. if (!show_inverted) {
  927. if (active) {
  928. if (strcmp(a->slab->name, active) == 0) {
  929. printf(" %s", a->name);
  930. continue;
  931. }
  932. }
  933. printf("\n%-12s <- %s", a->slab->name, a->name);
  934. active = a->slab->name;
  935. }
  936. else
  937. printf("%-20s -> %s\n", a->name, a->slab->name);
  938. }
  939. if (active)
  940. printf("\n");
  941. }
  942. static void rename_slabs(void)
  943. {
  944. struct slabinfo *s;
  945. struct aliasinfo *a;
  946. for (s = slabinfo; s < slabinfo + slabs; s++) {
  947. if (*s->name != ':')
  948. continue;
  949. if (s->refs > 1 && !show_first_alias)
  950. continue;
  951. a = find_one_alias(s);
  952. if (a)
  953. s->name = a->name;
  954. else {
  955. s->name = "*";
  956. actual_slabs--;
  957. }
  958. }
  959. }
  960. static int slab_mismatch(char *slab)
  961. {
  962. return regexec(&pattern, slab, 0, NULL, 0);
  963. }
  964. static void read_slab_dir(void)
  965. {
  966. DIR *dir;
  967. struct dirent *de;
  968. struct slabinfo *slab = slabinfo;
  969. struct aliasinfo *alias = aliasinfo;
  970. char *p;
  971. char *t;
  972. int count;
  973. if (chdir("/sys/kernel/slab") && chdir("/sys/slab"))
  974. fatal("SYSFS support for SLUB not active\n");
  975. dir = opendir(".");
  976. while ((de = readdir(dir))) {
  977. if (de->d_name[0] == '.' ||
  978. (de->d_name[0] != ':' && slab_mismatch(de->d_name)))
  979. continue;
  980. switch (de->d_type) {
  981. case DT_LNK:
  982. alias->name = strdup(de->d_name);
  983. count = readlink(de->d_name, buffer, sizeof(buffer));
  984. if (count < 0)
  985. fatal("Cannot read symlink %s\n", de->d_name);
  986. buffer[count] = 0;
  987. p = buffer + count;
  988. while (p > buffer && p[-1] != '/')
  989. p--;
  990. alias->ref = strdup(p);
  991. alias++;
  992. break;
  993. case DT_DIR:
  994. if (chdir(de->d_name))
  995. fatal("Unable to access slab %s\n", slab->name);
  996. slab->name = strdup(de->d_name);
  997. slab->alias = 0;
  998. slab->refs = 0;
  999. slab->aliases = get_obj("aliases");
  1000. slab->align = get_obj("align");
  1001. slab->cache_dma = get_obj("cache_dma");
  1002. slab->cpu_slabs = get_obj("cpu_slabs");
  1003. slab->destroy_by_rcu = get_obj("destroy_by_rcu");
  1004. slab->hwcache_align = get_obj("hwcache_align");
  1005. slab->object_size = get_obj("object_size");
  1006. slab->objects = get_obj("objects");
  1007. slab->objects_partial = get_obj("objects_partial");
  1008. slab->objects_total = get_obj("objects_total");
  1009. slab->objs_per_slab = get_obj("objs_per_slab");
  1010. slab->order = get_obj("order");
  1011. slab->partial = get_obj("partial");
  1012. slab->partial = get_obj_and_str("partial", &t);
  1013. decode_numa_list(slab->numa_partial, t);
  1014. free(t);
  1015. slab->poison = get_obj("poison");
  1016. slab->reclaim_account = get_obj("reclaim_account");
  1017. slab->red_zone = get_obj("red_zone");
  1018. slab->sanity_checks = get_obj("sanity_checks");
  1019. slab->slab_size = get_obj("slab_size");
  1020. slab->slabs = get_obj_and_str("slabs", &t);
  1021. decode_numa_list(slab->numa, t);
  1022. free(t);
  1023. slab->store_user = get_obj("store_user");
  1024. slab->trace = get_obj("trace");
  1025. slab->alloc_fastpath = get_obj("alloc_fastpath");
  1026. slab->alloc_slowpath = get_obj("alloc_slowpath");
  1027. slab->free_fastpath = get_obj("free_fastpath");
  1028. slab->free_slowpath = get_obj("free_slowpath");
  1029. slab->free_frozen= get_obj("free_frozen");
  1030. slab->free_add_partial = get_obj("free_add_partial");
  1031. slab->free_remove_partial = get_obj("free_remove_partial");
  1032. slab->alloc_from_partial = get_obj("alloc_from_partial");
  1033. slab->alloc_slab = get_obj("alloc_slab");
  1034. slab->alloc_refill = get_obj("alloc_refill");
  1035. slab->free_slab = get_obj("free_slab");
  1036. slab->cpuslab_flush = get_obj("cpuslab_flush");
  1037. slab->deactivate_full = get_obj("deactivate_full");
  1038. slab->deactivate_empty = get_obj("deactivate_empty");
  1039. slab->deactivate_to_head = get_obj("deactivate_to_head");
  1040. slab->deactivate_to_tail = get_obj("deactivate_to_tail");
  1041. slab->deactivate_remote_frees = get_obj("deactivate_remote_frees");
  1042. slab->order_fallback = get_obj("order_fallback");
  1043. slab->cmpxchg_double_cpu_fail = get_obj("cmpxchg_double_cpu_fail");
  1044. slab->cmpxchg_double_fail = get_obj("cmpxchg_double_fail");
  1045. slab->alloc_node_mismatch = get_obj("alloc_node_mismatch");
  1046. slab->deactivate_bypass = get_obj("deactivate_bypass");
  1047. chdir("..");
  1048. if (slab->name[0] == ':')
  1049. alias_targets++;
  1050. slab++;
  1051. break;
  1052. default :
  1053. fatal("Unknown file type %lx\n", de->d_type);
  1054. }
  1055. }
  1056. closedir(dir);
  1057. slabs = slab - slabinfo;
  1058. actual_slabs = slabs;
  1059. aliases = alias - aliasinfo;
  1060. if (slabs > MAX_SLABS)
  1061. fatal("Too many slabs\n");
  1062. if (aliases > MAX_ALIASES)
  1063. fatal("Too many aliases\n");
  1064. }
  1065. static void output_slabs(void)
  1066. {
  1067. struct slabinfo *slab;
  1068. for (slab = slabinfo; slab < slabinfo + slabs; slab++) {
  1069. if (slab->alias)
  1070. continue;
  1071. if (show_numa)
  1072. slab_numa(slab, 0);
  1073. else if (show_track)
  1074. show_tracking(slab);
  1075. else if (validate)
  1076. slab_validate(slab);
  1077. else if (shrink)
  1078. slab_shrink(slab);
  1079. else if (set_debug)
  1080. slab_debug(slab);
  1081. else if (show_ops)
  1082. ops(slab);
  1083. else if (show_slab)
  1084. slabcache(slab);
  1085. else if (show_report)
  1086. report(slab);
  1087. }
  1088. }
  1089. struct option opts[] = {
  1090. { "aliases", 0, NULL, 'a' },
  1091. { "activity", 0, NULL, 'A' },
  1092. { "debug", 2, NULL, 'd' },
  1093. { "display-activity", 0, NULL, 'D' },
  1094. { "empty", 0, NULL, 'e' },
  1095. { "first-alias", 0, NULL, 'f' },
  1096. { "help", 0, NULL, 'h' },
  1097. { "inverted", 0, NULL, 'i'},
  1098. { "numa", 0, NULL, 'n' },
  1099. { "ops", 0, NULL, 'o' },
  1100. { "report", 0, NULL, 'r' },
  1101. { "shrink", 0, NULL, 's' },
  1102. { "slabs", 0, NULL, 'l' },
  1103. { "track", 0, NULL, 't'},
  1104. { "validate", 0, NULL, 'v' },
  1105. { "zero", 0, NULL, 'z' },
  1106. { "1ref", 0, NULL, '1'},
  1107. { NULL, 0, NULL, 0 }
  1108. };
  1109. int main(int argc, char *argv[])
  1110. {
  1111. int c;
  1112. int err;
  1113. char *pattern_source;
  1114. page_size = getpagesize();
  1115. while ((c = getopt_long(argc, argv, "aAd::Defhil1noprstvzTS",
  1116. opts, NULL)) != -1)
  1117. switch (c) {
  1118. case '1':
  1119. show_single_ref = 1;
  1120. break;
  1121. case 'a':
  1122. show_alias = 1;
  1123. break;
  1124. case 'A':
  1125. sort_active = 1;
  1126. break;
  1127. case 'd':
  1128. set_debug = 1;
  1129. if (!debug_opt_scan(optarg))
  1130. fatal("Invalid debug option '%s'\n", optarg);
  1131. break;
  1132. case 'D':
  1133. show_activity = 1;
  1134. break;
  1135. case 'e':
  1136. show_empty = 1;
  1137. break;
  1138. case 'f':
  1139. show_first_alias = 1;
  1140. break;
  1141. case 'h':
  1142. usage();
  1143. return 0;
  1144. case 'i':
  1145. show_inverted = 1;
  1146. break;
  1147. case 'n':
  1148. show_numa = 1;
  1149. break;
  1150. case 'o':
  1151. show_ops = 1;
  1152. break;
  1153. case 'r':
  1154. show_report = 1;
  1155. break;
  1156. case 's':
  1157. shrink = 1;
  1158. break;
  1159. case 'l':
  1160. show_slab = 1;
  1161. break;
  1162. case 't':
  1163. show_track = 1;
  1164. break;
  1165. case 'v':
  1166. validate = 1;
  1167. break;
  1168. case 'z':
  1169. skip_zero = 0;
  1170. break;
  1171. case 'T':
  1172. show_totals = 1;
  1173. break;
  1174. case 'S':
  1175. sort_size = 1;
  1176. break;
  1177. default:
  1178. fatal("%s: Invalid option '%c'\n", argv[0], optopt);
  1179. }
  1180. if (!show_slab && !show_alias && !show_track && !show_report
  1181. && !validate && !shrink && !set_debug && !show_ops)
  1182. show_slab = 1;
  1183. if (argc > optind)
  1184. pattern_source = argv[optind];
  1185. else
  1186. pattern_source = ".*";
  1187. err = regcomp(&pattern, pattern_source, REG_ICASE|REG_NOSUB);
  1188. if (err)
  1189. fatal("%s: Invalid pattern '%s' code %d\n",
  1190. argv[0], pattern_source, err);
  1191. read_slab_dir();
  1192. if (show_alias)
  1193. alias();
  1194. else
  1195. if (show_totals)
  1196. totals();
  1197. else {
  1198. link_slabs();
  1199. rename_slabs();
  1200. sort_slabs();
  1201. output_slabs();
  1202. }
  1203. return 0;
  1204. }