diff options
author | Mel Gorman <mgorman@techsingularity.net> | 2016-05-19 20:14:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-05-19 22:12:14 -0400 |
commit | 0b423ca22f95a867f789aab1fe57ee4e378df43b (patch) | |
tree | cf0231b630d9be51604133f20d56a4e617914a33 /mm/page_alloc.c | |
parent | e5b31ac2ca2cd0cf6bf2fcbb708ed01466c89aaa (diff) |
mm, page_alloc: inline pageblock lookup in page free fast paths
The function call overhead of get_pfnblock_flags_mask() is measurable in
the page free paths. This patch uses an inlined version that is faster.
Signed-off-by: Mel Gorman <mgorman@techsingularity.net>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 188 |
1 files changed, 100 insertions, 88 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 822ce86fc883..bdf7a13311b5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -352,6 +352,106 @@ static inline bool update_defer_init(pg_data_t *pgdat, | |||
352 | } | 352 | } |
353 | #endif | 353 | #endif |
354 | 354 | ||
355 | /* Return a pointer to the bitmap storing bits affecting a block of pages */ | ||
356 | static inline unsigned long *get_pageblock_bitmap(struct page *page, | ||
357 | unsigned long pfn) | ||
358 | { | ||
359 | #ifdef CONFIG_SPARSEMEM | ||
360 | return __pfn_to_section(pfn)->pageblock_flags; | ||
361 | #else | ||
362 | return page_zone(page)->pageblock_flags; | ||
363 | #endif /* CONFIG_SPARSEMEM */ | ||
364 | } | ||
365 | |||
366 | static inline int pfn_to_bitidx(struct page *page, unsigned long pfn) | ||
367 | { | ||
368 | #ifdef CONFIG_SPARSEMEM | ||
369 | pfn &= (PAGES_PER_SECTION-1); | ||
370 | return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; | ||
371 | #else | ||
372 | pfn = pfn - round_down(page_zone(page)->zone_start_pfn, pageblock_nr_pages); | ||
373 | return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; | ||
374 | #endif /* CONFIG_SPARSEMEM */ | ||
375 | } | ||
376 | |||
377 | /** | ||
378 | * get_pfnblock_flags_mask - Return the requested group of flags for the pageblock_nr_pages block of pages | ||
379 | * @page: The page within the block of interest | ||
380 | * @pfn: The target page frame number | ||
381 | * @end_bitidx: The last bit of interest to retrieve | ||
382 | * @mask: mask of bits that the caller is interested in | ||
383 | * | ||
384 | * Return: pageblock_bits flags | ||
385 | */ | ||
386 | static __always_inline unsigned long __get_pfnblock_flags_mask(struct page *page, | ||
387 | unsigned long pfn, | ||
388 | unsigned long end_bitidx, | ||
389 | unsigned long mask) | ||
390 | { | ||
391 | unsigned long *bitmap; | ||
392 | unsigned long bitidx, word_bitidx; | ||
393 | unsigned long word; | ||
394 | |||
395 | bitmap = get_pageblock_bitmap(page, pfn); | ||
396 | bitidx = pfn_to_bitidx(page, pfn); | ||
397 | word_bitidx = bitidx / BITS_PER_LONG; | ||
398 | bitidx &= (BITS_PER_LONG-1); | ||
399 | |||
400 | word = bitmap[word_bitidx]; | ||
401 | bitidx += end_bitidx; | ||
402 | return (word >> (BITS_PER_LONG - bitidx - 1)) & mask; | ||
403 | } | ||
404 | |||
405 | unsigned long get_pfnblock_flags_mask(struct page *page, unsigned long pfn, | ||
406 | unsigned long end_bitidx, | ||
407 | unsigned long mask) | ||
408 | { | ||
409 | return __get_pfnblock_flags_mask(page, pfn, end_bitidx, mask); | ||
410 | } | ||
411 | |||
412 | static __always_inline int get_pfnblock_migratetype(struct page *page, unsigned long pfn) | ||
413 | { | ||
414 | return __get_pfnblock_flags_mask(page, pfn, PB_migrate_end, MIGRATETYPE_MASK); | ||
415 | } | ||
416 | |||
417 | /** | ||
418 | * set_pfnblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages | ||
419 | * @page: The page within the block of interest | ||
420 | * @flags: The flags to set | ||
421 | * @pfn: The target page frame number | ||
422 | * @end_bitidx: The last bit of interest | ||
423 | * @mask: mask of bits that the caller is interested in | ||
424 | */ | ||
425 | void set_pfnblock_flags_mask(struct page *page, unsigned long flags, | ||
426 | unsigned long pfn, | ||
427 | unsigned long end_bitidx, | ||
428 | unsigned long mask) | ||
429 | { | ||
430 | unsigned long *bitmap; | ||
431 | unsigned long bitidx, word_bitidx; | ||
432 | unsigned long old_word, word; | ||
433 | |||
434 | BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4); | ||
435 | |||
436 | bitmap = get_pageblock_bitmap(page, pfn); | ||
437 | bitidx = pfn_to_bitidx(page, pfn); | ||
438 | word_bitidx = bitidx / BITS_PER_LONG; | ||
439 | bitidx &= (BITS_PER_LONG-1); | ||
440 | |||
441 | VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page); | ||
442 | |||
443 | bitidx += end_bitidx; | ||
444 | mask <<= (BITS_PER_LONG - bitidx - 1); | ||
445 | flags <<= (BITS_PER_LONG - bitidx - 1); | ||
446 | |||
447 | word = READ_ONCE(bitmap[word_bitidx]); | ||
448 | for (;;) { | ||
449 | old_word = cmpxchg(&bitmap[word_bitidx], word, (word & ~mask) | flags); | ||
450 | if (word == old_word) | ||
451 | break; | ||
452 | word = old_word; | ||
453 | } | ||
454 | } | ||
355 | 455 | ||
356 | void set_pageblock_migratetype(struct page *page, int migratetype) | 456 | void set_pageblock_migratetype(struct page *page, int migratetype) |
357 | { | 457 | { |
@@ -6831,94 +6931,6 @@ void *__init alloc_large_system_hash(const char *tablename, | |||
6831 | return table; | 6931 | return table; |
6832 | } | 6932 | } |
6833 | 6933 | ||
6834 | /* Return a pointer to the bitmap storing bits affecting a block of pages */ | ||
6835 | static inline unsigned long *get_pageblock_bitmap(struct page *page, | ||
6836 | unsigned long pfn) | ||
6837 | { | ||
6838 | #ifdef CONFIG_SPARSEMEM | ||
6839 | return __pfn_to_section(pfn)->pageblock_flags; | ||
6840 | #else | ||
6841 | return page_zone(page)->pageblock_flags; | ||
6842 | #endif /* CONFIG_SPARSEMEM */ | ||
6843 | } | ||
6844 | |||
6845 | static inline int pfn_to_bitidx(struct page *page, unsigned long pfn) | ||
6846 | { | ||
6847 | #ifdef CONFIG_SPARSEMEM | ||
6848 | pfn &= (PAGES_PER_SECTION-1); | ||
6849 | return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; | ||
6850 | #else | ||
6851 | pfn = pfn - round_down(page_zone(page)->zone_start_pfn, pageblock_nr_pages); | ||
6852 | return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; | ||
6853 | #endif /* CONFIG_SPARSEMEM */ | ||
6854 | } | ||
6855 | |||
6856 | /** | ||
6857 | * get_pfnblock_flags_mask - Return the requested group of flags for the pageblock_nr_pages block of pages | ||
6858 | * @page: The page within the block of interest | ||
6859 | * @pfn: The target page frame number | ||
6860 | * @end_bitidx: The last bit of interest to retrieve | ||
6861 | * @mask: mask of bits that the caller is interested in | ||
6862 | * | ||
6863 | * Return: pageblock_bits flags | ||
6864 | */ | ||
6865 | unsigned long get_pfnblock_flags_mask(struct page *page, unsigned long pfn, | ||
6866 | unsigned long end_bitidx, | ||
6867 | unsigned long mask) | ||
6868 | { | ||
6869 | unsigned long *bitmap; | ||
6870 | unsigned long bitidx, word_bitidx; | ||
6871 | unsigned long word; | ||
6872 | |||
6873 | bitmap = get_pageblock_bitmap(page, pfn); | ||
6874 | bitidx = pfn_to_bitidx(page, pfn); | ||
6875 | word_bitidx = bitidx / BITS_PER_LONG; | ||
6876 | bitidx &= (BITS_PER_LONG-1); | ||
6877 | |||
6878 | word = bitmap[word_bitidx]; | ||
6879 | bitidx += end_bitidx; | ||
6880 | return (word >> (BITS_PER_LONG - bitidx - 1)) & mask; | ||
6881 | } | ||
6882 | |||
6883 | /** | ||
6884 | * set_pfnblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages | ||
6885 | * @page: The page within the block of interest | ||
6886 | * @flags: The flags to set | ||
6887 | * @pfn: The target page frame number | ||
6888 | * @end_bitidx: The last bit of interest | ||
6889 | * @mask: mask of bits that the caller is interested in | ||
6890 | */ | ||
6891 | void set_pfnblock_flags_mask(struct page *page, unsigned long flags, | ||
6892 | unsigned long pfn, | ||
6893 | unsigned long end_bitidx, | ||
6894 | unsigned long mask) | ||
6895 | { | ||
6896 | unsigned long *bitmap; | ||
6897 | unsigned long bitidx, word_bitidx; | ||
6898 | unsigned long old_word, word; | ||
6899 | |||
6900 | BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4); | ||
6901 | |||
6902 | bitmap = get_pageblock_bitmap(page, pfn); | ||
6903 | bitidx = pfn_to_bitidx(page, pfn); | ||
6904 | word_bitidx = bitidx / BITS_PER_LONG; | ||
6905 | bitidx &= (BITS_PER_LONG-1); | ||
6906 | |||
6907 | VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page); | ||
6908 | |||
6909 | bitidx += end_bitidx; | ||
6910 | mask <<= (BITS_PER_LONG - bitidx - 1); | ||
6911 | flags <<= (BITS_PER_LONG - bitidx - 1); | ||
6912 | |||
6913 | word = READ_ONCE(bitmap[word_bitidx]); | ||
6914 | for (;;) { | ||
6915 | old_word = cmpxchg(&bitmap[word_bitidx], word, (word & ~mask) | flags); | ||
6916 | if (word == old_word) | ||
6917 | break; | ||
6918 | word = old_word; | ||
6919 | } | ||
6920 | } | ||
6921 | |||
6922 | /* | 6934 | /* |
6923 | * This function checks whether pageblock includes unmovable pages or not. | 6935 | * This function checks whether pageblock includes unmovable pages or not. |
6924 | * If @count is not zero, it is okay to include less @count unmovable pages | 6936 | * If @count is not zero, it is okay to include less @count unmovable pages |