Commit f1a5ab1210579e2d3ac8c0c227645823af5aafb0
Committed by
Linus Torvalds
1 parent
d7a5752c0c
Exists in
master
and in
7 other branches
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
mm/vmstat.c
... | ... | @@ -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; |