diff options
| author | Joonsoo Kim <iamjoonsoo.kim@lge.com> | 2015-02-11 18:27:06 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-11 20:06:04 -0500 |
| commit | 837d026d560c5ef26abeca0441713d82e4e82cad (patch) | |
| tree | 074e7941df8d83fc7fdb0680883989c84c3d654c | |
| parent | e34d85f0e3c60f7226e5589898b7c7c5cd2a4f02 (diff) | |
mm/compaction: more trace to understand when/why compaction start/finish
It is not well analyzed that when/why compaction start/finish or not.
With these new tracepoints, we can know much more about start/finish
reason of compaction. I can find following bug with these tracepoint.
http://www.spinics.net/lists/linux-mm/msg81582.html
Signed-off-by: Joonsoo Kim <iamjoonsoo.kim@lge.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Mel Gorman <mgorman@suse.de>
Cc: David Rientjes <rientjes@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | include/linux/compaction.h | 3 | ||||
| -rw-r--r-- | include/trace/events/compaction.h | 74 | ||||
| -rw-r--r-- | mm/compaction.c | 38 |
3 files changed, 111 insertions, 4 deletions
diff --git a/include/linux/compaction.h b/include/linux/compaction.h index db64cae06530..501d7513aac1 100644 --- a/include/linux/compaction.h +++ b/include/linux/compaction.h | |||
| @@ -12,6 +12,9 @@ | |||
| 12 | #define COMPACT_PARTIAL 3 | 12 | #define COMPACT_PARTIAL 3 |
| 13 | /* The full zone was compacted */ | 13 | /* The full zone was compacted */ |
| 14 | #define COMPACT_COMPLETE 4 | 14 | #define COMPACT_COMPLETE 4 |
| 15 | /* For more detailed tracepoint output */ | ||
| 16 | #define COMPACT_NO_SUITABLE_PAGE 5 | ||
| 17 | #define COMPACT_NOT_SUITABLE_ZONE 6 | ||
| 15 | /* When adding new state, please change compaction_status_string, too */ | 18 | /* When adding new state, please change compaction_status_string, too */ |
| 16 | 19 | ||
| 17 | /* Used to signal whether compaction detected need_sched() or lock contention */ | 20 | /* Used to signal whether compaction detected need_sched() or lock contention */ |
diff --git a/include/trace/events/compaction.h b/include/trace/events/compaction.h index 139020b55612..d46535801f63 100644 --- a/include/trace/events/compaction.h +++ b/include/trace/events/compaction.h | |||
| @@ -164,6 +164,80 @@ TRACE_EVENT(mm_compaction_end, | |||
| 164 | compaction_status_string[__entry->status]) | 164 | compaction_status_string[__entry->status]) |
| 165 | ); | 165 | ); |
| 166 | 166 | ||
| 167 | TRACE_EVENT(mm_compaction_try_to_compact_pages, | ||
| 168 | |||
| 169 | TP_PROTO( | ||
| 170 | int order, | ||
| 171 | gfp_t gfp_mask, | ||
| 172 | enum migrate_mode mode), | ||
| 173 | |||
| 174 | TP_ARGS(order, gfp_mask, mode), | ||
| 175 | |||
| 176 | TP_STRUCT__entry( | ||
| 177 | __field(int, order) | ||
| 178 | __field(gfp_t, gfp_mask) | ||
| 179 | __field(enum migrate_mode, mode) | ||
| 180 | ), | ||
| 181 | |||
| 182 | TP_fast_assign( | ||
| 183 | __entry->order = order; | ||
| 184 | __entry->gfp_mask = gfp_mask; | ||
| 185 | __entry->mode = mode; | ||
| 186 | ), | ||
| 187 | |||
| 188 | TP_printk("order=%d gfp_mask=0x%x mode=%d", | ||
| 189 | __entry->order, | ||
| 190 | __entry->gfp_mask, | ||
| 191 | (int)__entry->mode) | ||
| 192 | ); | ||
| 193 | |||
| 194 | DECLARE_EVENT_CLASS(mm_compaction_suitable_template, | ||
| 195 | |||
| 196 | TP_PROTO(struct zone *zone, | ||
| 197 | int order, | ||
| 198 | int ret), | ||
| 199 | |||
| 200 | TP_ARGS(zone, order, ret), | ||
| 201 | |||
| 202 | TP_STRUCT__entry( | ||
| 203 | __field(int, nid) | ||
| 204 | __field(char *, name) | ||
| 205 | __field(int, order) | ||
| 206 | __field(int, ret) | ||
| 207 | ), | ||
| 208 | |||
| 209 | TP_fast_assign( | ||
| 210 | __entry->nid = zone_to_nid(zone); | ||
| 211 | __entry->name = (char *)zone->name; | ||
| 212 | __entry->order = order; | ||
| 213 | __entry->ret = ret; | ||
| 214 | ), | ||
| 215 | |||
| 216 | TP_printk("node=%d zone=%-8s order=%d ret=%s", | ||
| 217 | __entry->nid, | ||
| 218 | __entry->name, | ||
| 219 | __entry->order, | ||
| 220 | compaction_status_string[__entry->ret]) | ||
| 221 | ); | ||
| 222 | |||
| 223 | DEFINE_EVENT(mm_compaction_suitable_template, mm_compaction_finished, | ||
| 224 | |||
| 225 | TP_PROTO(struct zone *zone, | ||
| 226 | int order, | ||
| 227 | int ret), | ||
| 228 | |||
| 229 | TP_ARGS(zone, order, ret) | ||
| 230 | ); | ||
| 231 | |||
| 232 | DEFINE_EVENT(mm_compaction_suitable_template, mm_compaction_suitable, | ||
| 233 | |||
| 234 | TP_PROTO(struct zone *zone, | ||
| 235 | int order, | ||
| 236 | int ret), | ||
| 237 | |||
| 238 | TP_ARGS(zone, order, ret) | ||
| 239 | ); | ||
| 240 | |||
| 167 | #endif /* _TRACE_COMPACTION_H */ | 241 | #endif /* _TRACE_COMPACTION_H */ |
| 168 | 242 | ||
| 169 | /* This part must be outside protection */ | 243 | /* This part must be outside protection */ |
diff --git a/mm/compaction.c b/mm/compaction.c index b12df9fe10b4..b6ede459c1bb 100644 --- a/mm/compaction.c +++ b/mm/compaction.c | |||
| @@ -41,6 +41,8 @@ static const char *const compaction_status_string[] = { | |||
| 41 | "continue", | 41 | "continue", |
| 42 | "partial", | 42 | "partial", |
| 43 | "complete", | 43 | "complete", |
| 44 | "no_suitable_page", | ||
| 45 | "not_suitable_zone", | ||
| 44 | }; | 46 | }; |
| 45 | #endif | 47 | #endif |
| 46 | 48 | ||
| @@ -1049,7 +1051,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, | |||
| 1049 | return cc->nr_migratepages ? ISOLATE_SUCCESS : ISOLATE_NONE; | 1051 | return cc->nr_migratepages ? ISOLATE_SUCCESS : ISOLATE_NONE; |
| 1050 | } | 1052 | } |
| 1051 | 1053 | ||
| 1052 | static int compact_finished(struct zone *zone, struct compact_control *cc, | 1054 | static int __compact_finished(struct zone *zone, struct compact_control *cc, |
| 1053 | const int migratetype) | 1055 | const int migratetype) |
| 1054 | { | 1056 | { |
| 1055 | unsigned int order; | 1057 | unsigned int order; |
| @@ -1104,7 +1106,20 @@ static int compact_finished(struct zone *zone, struct compact_control *cc, | |||
| 1104 | return COMPACT_PARTIAL; | 1106 | return COMPACT_PARTIAL; |
| 1105 | } | 1107 | } |
| 1106 | 1108 | ||
| 1107 | return COMPACT_CONTINUE; | 1109 | return COMPACT_NO_SUITABLE_PAGE; |
| 1110 | } | ||
| 1111 | |||
| 1112 | static int compact_finished(struct zone *zone, struct compact_control *cc, | ||
| 1113 | const int migratetype) | ||
| 1114 | { | ||
| 1115 | int ret; | ||
| 1116 | |||
| 1117 | ret = __compact_finished(zone, cc, migratetype); | ||
| 1118 | trace_mm_compaction_finished(zone, cc->order, ret); | ||
| 1119 | if (ret == COMPACT_NO_SUITABLE_PAGE) | ||
| 1120 | ret = COMPACT_CONTINUE; | ||
| 1121 | |||
| 1122 | return ret; | ||
| 1108 | } | 1123 | } |
| 1109 | 1124 | ||
| 1110 | /* | 1125 | /* |
| @@ -1114,7 +1129,7 @@ static int compact_finished(struct zone *zone, struct compact_control *cc, | |||
| 1114 | * COMPACT_PARTIAL - If the allocation would succeed without compaction | 1129 | * COMPACT_PARTIAL - If the allocation would succeed without compaction |
| 1115 | * COMPACT_CONTINUE - If compaction should run now | 1130 | * COMPACT_CONTINUE - If compaction should run now |
| 1116 | */ | 1131 | */ |
| 1117 | unsigned long compaction_suitable(struct zone *zone, int order, | 1132 | static unsigned long __compaction_suitable(struct zone *zone, int order, |
| 1118 | int alloc_flags, int classzone_idx) | 1133 | int alloc_flags, int classzone_idx) |
| 1119 | { | 1134 | { |
| 1120 | int fragindex; | 1135 | int fragindex; |
| @@ -1158,11 +1173,24 @@ unsigned long compaction_suitable(struct zone *zone, int order, | |||
| 1158 | */ | 1173 | */ |
| 1159 | fragindex = fragmentation_index(zone, order); | 1174 | fragindex = fragmentation_index(zone, order); |
| 1160 | if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold) | 1175 | if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold) |
| 1161 | return COMPACT_SKIPPED; | 1176 | return COMPACT_NOT_SUITABLE_ZONE; |
| 1162 | 1177 | ||
| 1163 | return COMPACT_CONTINUE; | 1178 | return COMPACT_CONTINUE; |
| 1164 | } | 1179 | } |
| 1165 | 1180 | ||
| 1181 | unsigned long compaction_suitable(struct zone *zone, int order, | ||
| 1182 | int alloc_flags, int classzone_idx) | ||
| 1183 | { | ||
| 1184 | unsigned long ret; | ||
| 1185 | |||
| 1186 | ret = __compaction_suitable(zone, order, alloc_flags, classzone_idx); | ||
| 1187 | trace_mm_compaction_suitable(zone, order, ret); | ||
| 1188 | if (ret == COMPACT_NOT_SUITABLE_ZONE) | ||
| 1189 | ret = COMPACT_SKIPPED; | ||
| 1190 | |||
| 1191 | return ret; | ||
| 1192 | } | ||
| 1193 | |||
| 1166 | static int compact_zone(struct zone *zone, struct compact_control *cc) | 1194 | static int compact_zone(struct zone *zone, struct compact_control *cc) |
| 1167 | { | 1195 | { |
| 1168 | int ret; | 1196 | int ret; |
| @@ -1376,6 +1404,8 @@ unsigned long try_to_compact_pages(gfp_t gfp_mask, unsigned int order, | |||
| 1376 | if (!order || !may_enter_fs || !may_perform_io) | 1404 | if (!order || !may_enter_fs || !may_perform_io) |
| 1377 | return COMPACT_SKIPPED; | 1405 | return COMPACT_SKIPPED; |
| 1378 | 1406 | ||
| 1407 | trace_mm_compaction_try_to_compact_pages(order, gfp_mask, mode); | ||
| 1408 | |||
| 1379 | /* Compact each zone in the list */ | 1409 | /* Compact each zone in the list */ |
| 1380 | for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx, | 1410 | for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx, |
| 1381 | ac->nodemask) { | 1411 | ac->nodemask) { |
