Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm: page_alloc: reduce number of times page_to_pfn is called

In the free path we calculate page_to_pfn multiple times. Reduce that.

Signed-off-by: Mel Gorman <mgorman@suse.de>
Acked-by: Rik van Riel <riel@redhat.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Cc: Jan Kara <jack@suse.cz>
Cc: Michal Hocko <mhocko@suse.cz>
Cc: Hugh Dickins <hughd@google.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Mel Gorman and committed by
Linus Torvalds
dc4b0caf e58469ba

+39 -37
+7 -2
include/linux/mmzone.h
··· 78 78 #define NR_MIGRATETYPE_BITS (PB_migrate_end - PB_migrate + 1) 79 79 #define MIGRATETYPE_MASK ((1UL << NR_MIGRATETYPE_BITS) - 1) 80 80 81 - static inline int get_pageblock_migratetype(struct page *page) 81 + #define get_pageblock_migratetype(page) \ 82 + get_pfnblock_flags_mask(page, page_to_pfn(page), \ 83 + PB_migrate_end, MIGRATETYPE_MASK) 84 + 85 + static inline int get_pfnblock_migratetype(struct page *page, unsigned long pfn) 82 86 { 83 87 BUILD_BUG_ON(PB_migrate_end - PB_migrate != 2); 84 - return get_pageblock_flags_mask(page, PB_migrate_end, MIGRATETYPE_MASK); 88 + return get_pfnblock_flags_mask(page, pfn, PB_migrate_end, 89 + MIGRATETYPE_MASK); 85 90 } 86 91 87 92 struct free_area {
+13 -20
include/linux/pageblock-flags.h
··· 65 65 /* Forward declaration */ 66 66 struct page; 67 67 68 - unsigned long get_pageblock_flags_mask(struct page *page, 68 + unsigned long get_pfnblock_flags_mask(struct page *page, 69 + unsigned long pfn, 69 70 unsigned long end_bitidx, 70 71 unsigned long mask); 71 - void set_pageblock_flags_mask(struct page *page, 72 + 73 + void set_pfnblock_flags_mask(struct page *page, 72 74 unsigned long flags, 75 + unsigned long pfn, 73 76 unsigned long end_bitidx, 74 77 unsigned long mask); 75 78 76 79 /* Declarations for getting and setting flags. See mm/page_alloc.c */ 77 - static inline unsigned long get_pageblock_flags_group(struct page *page, 78 - int start_bitidx, int end_bitidx) 79 - { 80 - unsigned long nr_flag_bits = end_bitidx - start_bitidx + 1; 81 - unsigned long mask = (1 << nr_flag_bits) - 1; 82 - 83 - return get_pageblock_flags_mask(page, end_bitidx, mask); 84 - } 85 - 86 - static inline void set_pageblock_flags_group(struct page *page, 87 - unsigned long flags, 88 - int start_bitidx, int end_bitidx) 89 - { 90 - unsigned long nr_flag_bits = end_bitidx - start_bitidx + 1; 91 - unsigned long mask = (1 << nr_flag_bits) - 1; 92 - 93 - set_pageblock_flags_mask(page, flags, end_bitidx, mask); 94 - } 80 + #define get_pageblock_flags_group(page, start_bitidx, end_bitidx) \ 81 + get_pfnblock_flags_mask(page, page_to_pfn(page), \ 82 + end_bitidx, \ 83 + (1 << (end_bitidx - start_bitidx + 1)) - 1) 84 + #define set_pageblock_flags_group(page, flags, start_bitidx, end_bitidx) \ 85 + set_pfnblock_flags_mask(page, flags, page_to_pfn(page), \ 86 + end_bitidx, \ 87 + (1 << (end_bitidx - start_bitidx + 1)) - 1) 95 88 96 89 #ifdef CONFIG_COMPACTION 97 90 #define get_pageblock_skip(page) \
+19 -15
mm/page_alloc.c
··· 560 560 */ 561 561 562 562 static inline void __free_one_page(struct page *page, 563 + unsigned long pfn, 563 564 struct zone *zone, unsigned int order, 564 565 int migratetype) 565 566 { ··· 577 576 578 577 VM_BUG_ON(migratetype == -1); 579 578 580 - page_idx = page_to_pfn(page) & ((1 << MAX_ORDER) - 1); 579 + page_idx = pfn & ((1 << MAX_ORDER) - 1); 581 580 582 581 VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page); 583 582 VM_BUG_ON_PAGE(bad_range(zone, page), page); ··· 712 711 list_del(&page->lru); 713 712 mt = get_freepage_migratetype(page); 714 713 /* MIGRATE_MOVABLE list may include MIGRATE_RESERVEs */ 715 - __free_one_page(page, zone, 0, mt); 714 + __free_one_page(page, page_to_pfn(page), zone, 0, mt); 716 715 trace_mm_page_pcpu_drain(page, 0, mt); 717 716 if (likely(!is_migrate_isolate_page(page))) { 718 717 __mod_zone_page_state(zone, NR_FREE_PAGES, 1); ··· 724 723 spin_unlock(&zone->lock); 725 724 } 726 725 727 - static void free_one_page(struct zone *zone, struct page *page, int order, 726 + static void free_one_page(struct zone *zone, 727 + struct page *page, unsigned long pfn, 728 + int order, 728 729 int migratetype) 729 730 { 730 731 spin_lock(&zone->lock); 731 732 zone->pages_scanned = 0; 732 733 733 - __free_one_page(page, zone, order, migratetype); 734 + __free_one_page(page, pfn, zone, order, migratetype); 734 735 if (unlikely(!is_migrate_isolate(migratetype))) 735 736 __mod_zone_freepage_state(zone, 1 << order, migratetype); 736 737 spin_unlock(&zone->lock); ··· 769 766 { 770 767 unsigned long flags; 771 768 int migratetype; 769 + unsigned long pfn = page_to_pfn(page); 772 770 773 771 if (!free_pages_prepare(page, order)) 774 772 return; 775 773 776 774 local_irq_save(flags); 777 775 __count_vm_events(PGFREE, 1 << order); 778 - migratetype = get_pageblock_migratetype(page); 776 + migratetype = get_pfnblock_migratetype(page, pfn); 779 777 set_freepage_migratetype(page, migratetype); 780 - free_one_page(page_zone(page), page, order, migratetype); 778 + free_one_page(page_zone(page), page, pfn, order, migratetype); 781 779 local_irq_restore(flags); 782 780 } 783 781 ··· 1384 1380 struct zone *zone = page_zone(page); 1385 1381 struct per_cpu_pages *pcp; 1386 1382 unsigned long flags; 1383 + unsigned long pfn = page_to_pfn(page); 1387 1384 int migratetype; 1388 1385 1389 1386 if (!free_pages_prepare(page, 0)) 1390 1387 return; 1391 1388 1392 - migratetype = get_pageblock_migratetype(page); 1389 + migratetype = get_pfnblock_migratetype(page, pfn); 1393 1390 set_freepage_migratetype(page, migratetype); 1394 1391 local_irq_save(flags); 1395 1392 __count_vm_event(PGFREE); ··· 1404 1399 */ 1405 1400 if (migratetype >= MIGRATE_PCPTYPES) { 1406 1401 if (unlikely(is_migrate_isolate(migratetype))) { 1407 - free_one_page(zone, page, 0, migratetype); 1402 + free_one_page(zone, page, pfn, 0, migratetype); 1408 1403 goto out; 1409 1404 } 1410 1405 migratetype = MIGRATE_MOVABLE; ··· 6033 6028 * @end_bitidx: The last bit of interest 6034 6029 * returns pageblock_bits flags 6035 6030 */ 6036 - unsigned long get_pageblock_flags_mask(struct page *page, 6031 + unsigned long get_pfnblock_flags_mask(struct page *page, unsigned long pfn, 6037 6032 unsigned long end_bitidx, 6038 6033 unsigned long mask) 6039 6034 { 6040 6035 struct zone *zone; 6041 6036 unsigned long *bitmap; 6042 - unsigned long pfn, bitidx, word_bitidx; 6037 + unsigned long bitidx, word_bitidx; 6043 6038 unsigned long word; 6044 6039 6045 6040 zone = page_zone(page); 6046 - pfn = page_to_pfn(page); 6047 6041 bitmap = get_pageblock_bitmap(zone, pfn); 6048 6042 bitidx = pfn_to_bitidx(zone, pfn); 6049 6043 word_bitidx = bitidx / BITS_PER_LONG; ··· 6054 6050 } 6055 6051 6056 6052 /** 6057 - * set_pageblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages 6053 + * set_pfnblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages 6058 6054 * @page: The page within the block of interest 6059 6055 * @start_bitidx: The first bit of interest 6060 6056 * @end_bitidx: The last bit of interest 6061 6057 * @flags: The flags to set 6062 6058 */ 6063 - void set_pageblock_flags_mask(struct page *page, unsigned long flags, 6059 + void set_pfnblock_flags_mask(struct page *page, unsigned long flags, 6060 + unsigned long pfn, 6064 6061 unsigned long end_bitidx, 6065 6062 unsigned long mask) 6066 6063 { 6067 6064 struct zone *zone; 6068 6065 unsigned long *bitmap; 6069 - unsigned long pfn, bitidx, word_bitidx; 6066 + unsigned long bitidx, word_bitidx; 6070 6067 unsigned long old_word, word; 6071 6068 6072 6069 BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4); 6073 6070 6074 6071 zone = page_zone(page); 6075 - pfn = page_to_pfn(page); 6076 6072 bitmap = get_pageblock_bitmap(zone, pfn); 6077 6073 bitidx = pfn_to_bitidx(zone, pfn); 6078 6074 word_bitidx = bitidx / BITS_PER_LONG;