Commit f1a5ab1210579e2d3ac8c0c227645823af5aafb0

Authored by Mel Gorman
Committed by Linus Torvalds
1 parent d7a5752c0c

mm: export fragmentation index via debugfs

The fragmentation fragmentation index, is only meaningful if an allocation
would fail and indicates what the failure is due to.  A value of -1 such
as in many of the examples above states that the allocation would succeed.
 If it would fail, the value is between 0 and 1.  A value tending towards
0 implies the allocation failed due to a lack of memory.  A value tending
towards 1 implies it failed due to external fragmentation.

For the most part, the huge page size will be the size of interest but not
necessarily so it is exported on a per-order and per-zo basis via
/sys/kernel/debug/extfrag/extfrag_index

> cat /sys/kernel/debug/extfrag/extfrag_index
Node 0, zone      DMA -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.00
Node 0, zone   Normal -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 -1.000 0.954

Signed-off-by: Mel Gorman <mel@csn.ul.ie>
Reviewed-by: Minchan Kim <minchan.kim@gmail.com>
Acked-by: Rik van Riel <riel@redhat.com>
Reviewed-by: Christoph Lameter <cl@linux-foundation.org>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 84 additions and 0 deletions Side-by-side Diff

... ... @@ -16,6 +16,7 @@
16 16 #include <linux/cpu.h>
17 17 #include <linux/vmstat.h>
18 18 #include <linux/sched.h>
  19 +#include <linux/math64.h>
19 20  
20 21 #ifdef CONFIG_VM_EVENT_COUNTERS
21 22 DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}};
... ... @@ -420,6 +421,33 @@
420 421 (order - suitable_order);
421 422 }
422 423 }
  424 +
  425 +/*
  426 + * A fragmentation index only makes sense if an allocation of a requested
  427 + * size would fail. If that is true, the fragmentation index indicates
  428 + * whether external fragmentation or a lack of memory was the problem.
  429 + * The value can be used to determine if page reclaim or compaction
  430 + * should be used
  431 + */
  432 +int fragmentation_index(unsigned int order, struct contig_page_info *info)
  433 +{
  434 + unsigned long requested = 1UL << order;
  435 +
  436 + if (!info->free_blocks_total)
  437 + return 0;
  438 +
  439 + /* Fragmentation index only makes sense when a request would fail */
  440 + if (info->free_blocks_suitable)
  441 + return -1000;
  442 +
  443 + /*
  444 + * Index is between 0 and 1 so return within 3 decimal places
  445 + *
  446 + * 0 => allocation would fail due to lack of memory
  447 + * 1 => allocation would fail due to fragmentation
  448 + */
  449 + return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total);
  450 +}
423 451 #endif
424 452  
425 453 #if defined(CONFIG_PROC_FS) || defined(CONFIG_COMPACTION)
... ... @@ -1087,6 +1115,58 @@
1087 1115 .release = seq_release,
1088 1116 };
1089 1117  
  1118 +static void extfrag_show_print(struct seq_file *m,
  1119 + pg_data_t *pgdat, struct zone *zone)
  1120 +{
  1121 + unsigned int order;
  1122 + int index;
  1123 +
  1124 + /* Alloc on stack as interrupts are disabled for zone walk */
  1125 + struct contig_page_info info;
  1126 +
  1127 + seq_printf(m, "Node %d, zone %8s ",
  1128 + pgdat->node_id,
  1129 + zone->name);
  1130 + for (order = 0; order < MAX_ORDER; ++order) {
  1131 + fill_contig_page_info(zone, order, &info);
  1132 + index = fragmentation_index(order, &info);
  1133 + seq_printf(m, "%d.%03d ", index / 1000, index % 1000);
  1134 + }
  1135 +
  1136 + seq_putc(m, '\n');
  1137 +}
  1138 +
  1139 +/*
  1140 + * Display fragmentation index for orders that allocations would fail for
  1141 + */
  1142 +static int extfrag_show(struct seq_file *m, void *arg)
  1143 +{
  1144 + pg_data_t *pgdat = (pg_data_t *)arg;
  1145 +
  1146 + walk_zones_in_node(m, pgdat, extfrag_show_print);
  1147 +
  1148 + return 0;
  1149 +}
  1150 +
  1151 +static const struct seq_operations extfrag_op = {
  1152 + .start = frag_start,
  1153 + .next = frag_next,
  1154 + .stop = frag_stop,
  1155 + .show = extfrag_show,
  1156 +};
  1157 +
  1158 +static int extfrag_open(struct inode *inode, struct file *file)
  1159 +{
  1160 + return seq_open(file, &extfrag_op);
  1161 +}
  1162 +
  1163 +static const struct file_operations extfrag_file_ops = {
  1164 + .open = extfrag_open,
  1165 + .read = seq_read,
  1166 + .llseek = seq_lseek,
  1167 + .release = seq_release,
  1168 +};
  1169 +
1090 1170 static int __init extfrag_debug_init(void)
1091 1171 {
1092 1172 extfrag_debug_root = debugfs_create_dir("extfrag", NULL);
... ... @@ -1095,6 +1175,10 @@
1095 1175  
1096 1176 if (!debugfs_create_file("unusable_index", 0444,
1097 1177 extfrag_debug_root, NULL, &unusable_file_ops))
  1178 + return -ENOMEM;
  1179 +
  1180 + if (!debugfs_create_file("extfrag_index", 0444,
  1181 + extfrag_debug_root, NULL, &extfrag_file_ops))
1098 1182 return -ENOMEM;
1099 1183  
1100 1184 return 0;