aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <nickpiggin@yahoo.com.au>2006-01-06 03:11:20 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:29 -0500
commita74609fafa2e5cc31d558012abaaa55ec9ad9da4 (patch)
tree0be653692864d99da345b575dfe2083994ee1d21
parentd3cb487149bd706aa6aeb02042332a450978dc1c (diff)
[PATCH] mm: page_state opt
Optimise page_state manipulations by introducing interrupt unsafe accessors to page_state fields. Callers must provide their own locking (either disable interrupts or not update from interrupt context). Switch over the hot callsites that can easily be moved under interrupts off sections. Signed-off-by: Nick Piggin <npiggin@suse.de> Cc: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--include/linux/page-flags.h43
-rw-r--r--mm/page_alloc.c89
-rw-r--r--mm/rmap.c10
-rw-r--r--mm/vmscan.c27
4 files changed, 104 insertions, 65 deletions
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 32d09c8d952b..dede8d412dca 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -144,22 +144,33 @@ struct page_state {
144extern void get_page_state(struct page_state *ret); 144extern void get_page_state(struct page_state *ret);
145extern void get_page_state_node(struct page_state *ret, int node); 145extern void get_page_state_node(struct page_state *ret, int node);
146extern void get_full_page_state(struct page_state *ret); 146extern void get_full_page_state(struct page_state *ret);
147extern unsigned long __read_page_state(unsigned long offset); 147extern unsigned long read_page_state_offset(unsigned long offset);
148extern void __mod_page_state(unsigned long offset, unsigned long delta); 148extern void mod_page_state_offset(unsigned long offset, unsigned long delta);
149extern void __mod_page_state_offset(unsigned long offset, unsigned long delta);
149 150
150#define read_page_state(member) \ 151#define read_page_state(member) \
151 __read_page_state(offsetof(struct page_state, member)) 152 read_page_state_offset(offsetof(struct page_state, member))
152 153
153#define mod_page_state(member, delta) \ 154#define mod_page_state(member, delta) \
154 __mod_page_state(offsetof(struct page_state, member), (delta)) 155 mod_page_state_offset(offsetof(struct page_state, member), (delta))
155 156
156#define inc_page_state(member) mod_page_state(member, 1UL) 157#define __mod_page_state(member, delta) \
157#define dec_page_state(member) mod_page_state(member, 0UL - 1) 158 __mod_page_state_offset(offsetof(struct page_state, member), (delta))
158#define add_page_state(member,delta) mod_page_state(member, (delta))
159#define sub_page_state(member,delta) mod_page_state(member, 0UL - (delta))
160 159
161#define mod_page_state_zone(zone, member, delta) \ 160#define inc_page_state(member) mod_page_state(member, 1UL)
162 do { \ 161#define dec_page_state(member) mod_page_state(member, 0UL - 1)
162#define add_page_state(member,delta) mod_page_state(member, (delta))
163#define sub_page_state(member,delta) mod_page_state(member, 0UL - (delta))
164
165#define __inc_page_state(member) __mod_page_state(member, 1UL)
166#define __dec_page_state(member) __mod_page_state(member, 0UL - 1)
167#define __add_page_state(member,delta) __mod_page_state(member, (delta))
168#define __sub_page_state(member,delta) __mod_page_state(member, 0UL - (delta))
169
170#define page_state(member) (*__page_state(offsetof(struct page_state, member)))
171
172#define state_zone_offset(zone, member) \
173({ \
163 unsigned offset; \ 174 unsigned offset; \
164 if (is_highmem(zone)) \ 175 if (is_highmem(zone)) \
165 offset = offsetof(struct page_state, member##_high); \ 176 offset = offsetof(struct page_state, member##_high); \
@@ -169,7 +180,17 @@ extern void __mod_page_state(unsigned long offset, unsigned long delta);
169 offset = offsetof(struct page_state, member##_dma32); \ 180 offset = offsetof(struct page_state, member##_dma32); \
170 else \ 181 else \
171 offset = offsetof(struct page_state, member##_dma); \ 182 offset = offsetof(struct page_state, member##_dma); \
172 __mod_page_state(offset, (delta)); \ 183 offset; \
184})
185
186#define __mod_page_state_zone(zone, member, delta) \
187 do { \
188 __mod_page_state_offset(state_zone_offset(zone, member), (delta)); \
189 } while (0)
190
191#define mod_page_state_zone(zone, member, delta) \
192 do { \
193 mod_page_state_offset(state_zone_offset(zone, member), (delta)); \
173 } while (0) 194 } while (0)
174 195
175/* 196/*
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7f580779abdb..fd47494cb989 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -424,9 +424,9 @@ void __free_pages_ok(struct page *page, unsigned int order)
424 return; 424 return;
425 425
426 list_add(&page->lru, &list); 426 list_add(&page->lru, &list);
427 mod_page_state(pgfree, 1 << order);
428 kernel_map_pages(page, 1<<order, 0); 427 kernel_map_pages(page, 1<<order, 0);
429 local_irq_save(flags); 428 local_irq_save(flags);
429 __mod_page_state(pgfree, 1 << order);
430 free_pages_bulk(page_zone(page), 1, &list, order); 430 free_pages_bulk(page_zone(page), 1, &list, order);
431 local_irq_restore(flags); 431 local_irq_restore(flags);
432} 432}
@@ -674,18 +674,14 @@ void drain_local_pages(void)
674} 674}
675#endif /* CONFIG_PM */ 675#endif /* CONFIG_PM */
676 676
677static void zone_statistics(struct zonelist *zonelist, struct zone *z) 677static void zone_statistics(struct zonelist *zonelist, struct zone *z, int cpu)
678{ 678{
679#ifdef CONFIG_NUMA 679#ifdef CONFIG_NUMA
680 unsigned long flags;
681 int cpu;
682 pg_data_t *pg = z->zone_pgdat; 680 pg_data_t *pg = z->zone_pgdat;
683 pg_data_t *orig = zonelist->zones[0]->zone_pgdat; 681 pg_data_t *orig = zonelist->zones[0]->zone_pgdat;
684 struct per_cpu_pageset *p; 682 struct per_cpu_pageset *p;
685 683
686 local_irq_save(flags); 684 p = zone_pcp(z, cpu);
687 cpu = smp_processor_id();
688 p = zone_pcp(z,cpu);
689 if (pg == orig) { 685 if (pg == orig) {
690 p->numa_hit++; 686 p->numa_hit++;
691 } else { 687 } else {
@@ -696,7 +692,6 @@ static void zone_statistics(struct zonelist *zonelist, struct zone *z)
696 p->local_node++; 692 p->local_node++;
697 else 693 else
698 p->other_node++; 694 p->other_node++;
699 local_irq_restore(flags);
700#endif 695#endif
701} 696}
702 697
@@ -716,11 +711,11 @@ static void fastcall free_hot_cold_page(struct page *page, int cold)
716 if (free_pages_check(page)) 711 if (free_pages_check(page))
717 return; 712 return;
718 713
719 inc_page_state(pgfree);
720 kernel_map_pages(page, 1, 0); 714 kernel_map_pages(page, 1, 0);
721 715
722 pcp = &zone_pcp(zone, get_cpu())->pcp[cold]; 716 pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
723 local_irq_save(flags); 717 local_irq_save(flags);
718 __inc_page_state(pgfree);
724 list_add(&page->lru, &pcp->list); 719 list_add(&page->lru, &pcp->list);
725 pcp->count++; 720 pcp->count++;
726 if (pcp->count >= pcp->high) 721 if (pcp->count >= pcp->high)
@@ -753,49 +748,58 @@ static inline void prep_zero_page(struct page *page, int order, gfp_t gfp_flags)
753 * we cheat by calling it from here, in the order > 0 path. Saves a branch 748 * we cheat by calling it from here, in the order > 0 path. Saves a branch
754 * or two. 749 * or two.
755 */ 750 */
756static struct page * 751static struct page *buffered_rmqueue(struct zonelist *zonelist,
757buffered_rmqueue(struct zone *zone, int order, gfp_t gfp_flags) 752 struct zone *zone, int order, gfp_t gfp_flags)
758{ 753{
759 unsigned long flags; 754 unsigned long flags;
760 struct page *page; 755 struct page *page;
761 int cold = !!(gfp_flags & __GFP_COLD); 756 int cold = !!(gfp_flags & __GFP_COLD);
757 int cpu;
762 758
763again: 759again:
760 cpu = get_cpu();
764 if (order == 0) { 761 if (order == 0) {
765 struct per_cpu_pages *pcp; 762 struct per_cpu_pages *pcp;
766 763
767 page = NULL; 764 pcp = &zone_pcp(zone, cpu)->pcp[cold];
768 pcp = &zone_pcp(zone, get_cpu())->pcp[cold];
769 local_irq_save(flags); 765 local_irq_save(flags);
770 if (!pcp->count) 766 if (!pcp->count) {
771 pcp->count += rmqueue_bulk(zone, 0, 767 pcp->count += rmqueue_bulk(zone, 0,
772 pcp->batch, &pcp->list); 768 pcp->batch, &pcp->list);
773 if (likely(pcp->count)) { 769 if (unlikely(!pcp->count))
774 page = list_entry(pcp->list.next, struct page, lru); 770 goto failed;
775 list_del(&page->lru);
776 pcp->count--;
777 } 771 }
778 local_irq_restore(flags); 772 page = list_entry(pcp->list.next, struct page, lru);
779 put_cpu(); 773 list_del(&page->lru);
774 pcp->count--;
780 } else { 775 } else {
781 spin_lock_irqsave(&zone->lock, flags); 776 spin_lock_irqsave(&zone->lock, flags);
782 page = __rmqueue(zone, order); 777 page = __rmqueue(zone, order);
783 spin_unlock_irqrestore(&zone->lock, flags); 778 spin_unlock(&zone->lock);
779 if (!page)
780 goto failed;
784 } 781 }
785 782
786 if (page != NULL) { 783 __mod_page_state_zone(zone, pgalloc, 1 << order);
787 BUG_ON(bad_range(zone, page)); 784 zone_statistics(zonelist, zone, cpu);
788 mod_page_state_zone(zone, pgalloc, 1 << order); 785 local_irq_restore(flags);
789 if (prep_new_page(page, order)) 786 put_cpu();
790 goto again;
791 787
792 if (gfp_flags & __GFP_ZERO) 788 BUG_ON(bad_range(zone, page));
793 prep_zero_page(page, order, gfp_flags); 789 if (prep_new_page(page, order))
790 goto again;
794 791
795 if (order && (gfp_flags & __GFP_COMP)) 792 if (gfp_flags & __GFP_ZERO)
796 prep_compound_page(page, order); 793 prep_zero_page(page, order, gfp_flags);
797 } 794
795 if (order && (gfp_flags & __GFP_COMP))
796 prep_compound_page(page, order);
798 return page; 797 return page;
798
799failed:
800 local_irq_restore(flags);
801 put_cpu();
802 return NULL;
799} 803}
800 804
801#define ALLOC_NO_WATERMARKS 0x01 /* don't check watermarks at all */ 805#define ALLOC_NO_WATERMARKS 0x01 /* don't check watermarks at all */
@@ -871,9 +875,8 @@ get_page_from_freelist(gfp_t gfp_mask, unsigned int order,
871 continue; 875 continue;
872 } 876 }
873 877
874 page = buffered_rmqueue(*z, order, gfp_mask); 878 page = buffered_rmqueue(zonelist, *z, order, gfp_mask);
875 if (page) { 879 if (page) {
876 zone_statistics(zonelist, *z);
877 break; 880 break;
878 } 881 }
879 } while (*(++z) != NULL); 882 } while (*(++z) != NULL);
@@ -1248,7 +1251,7 @@ void get_full_page_state(struct page_state *ret)
1248 __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long), &mask); 1251 __get_page_state(ret, sizeof(*ret) / sizeof(unsigned long), &mask);
1249} 1252}
1250 1253
1251unsigned long __read_page_state(unsigned long offset) 1254unsigned long read_page_state_offset(unsigned long offset)
1252{ 1255{
1253 unsigned long ret = 0; 1256 unsigned long ret = 0;
1254 int cpu; 1257 int cpu;
@@ -1262,18 +1265,26 @@ unsigned long __read_page_state(unsigned long offset)
1262 return ret; 1265 return ret;
1263} 1266}
1264 1267
1265void __mod_page_state(unsigned long offset, unsigned long delta) 1268void __mod_page_state_offset(unsigned long offset, unsigned long delta)
1269{
1270 void *ptr;
1271
1272 ptr = &__get_cpu_var(page_states);
1273 *(unsigned long *)(ptr + offset) += delta;
1274}
1275EXPORT_SYMBOL(__mod_page_state_offset);
1276
1277void mod_page_state_offset(unsigned long offset, unsigned long delta)
1266{ 1278{
1267 unsigned long flags; 1279 unsigned long flags;
1268 void* ptr; 1280 void *ptr;
1269 1281
1270 local_irq_save(flags); 1282 local_irq_save(flags);
1271 ptr = &__get_cpu_var(page_states); 1283 ptr = &__get_cpu_var(page_states);
1272 *(unsigned long*)(ptr + offset) += delta; 1284 *(unsigned long *)(ptr + offset) += delta;
1273 local_irq_restore(flags); 1285 local_irq_restore(flags);
1274} 1286}
1275 1287EXPORT_SYMBOL(mod_page_state_offset);
1276EXPORT_SYMBOL(__mod_page_state);
1277 1288
1278void __get_zone_counts(unsigned long *active, unsigned long *inactive, 1289void __get_zone_counts(unsigned long *active, unsigned long *inactive,
1279 unsigned long *free, struct pglist_data *pgdat) 1290 unsigned long *free, struct pglist_data *pgdat)
diff --git a/mm/rmap.c b/mm/rmap.c
index 4107f64ff749..6f3f7db27128 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -451,7 +451,11 @@ static void __page_set_anon_rmap(struct page *page,
451 451
452 page->index = linear_page_index(vma, address); 452 page->index = linear_page_index(vma, address);
453 453
454 inc_page_state(nr_mapped); 454 /*
455 * nr_mapped state can be updated without turning off
456 * interrupts because it is not modified via interrupt.
457 */
458 __inc_page_state(nr_mapped);
455} 459}
456 460
457/** 461/**
@@ -498,7 +502,7 @@ void page_add_file_rmap(struct page *page)
498 BUG_ON(!pfn_valid(page_to_pfn(page))); 502 BUG_ON(!pfn_valid(page_to_pfn(page)));
499 503
500 if (atomic_inc_and_test(&page->_mapcount)) 504 if (atomic_inc_and_test(&page->_mapcount))
501 inc_page_state(nr_mapped); 505 __inc_page_state(nr_mapped);
502} 506}
503 507
504/** 508/**
@@ -522,7 +526,7 @@ void page_remove_rmap(struct page *page)
522 */ 526 */
523 if (page_test_and_clear_dirty(page)) 527 if (page_test_and_clear_dirty(page))
524 set_page_dirty(page); 528 set_page_dirty(page);
525 dec_page_state(nr_mapped); 529 __dec_page_state(nr_mapped);
526 } 530 }
527} 531}
528 532
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 7681d8ee04fe..be8235fb1939 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -645,16 +645,17 @@ static void shrink_cache(struct zone *zone, struct scan_control *sc)
645 goto done; 645 goto done;
646 646
647 max_scan -= nr_scan; 647 max_scan -= nr_scan;
648 if (current_is_kswapd())
649 mod_page_state_zone(zone, pgscan_kswapd, nr_scan);
650 else
651 mod_page_state_zone(zone, pgscan_direct, nr_scan);
652 nr_freed = shrink_list(&page_list, sc); 648 nr_freed = shrink_list(&page_list, sc);
653 if (current_is_kswapd())
654 mod_page_state(kswapd_steal, nr_freed);
655 mod_page_state_zone(zone, pgsteal, nr_freed);
656 649
657 spin_lock_irq(&zone->lru_lock); 650 local_irq_disable();
651 if (current_is_kswapd()) {
652 __mod_page_state_zone(zone, pgscan_kswapd, nr_scan);
653 __mod_page_state(kswapd_steal, nr_freed);
654 } else
655 __mod_page_state_zone(zone, pgscan_direct, nr_scan);
656 __mod_page_state_zone(zone, pgsteal, nr_freed);
657
658 spin_lock(&zone->lru_lock);
658 /* 659 /*
659 * Put back any unfreeable pages. 660 * Put back any unfreeable pages.
660 */ 661 */
@@ -816,11 +817,13 @@ refill_inactive_zone(struct zone *zone, struct scan_control *sc)
816 } 817 }
817 } 818 }
818 zone->nr_active += pgmoved; 819 zone->nr_active += pgmoved;
819 spin_unlock_irq(&zone->lru_lock); 820 spin_unlock(&zone->lru_lock);
820 pagevec_release(&pvec); 821
822 __mod_page_state_zone(zone, pgrefill, pgscanned);
823 __mod_page_state(pgdeactivate, pgdeactivate);
824 local_irq_enable();
821 825
822 mod_page_state_zone(zone, pgrefill, pgscanned); 826 pagevec_release(&pvec);
823 mod_page_state(pgdeactivate, pgdeactivate);
824} 827}
825 828
826/* 829/*