VM pageout scalability improvements
Subsystems (24)
cover VM pageout scalability improvements
On large memory systems, the VM can spend way too much time scanning through pages that it cannot (or should not) evict from memory. Not only does it use up CPU time, but it also provokes lock contention and can leave large systems under memory presure in a catatonic state.
This patch series improves VM scalability by:
1) making the locking a little more scalable
2) putting filesystem backed, swap backed and non-reclaimable pages onto their own LRUs, so the system only scans the pages that it can/should evict from memory
3) switching to SEQ replacement for the anonymous LRUs, so the number of pages that need to be scanned when the system starts swapping is bound to a reasonable number
The noreclaim patches come verbatim from Lee Schermerhorn and Nick Piggin. I have not taken a detailed look at them yet and all I have done is fix the rejects against the latest -mm kernel.
I am posting this series now because I would like to get more feedback, while I am studying and improving the noreclaim patches myself.
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/20 convert anon_vma list lock a read/write lock
Make the anon_vma list lock a read/write lock. Heaviest use of this lock is in the page_referenced()/try_to_unmap() calls from vmscan [shrink_page_list()]. These functions can use a read lock to allow some parallelism for different cpus trying to reclaim pages mapped via the same set of vmas.
This change should not change the footprint of the anon_vma in the non-debug case.
include/linux/rmap.h +6 -3
@@ -25,7 +25,7 @@* pointing to this anon_vma once its vma list is empty. */ struct anon_vma { -spinlock_t lock;/* Serialize access to vma list */ +rwlock_t rwlock;/* Serialize access to vma list */ struct list_head head;/* List of private "related" vmas */ };
@@ -43,18 +43,21 @@ static inline void anon_vma_free(structkmem_cache_free (anon_vma_cachep, anon_vma); } +/* +* This needs to be a write lock for __vma_link() +*/ static inline void anon_vma_lock (struct vm_area_struct *vma) {struct anon_vma *anon_vma = vma->anon_vma;if (anon_vma) -spin_lock (&anon_vma->lock); +write_lock (&anon_vma->rwlock); }static inline void anon_vma_unlock (struct vm_area_struct *vma) {struct anon_vma *anon_vma = vma->anon_vma;if (anon_vma) -spin_unlock (&anon_vma->lock); +write_unlock (&anon_vma->rwlock); }/*
mm/rmap.c +10 -10
@@ -25,7 +25,7 @@* mm->mmap_sem * page->flags PG_locked (lock_page) * mapping->i_mmap_lock -* anon_vma->lock +* anon_vma->rwlock * mm->page_table_lock or pte_lock * zone->lru_lock (in mark_page_accessed, isolate_lru_page) * swap_lock (in swap_duplicate, swap_info_get)
@@ -68,7 +68,7 @@ int anon_vma_prepare(struct vm_area_struif (anon_vma) { allocated =NULL ; locked = anon_vma; -spin_lock (&locked->lock); +write_lock (&locked->rwlock); }else { anon_vma =anon_vma_alloc ();if (unlikely (!anon_vma))
@@ -87,7 +87,7 @@ int anon_vma_prepare(struct vm_area_struspin_unlock (&mm->page_table_lock);if (locked) -spin_unlock (&locked->lock); +write_unlock (&locked->rwlock);if (unlikely (allocated))anon_vma_free (allocated); }
@@ -113,9 +113,9 @@ void anon_vma_link(struct vm_area_structstruct anon_vma *anon_vma = vma->anon_vma;if (anon_vma) { -spin_lock (&anon_vma->lock); +write_lock (&anon_vma->rwlock);list_add_tail (&vma->anon_vma_node, &anon_vma->head); -spin_unlock (&anon_vma->lock); +write_unlock (&anon_vma->rwlock); } }
@@ -127,12 +127,12 @@ void anon_vma_unlink(struct vm_area_struif (!anon_vma)return ; -spin_lock (&anon_vma->lock); +write_lock (&anon_vma->rwlock);list_del (&vma->anon_vma_node);/* We must garbage collect the anon_vma if it's empty */ empty =list_empty (&anon_vma->head); -spin_unlock (&anon_vma->lock); +write_unlock (&anon_vma->rwlock);if (empty)anon_vma_free (anon_vma);
@@ -142,7 +142,7 @@ static void anon_vma_ctor(struct kmem_ca {struct anon_vma *anon_vma = data; -spin_lock_init (&anon_vma->lock); +rwlock_init (&anon_vma->rwlock);INIT_LIST_HEAD (&anon_vma->head); }
@@ -169,7 +169,7 @@ static struct anon_vma *page_lock_anon_v goto out; anon_vma = (struct anon_vma *) (anon_mapping -PAGE_MAPPING_ANON ); -spin_lock (&anon_vma->lock); +read_lock (&anon_vma->rwlock);return anon_vma; out:rcu_read_unlock ();
@@ -178,7 +178,7 @@ out:static void page_unlock_anon_vma (struct anon_vma *anon_vma) { -spin_unlock (&anon_vma->lock); +read_unlock (&anon_vma->rwlock);rcu_read_unlock (); }
mm/mmap.c +2 -2
@@ -564,7 +564,7 @@ again: remove_next = 1 + (end > next->if (vma->anon_vma) anon_vma = vma->anon_vma;if (anon_vma) { -spin_lock (&anon_vma->lock); +write_lock (&anon_vma->rwlock);/* * Easily overlooked: when mprotect shifts the boundary, * make sure the expanding vma has anon_vma set if the
@@ -618,7 +618,7 @@ again: remove_next = 1 + (end > next-> }if (anon_vma) -spin_unlock (&anon_vma->lock); +write_unlock (&anon_vma->rwlock);if (mapping)spin_unlock (&mapping->i_mmap_lock);
mm/migrate.c +2 -2
@@ -229,12 +229,12 @@ static void remove_anon_migration_ptes(s* We hold the mmap_sem lock. So no need to call page_lock_anon_vma. */ anon_vma = (struct anon_vma *) (mapping -PAGE_MAPPING_ANON ); -spin_lock (&anon_vma->lock); +read_lock (&anon_vma->rwlock);list_for_each_entry (vma, &anon_vma->head, anon_vma_node)remove_migration_pte (vma, old, new); -spin_unlock (&anon_vma->lock); +read_unlock (&anon_vma->rwlock); }/*
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 01/20] convert anon_vma list lock a read/write lock
Note that this is a nice improvement also to page migration.
Another solution may be to use a single linked list and RCU.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/20 make the inode i_mmap_lock a reader/writer lock
In reply to Rik van RielI have seen soft cpu lockups in page_referenced_file() due to contention on i_mmap_lock() for different pages. Making the i_mmap_lock a reader/writer lock should increase parallelism in vmscan for file back pages mapped into many address spaces.
Read lock the i_mmap_lock for all usage except:
1) mmap/munmap: linking vma into i_mmap prio_tree or removing
2) unmap_mapping_range: protecting vm_truncate_count
rmap: try_to_unmap_file() required new cond_resched_rwlock(). To reduce code duplication, I recast cond_resched_lock() as a [static inline] wrapper around reworked cond_sched_lock() => __cond_resched_lock(void *lock, int type).
New cond_resched_rwlock() implemented as another wrapper.
include/linux/fs.h +1 -1
@@ -501,7 +501,7 @@ struct address_space {unsigned int i_mmap_writable;/* count VM_SHARED mappings */ struct prio_tree_root i_mmap;/* tree of private and shared mappings */ struct list_head i_mmap_nonlinear;/*list VM_NONLINEAR mappings */ -spinlock_t i_mmap_lock;/* protect tree, count, list */ +rwlock_t i_mmap_lock;/* protect tree, count, list */ unsigned int truncate_count;/* Cover race condition with truncate */ unsigned long nrpages;/* number of total pages */ pgoff_t writeback_index;/* writeback starts here */
include/linux/mm.h +1 -1
@@ -707,7 +707,7 @@ struct zap_details {struct address_space *check_mapping;/* Check page->mapping if set */ pgoff_t first_index;/* Lowest page->index to unmap */ pgoff_t last_index;/* Highest page->index to unmap */ -spinlock_t *i_mmap_lock;/* For unmap_mapping_range: */ +rwlock_t *i_mmap_lock;/* For unmap_mapping_range: */ unsigned long truncate_count;/* Compare vm_truncate_count */ };
fs/inode.c +1 -1
@@ -210,7 +210,7 @@ void inode_init_once(struct inode *inodeINIT_LIST_HEAD (&inode->i_devices);INIT_RADIX_TREE (&inode->i_data.page_tree,GFP_ATOMIC );rwlock_init (&inode->i_data.tree_lock); -spin_lock_init (&inode->i_data.i_mmap_lock); +rwlock_init (&inode->i_data.i_mmap_lock);INIT_LIST_HEAD (&inode->i_data.private_list);spin_lock_init (&inode->i_data.private_lock);INIT_RAW_PRIO_TREE_ROOT (&inode->i_data.i_mmap);
fs/hugetlbfs/inode.c +5 -2
@@ -420,6 +420,9 @@ static void hugetlbfs_drop_inode(structhugetlbfs_forget_inode (inode); } +/* +* LOCKING: __unmap_hugepage_range() requires write lock on i_mmap_lock +*/ static inline void hugetlb_vmtruncate_list (struct prio_tree_root *root,pgoff_t pgoff) {
@@ -454,10 +457,10 @@ static int hugetlb_vmtruncate(struct ino pgoff = offset >>PAGE_SHIFT ;i_size_write (inode, offset); -spin_lock (&mapping->i_mmap_lock); +write_lock (&mapping->i_mmap_lock);if (!prio_tree_empty (&mapping->i_mmap))hugetlb_vmtruncate_list (&mapping->i_mmap, pgoff); -spin_unlock (&mapping->i_mmap_lock); +write_unlock (&mapping->i_mmap_lock);truncate_hugepages (inode, offset);return 0 ; }
kernel/fork.c +2 -2
@@ -272,12 +272,12 @@ static int dup_mmap(struct mm_struct *mmatomic_dec (&inode->i_writecount);/* insert tmp into the share list, just after mpnt */ -spin_lock (&file->f_mapping->i_mmap_lock); +write_lock (&file->f_mapping->i_mmap_lock); tmp->vm_truncate_count = mpnt->vm_truncate_count;flush_dcache_mmap_lock (file->f_mapping);vma_prio_tree_add (tmp, mpnt);flush_dcache_mmap_unlock (file->f_mapping); -spin_unlock (&file->f_mapping->i_mmap_lock); +write_unlock (&file->f_mapping->i_mmap_lock); }/*
mm/filemap_xip.c +2 -2
@@ -182,7 +182,7 @@ __xip_unmap (struct address_space * mappif (!page)return ; -spin_lock (&mapping->i_mmap_lock); +read_lock (&mapping->i_mmap_lock); vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { mm = vma->vm_mm; address = vma->vm_start +
@@ -200,7 +200,7 @@ __xip_unmap (struct address_space * mapppage_cache_release (page); } } -spin_unlock (&mapping->i_mmap_lock); +read_unlock (&mapping->i_mmap_lock); }/*
mm/fremap.c +2 -2
@@ -202,13 +202,13 @@ asmlinkage long sys_remap_file_pages(uns } goto out; } -spin_lock (&mapping->i_mmap_lock); +write_lock (&mapping->i_mmap_lock);flush_dcache_mmap_lock (mapping); vma->vm_flags |=VM_NONLINEAR ;vma_prio_tree_remove (vma, &mapping->i_mmap);vma_nonlinear_insert (vma, &mapping->i_mmap_nonlinear);flush_dcache_mmap_unlock (mapping); -spin_unlock (&mapping->i_mmap_lock); +write_unlock (&mapping->i_mmap_lock); } err =populate_range (mm, vma, start, size, pgoff);
mm/hugetlb.c +4 -4
@@ -721,9 +721,9 @@ void unmap_hugepage_range(struct vm_area* do nothing in this case. */ if (vma->vm_file) { -spin_lock (&vma->vm_file->f_mapping->i_mmap_lock); +write_lock (&vma->vm_file->f_mapping->i_mmap_lock);__unmap_hugepage_range (vma, start, end); -spin_unlock (&vma->vm_file->f_mapping->i_mmap_lock); +write_unlock (&vma->vm_file->f_mapping->i_mmap_lock); } }
@@ -964,7 +964,7 @@ void hugetlb_change_protection(struct vmBUG_ON (address >= end);flush_cache_range (vma, address, end); -spin_lock (&vma->vm_file->f_mapping->i_mmap_lock); +read_lock (&vma->vm_file->f_mapping->i_mmap_lock);spin_lock (&mm->page_table_lock);for (; address < end; address +=HPAGE_SIZE ) { ptep =huge_pte_offset (mm, address);
@@ -979,7 +979,7 @@ void hugetlb_change_protection(struct vm } }spin_unlock (&mm->page_table_lock); -spin_unlock (&vma->vm_file->f_mapping->i_mmap_lock); +read_unlock (&vma->vm_file->f_mapping->i_mmap_lock);flush_tlb_range (vma, start, end); }
mm/memory.c +7 -6
@@ -811,7 +811,7 @@ unsigned long unmap_vmas(struct mmu_gathunsigned long tlb_start =0 ;/* For tlb_finish_mmu */ int tlb_start_valid =0 ;unsigned long start = start_addr; -spinlock_t *i_mmap_lock = details? details->i_mmap_lock:NULL ; +rwlock_t *i_mmap_lock = details? details->i_mmap_lock:NULL ;int fullmm = (*tlbp)->fullmm;for ( ; vma && vma->vm_start < end_addr; vma = vma->vm_next) {
@@ -1727,7 +1727,7 @@ unwritable_page:* can't efficiently keep all vmas in step with mapping->truncate_count: * so instead reset them all whenever it wraps back to 0 (then go to 1). * mapping->truncate_count and vma->vm_truncate_count are protected by -* i_mmap_lock. +* write locked i_mmap_lock. * * In order to make forward progress despite repeatedly restarting some * large vma, note the restart_addr from unmap_vmas when it breaks out:
@@ -1792,9 +1792,10 @@ again: goto again; } -spin_unlock (details->i_mmap_lock); +//TODO: why not cond_resched_lock() here [rwlock version]? +write_unlock (details->i_mmap_lock);cond_resched (); -spin_lock (details->i_mmap_lock); +write_lock (details->i_mmap_lock);return -EINTR ; }
@@ -1890,7 +1891,7 @@ void unmap_mapping_range(struct address_ details.last_index =ULONG_MAX ; details.i_mmap_lock = &mapping->i_mmap_lock; -spin_lock (&mapping->i_mmap_lock); +write_lock (&mapping->i_mmap_lock);/* Protect against endless unmapping loops */ mapping->truncate_count++;
@@ -1905,7 +1906,7 @@ void unmap_mapping_range(struct address_unmap_mapping_range_tree (&mapping->i_mmap, &details);if (unlikely (!list_empty (&mapping->i_mmap_nonlinear)))unmap_mapping_range_list (&mapping->i_mmap_nonlinear, &details); -spin_unlock (&mapping->i_mmap_lock); +write_unlock (&mapping->i_mmap_lock); }EXPORT_SYMBOL (unmap_mapping_range);
mm/migrate.c +2 -2
@@ -202,12 +202,12 @@ static void remove_file_migration_ptes(sif (!mapping)return ; -spin_lock (&mapping->i_mmap_lock); +read_lock (&mapping->i_mmap_lock); vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff)remove_migration_pte (vma, old, new); -spin_unlock (&mapping->i_mmap_lock); +read_unlock (&mapping->i_mmap_lock); }/*
mm/mmap.c +8 -8
@@ -186,7 +186,7 @@ error: }/* -* Requires inode->i_mapping->i_mmap_lock +* Requires write locked inode->i_mapping->i_mmap_lock */ static void __remove_shared_vm_struct (struct vm_area_struct *vma,struct file *file,struct address_space *mapping)
@@ -214,9 +214,9 @@ void unlink_file_vma(struct vm_area_struif (file) {struct address_space *mapping = file->f_mapping; -spin_lock (&mapping->i_mmap_lock); +write_lock (&mapping->i_mmap_lock);__remove_shared_vm_struct (vma, file, mapping); -spin_unlock (&mapping->i_mmap_lock); +write_unlock (&mapping->i_mmap_lock); } }
@@ -439,7 +439,7 @@ static void vma_link(struct mm_struct *m mapping = vma->vm_file->f_mapping;if (mapping) { -spin_lock (&mapping->i_mmap_lock); +write_lock (&mapping->i_mmap_lock); vma->vm_truncate_count = mapping->truncate_count; }anon_vma_lock (vma);
@@ -449,7 +449,7 @@ static void vma_link(struct mm_struct *manon_vma_unlock (vma);if (mapping) -spin_unlock (&mapping->i_mmap_lock); +write_unlock (&mapping->i_mmap_lock); mm->map_count++;validate_mm (mm);
@@ -536,7 +536,7 @@ again: remove_next = 1 + (end > next-> mapping = file->f_mapping;if (!(vma->vm_flags &VM_NONLINEAR )) root = &mapping->i_mmap; -spin_lock (&mapping->i_mmap_lock); +write_lock (&mapping->i_mmap_lock);if (importer && vma->vm_truncate_count != next->vm_truncate_count) {/*
@@ -620,7 +620,7 @@ again: remove_next = 1 + (end > next->if (anon_vma)write_unlock (&anon_vma->rwlock);if (mapping) -spin_unlock (&mapping->i_mmap_lock); +write_unlock (&mapping->i_mmap_lock);if (remove_next) {if (file)
@@ -2061,7 +2061,7 @@ void exit_mmap(struct mm_struct *mm)/* Insert vm structure into process list sorted by address * and into the inode's i_mmap tree. If vm_file is non-NULL -* then i_mmap_lock is taken here. +* then i_mmap_lock is write locked here. */ int insert_vm_struct (struct mm_struct * mm,struct vm_area_struct * vma) {
mm/mremap.c +2 -2
@@ -83,7 +83,7 @@ static void move_ptes(struct vm_area_str* and we propagate stale pages into the dst afterward. */ mapping = vma->vm_file->f_mapping; -spin_lock (&mapping->i_mmap_lock); +read_lock (&mapping->i_mmap_lock);if (new_vma->vm_truncate_count && new_vma->vm_truncate_count != vma->vm_truncate_count) new_vma->vm_truncate_count =0 ;
@@ -115,7 +115,7 @@ static void move_ptes(struct vm_area_strpte_unmap_nested (new_pte -1 );pte_unmap_unlock (old_pte -1 , old_ptl);if (mapping) -spin_unlock (&mapping->i_mmap_lock); +read_unlock (&mapping->i_mmap_lock); }#define LATENCY_LIMIT (64 * PAGE_SIZE)
mm/rmap.c +8 -8
@@ -368,7 +368,7 @@ static int page_referenced_file(struct p*/ BUG_ON (!PageLocked (page)); -spin_lock (&mapping->i_mmap_lock); +read_lock (&mapping->i_mmap_lock);/* * i_mmap_lock does not stabilize mapcount at all, but mapcount
@@ -394,7 +394,7 @@ static int page_referenced_file(struct pbreak ; } -spin_unlock (&mapping->i_mmap_lock); +read_unlock (&mapping->i_mmap_lock);return referenced; }
@@ -474,12 +474,12 @@ static int page_mkclean_file(struct addrBUG_ON (PageAnon (page)); -spin_lock (&mapping->i_mmap_lock); +read_lock (&mapping->i_mmap_lock); vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {if (vma->vm_flags &VM_SHARED ) ret +=page_mkclean_one (page, vma); } -spin_unlock (&mapping->i_mmap_lock); +read_unlock (&mapping->i_mmap_lock);return ret; }
@@ -909,7 +909,7 @@ static int try_to_unmap_file(struct pageunsigned long max_nl_size =0 ;unsigned int mapcount; -spin_lock (&mapping->i_mmap_lock); +read_lock (&mapping->i_mmap_lock); vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) { ret =try_to_unmap_one (page, vma, migration);if (ret ==SWAP_FAIL || !page_mapped (page))
@@ -946,7 +946,7 @@ static int try_to_unmap_file(struct page mapcount =page_mapcount (page);if (!mapcount) goto out; -cond_resched_lock (&mapping->i_mmap_lock); +cond_resched_rwlock (&mapping->i_mmap_lock,0 ); max_nl_size = (max_nl_size +CLUSTER_SIZE -1 ) &CLUSTER_MASK ;if (max_nl_cursor ==0 )
@@ -968,7 +968,7 @@ static int try_to_unmap_file(struct page } vma->vm_private_data = (void *) max_nl_cursor; } -cond_resched_lock (&mapping->i_mmap_lock); +cond_resched_rwlock (&mapping->i_mmap_lock,0 ); max_nl_cursor +=CLUSTER_SIZE ; }while (max_nl_cursor <= max_nl_size);
@@ -980,7 +980,7 @@ static int try_to_unmap_file(struct pagelist_for_each_entry (vma, &mapping->i_mmap_nonlinear, shared.vm_set.list) vma->vm_private_data =NULL ; out: -spin_unlock (&mapping->i_mmap_lock); +read_unlock (&mapping->i_mmap_lock);return ret; }
include/linux/sched.h +14 -3
@@ -1889,12 +1889,23 @@ static inline int need_resched(void)* cond_resched() and cond_resched_lock(): latency reduction via * explicit rescheduling in places that are safe. The return * value indicates whether a reschedule was done in fact. -* cond_resched_lock() will drop the spinlock before scheduling, -* cond_resched_softirq() will enable bhs before scheduling. +* cond_resched_softirq() will enable bhs before scheduling, +* cond_resched_*lock() will drop the *lock before scheduling. */ extern int cond_resched (void ); -extern int cond_resched_lock (spinlock_t * lock);extern int cond_resched_softirq (void ); +extern int __cond_resched_lock (void * lock,int lock_type); + +#define COND_RESCHED_SPIN 2 +static inline int cond_resched_lock (spinlock_t * lock) +{ +return __cond_resched_lock (lock,COND_RESCHED_SPIN ); +} + +static inline int cond_resched_rwlock (rwlock_t * lock,int write_lock) +{ +return __cond_resched_lock (lock, !!write_lock); +}/* * Does a critical section need to be broken due to another
kernel/sched.c +54 -10
88 lines not on this page · raw message
arch/x86/mm/hugetlbpage.c +2 -2
@@ -68,7 +68,7 @@ static void huge_pmd_share(struct mm_strif (!vma_shareable (vma, addr))return ; -spin_lock (&mapping->i_mmap_lock); +read_lock (&mapping->i_mmap_lock); vma_prio_tree_foreach(svma, &iter, &mapping->i_mmap, idx, idx) {if (svma == vma)continue ;
@@ -93,7 +93,7 @@ static void huge_pmd_share(struct mm_strput_page (virt_to_page (spte));spin_unlock (&mm->page_table_lock); out: -spin_unlock (&mapping->i_mmap_lock); +read_unlock (&mapping->i_mmap_lock); }/*
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 7 lines · Rik van Riel
I have seen soft cpu lockups in
page_referenced_file()due to contention oni_mmap_lock()for different pages. Making thei_mmap_locka reader/writer lock should increase parallelism in vmscan for file back pages mapped into many address spaces.Read lock the
i_mmap_lockfor all usage except:
Quoted 8 lines
1) mmap/munmap: linking vma into
i_mmapprio_treeor removing
2)unmap_mapping_range: protectingvm_truncate_countrmap:
try_to_unmap_file()required newcond_resched_rwlock(). To reduce code duplication, I recastcond_resched_lock()as a [static inline] wrapper around reworkedcond_sched_lock()=>__cond_resched_lock(void *lock, int type).
Newcond_resched_rwlock()implemented as another wrapper.
Reader/writer locks really suck in terms of fairness and starvation, especially when the read-side is common and frequent. (also, single threaded performance of the read-side is worse).
I know Lee saw some big latencies on the anon_vma list lock when running (IIRC) a large benchmark... but are there more realistic situations where this is a problem?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Hi
Quoted 9 lines
Quoted 5 lines
rmap:
try_to_unmap_file()required newcond_resched_rwlock(). To reduce code duplication, I recastcond_resched_lock()as a [static inline] wrapper around reworkedcond_sched_lock()=>__cond_resched_lock(void *lock, int type).
Newcond_resched_rwlock()implemented as another wrapper.Reader/writer locks really suck in terms of fairness and starvation, especially when the read-side is common and frequent. (also, single threaded performance of the read-side is worse).
Agreed.
rwlock got bad performance some case. (especially on many cpu machine)
if many cpu grab read-lock on and off on many cpu system.
then at least 1 cpu always grab read lock and the cpu of waiting write-lock never get lock.
threrefore, rwlock often make performance weakness of stress.
I want know testcase for this patch and run it.
Do you have it?
/kosaki
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
In reply to Nick PigginQuoted 17 lines · Nick Piggin
Quoted 7 lines · Rik van Riel
I have seen soft cpu lockups in
page_referenced_file()due to contention oni_mmap_lock()for different pages. Making thei_mmap_locka reader/writer lock should increase parallelism in vmscan for file back pages mapped into many address spaces.Read lock the
i_mmap_lockfor all usage except:Quoted 8 lines
1) mmap/munmap: linking vma into
i_mmapprio_treeor removing
2)unmap_mapping_range: protectingvm_truncate_countrmap:
try_to_unmap_file()required newcond_resched_rwlock(). To reduce code duplication, I recastcond_resched_lock()as a [static inline] wrapper around reworkedcond_sched_lock()=>__cond_resched_lock(void *lock, int type).
Newcond_resched_rwlock()implemented as another wrapper.
Quoted 7 lines
Reader/writer locks really suck in terms of fairness and starvation, especially when the read-side is common and frequent. (also, single threaded performance of the read-side is worse).
I know Lee saw some big latencies on the
anon_vmalist lock when running (IIRC) a large benchmark... but are there more realistic situations where this is a problem?
Yes, we see the stall on the anon_vma lock most frequently running the AIM benchmark with several tens of thousands of processes--all forked from the same parent. If we push the system into reclaim, all cpus end up spinning on the lock in one of the anon_vma's shared by all the tasks. Quite easy to reproduce. I have also seen this running stress tests to force reclaim under Dave Anderson's "usex" exerciser--e.g., testing the split LRU and noreclaim patches--even with the reader-writer lock patch.
I've seen the lockups on the i_mmap_lock running Oracle workloads on our large servers. This is running an OLTP workload with only a thousand or
so "clients" all running the same application image. Again, when the
system attempts to reclaim we end up spinning on the i_mmap_lock of one of the files [possibly the shared global shmem segment] shared by all the applications. I also see it with the usex stress load--also, with and without this patch. I think this is a more probably scenario--thousands of processes sharing a single file, such as libc.so--than thousands of processes all descended from a single ancestor w/o exec'ing.
I keep these patches up to date for testing. I don't have conclusive evidence whether they alleviate or exacerbate the problem nor by how much.
Lee
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 3 lines · On Wed, 19 Dec 2007 10:52:09 -0500 Lee Schermerhorn <[email protected]>…
I keep these patches up to date for testing. I don't have conclusive evidence whether they alleviate or exacerbate the problem nor by how much.
When the queued locking from Ingo's x86 tree hits mainline, I suspect that spinlocks may end up behaving a lot nicer.
Should I drop the rwlock patches from my tree for now and focus on just the page reclaim stuff?
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 9 lines · Rik van Riel
Quoted 3 lines · On Wed, 19 Dec 2007 10:52:09 -0500 Lee Schermerhorn <[email protected]>…
I keep these patches up to date for testing. I don't have conclusive evidence whether they alleviate or exacerbate the problem nor by how much.
When the queued locking from Ingo's x86 tree hits mainline, I suspect that spinlocks may end up behaving a lot nicer.
That would be worth testing with our problematic workloads...
Quoted 3 lines
Should I drop the rwlock patches from my tree for now and focus on just the page reclaim stuff?
That's fine with me. They're out there is anyone is interested. I'll keep them up to date in my tree [and hope they don't conflict with split lru and noreclaim patches too much] for occasional testing.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 14 lines · Lee Schermerhorn
Quoted 9 lines · Rik van Riel
Quoted 3 lines · On Wed, 19 Dec 2007 10:52:09 -0500 Lee Schermerhorn <[email protected]>…
I keep these patches up to date for testing. I don't have conclusive evidence whether they alleviate or exacerbate the problem nor by how much.
When the queued locking from Ingo's x86 tree hits mainline, I suspect that spinlocks may end up behaving a lot nicer.
That would be worth testing with our problematic workloads...
Quoted 1 line
Quoted 6 lines
Quoted 2 lines
Should I drop the rwlock patches from my tree for now and focus on just the page reclaim stuff?
That's fine with me. They're out there is anyone is interested. I'll keep them up to date in my tree [and hope they don't conflict with split lru and noreclaim patches too much] for occasional testing.
Of course, someone would need to implement ticket locks for ia64 - preferably without the 256 cpu limit.
Nick, growing spinlock_t to 64 bits would yield space for 64k cpus, right? I'm guessing that would be enough for a while, even for SGI.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 17 lines · Peter Zijlstra
Quoted 16 lines · Lee Schermerhorn
Quoted 9 lines · Rik van Riel
On Wed, 19 Dec 2007 10:52:09 -0500
Quoted 3 lines · Lee Schermerhorn
I keep these patches up to date for testing. I don't have conclusive evidence whether they alleviate or exacerbate the problem nor by how much.
When the queued locking from Ingo's x86 tree hits mainline, I suspect that spinlocks may end up behaving a lot nicer.
That would be worth testing with our problematic workloads...
Quoted 2 lines
Should I drop the rwlock patches from my tree for now and focus on just the page reclaim stuff?
Quoted 6 lines
Quoted 3 lines
That's fine with me. They're out there is anyone is interested. I'll keep them up to date in my tree [and hope they don't conflict with split lru and noreclaim patches too much] for occasional testing.
Of course, someone would need to implement ticket locks for ia64 - preferably without the 256 cpu limit.
Yep. Wouldn't be hard at all -- ia64 has a "fetchadd" with acquire semantics.
The only reason the x86 ticket locks have the 256 CPu limit is that if they go any bigger, we can't use the partial registers so would have to have a few more instructions.
Quoted 2 lines
Nick, growing
spinlock_tto 64 bits would yield space for 64k cpus right? I'm guessing that would be enough for a while, even for SGI.
A 32 bit spinlock would allow 64K cpus (ticket lock has 2 counters, each would be 16 bits). And it would actually shrink the spinlock in the case of preempt kernels too (because it would no longer have the lockbreak field).
And yes, I'll go out on a limb and say that 64k CPUs ought to be enough for anyone ;)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 4 lines
The only reason the x86 ticket locks have the 256 CPu limit is that if they go any bigger, we can't use the partial registers so would have to have a few more instructions.
x86_64 is going up to 4k or 16k cpus soon for our new hardware.
Quoted 7 lines
A 32 bit spinlock would allow 64K cpus (ticket lock has 2 counters, each would be 16 bits). And it would actually shrink the spinlock in the case of preempt kernels too (because it would no longer have the lockbreak field).
And yes, I'll go out on a limb and say that 64k CPUs ought to be enough for anyone ;)
I think those things need a timeframe applied to it. Thats likely going to be true for the next 3 years (optimistic assessment ;-)).
Could you go to 32bit spinlock by default?
How about NUMA awareness for the spinlocks? Larger backoff periods for off node lock contentions please.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 11 lines · Christoph Lameter
Quoted 3 lines
The only reason the x86 ticket locks have the 256 CPu limit is that if they go any bigger, we can't use the partial registers so would have to have a few more instructions.
x86_64is going up to 4k or 16k cpus soon for our new hardware.Quoted 5 lines
A 32 bit spinlock would allow 64K cpus (ticket lock has 2 counters, each would be 16 bits). And it would actually shrink the spinlock in the case of preempt kernels too (because it would no longer have the lockbreak field).
Quoted 5 lines
Quoted 2 lines
And yes, I'll go out on a limb and say that 64k CPUs ought to be enough for anyone ;)
I think those things need a timeframe applied to it. Thats likely going to be true for the next 3 years (optimistic assessment ;-)).
Yeah, that was tongue in cheek ;)
Quoted 1 line
Could you go to 32bit spinlock by default?
On x86, the size of the ticket locks is 32 bit, simply because I didn't want to risk possible alignment bugs (a subsequent patch cuts it down to 16 bits, but this is a much smaller win than 64->32 in general because of natural alignment of types).
Note that the ticket locks still support twice the number as the old spinlocks, so I'm not causing a regression here... but yes, increasing the size further will require an extra instruction or two.
Quoted 2 lines
How about NUMA awareness for the spinlocks? Larger backoff periods for off node lock contentions please.
ticket locks can naturally tell you how many waiters there are, and how many waiters are in front of you, so it is really nice for doing backoff (eg. you can adapt the backoff *very* nicely depending on how many are in front of you, and how quickly you are moving toward the front).
Also, since I got rid of the ->break_lock field, you could use that space perhaps to add a cpu # of the lock holder for even more backoff context (if you find that helps).
Anyway, I didn't do any of that because it obviously needs someone with real hardware in order to tune it properly.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Hi Nick,
Have you done anything more with allowing > 256 CPUS in this spinlock patch? We've been testing with 1k cpus and to verify with -mm kernel, we need to "unpatch" these spinlock changes.
Thanks,
Mike
Quoted 42 lines · Nick Piggin
Quoted 10 lines · Christoph Lameter
Quoted 3 lines
The only reason the x86 ticket locks have the 256 CPu limit is that if they go any bigger, we can't use the partial registers so would have to have a few more instructions.
x86_64is going up to 4k or 16k cpus soon for our new hardware.Quoted 5 lines
A 32 bit spinlock would allow 64K cpus (ticket lock has 2 counters, each would be 16 bits). And it would actually shrink the spinlock in the case of preempt kernels too (because it would no longer have the lockbreak field).
Quoted 4 lines
Quoted 2 lines
And yes, I'll go out on a limb and say that 64k CPUs ought to be enough for anyone ;)
I think those things need a timeframe applied to it. Thats likely going to be true for the next 3 years (optimistic assessment ;-)).
Yeah, that was tongue in cheek ;)
Quoted 1 line
Could you go to 32bit spinlock by default?
On x86, the size of the ticket locks is 32 bit, simply because I didn't want to risk possible alignment bugs (a subsequent patch cuts it down to 16 bits, but this is a much smaller win than 64->32 in general because of natural alignment of types).
Note that the ticket locks still support twice the number as the old spinlocks, so I'm not causing a regression here... but yes, increasing the size further will require an extra instruction or two.
Quoted 2 lines
How about NUMA awareness for the spinlocks? Larger backoff periods for off node lock contentions please.
ticket locks can naturally tell you how many waiters there are, and how many waiters are in front of you, so it is really nice for doing backoff (eg. you can adapt the backoff *very* nicely depending on how many are in front of you, and how quickly you are moving toward the front).
Also, since I got rid of the ->break_lock field, you could use that space perhaps to add a cpu # of the lock holder for even more backoff context (if you find that helps).
Quoted 8 lines
Anyway, I didn't do any of that because it obviously needs someone with real hardware in order to tune it properly.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 8 lines · Mike Travis
Hi Nick,
Have you done anything more with allowing > 256 CPUS in this spinlock patch? We've been testing with 1k cpus and to verify with -mm kernel, we need to "unpatch" these spinlock changes.
Thanks,
Mike
Hi Mike,
Actually I had it in my mind that 64 bit used single-byte locking like i386, so I didn't think I'd caused a regression there.
I'll take a look at fixing that up now.
Thanks,
Nick
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 10 lines · Nick Piggin
Quoted 3 lines
Have you done anything more with allowing > 256 CPUS in this spinlock patch? We've been testing with 1k cpus and to verify with -mm kernel, we need to "unpatch" these spinlock changes.
Hi Mike,
Actually I had it in my mind that 64 bit used single-byte locking like i386, so I didn't think I'd caused a regression there.
I'll take a look at fixing that up now.
thanks - this is a serious showstopper for the ticket spinlock patch.
( which has otherwise been performing very well in x86.git so far - it
has passed a few thousand bootup tests on 64-bit and 32-bit as well, so we are close to it being in a mergable state. Would be a pity to lose it due to the 256 cpus limit. )
Ingo
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 02/20] make the inode i_mmap_lock a reader/writer lock
Quoted 10 lines · Ingo Molnar
Quoted 9 lines · Nick Piggin
Quoted 3 lines
Have you done anything more with allowing > 256 CPUS in this spinlock patch? We've been testing with 1k cpus and to verify with -mm kernel, we need to "unpatch" these spinlock changes.
Hi Mike,
Actually I had it in my mind that 64 bit used single-byte locking like i386, so I didn't think I'd caused a regression there.
Quoted 8 lines
Quoted 1 line
I'll take a look at fixing that up now.
thanks - this is a serious showstopper for the ticket spinlock patch.
( which has otherwise been performing very well in x86.git so far - it
has passed a few thousand bootup tests on 64-bit and 32-bit as well, so we are close to it being in a mergable state. Would be a pity to lose it due to the 256 cpus limit. )
OK, this is what my test harness code looks like for > 256 CPUs (basically the same as the in-kernel code, but some names etc. are slightly different).
It passes my basic tests, and performance doesn't seem to have suffered. I was going to suggest making the <= 256 vs > 256 cases config options, but maybe we don't need to unless some CPUs are slow at shifts / rotates? I don't know...
After I get comments, I will come up with an incremental patch against the kernel... It will be interesting to know whether ticket locks help big SGI systems.
static inline void xlock(lock_t *lock)
{
lock_t inc = 0x00010000;
lock_t tmp;
__asm__ __volatile__ (
"lock ; xaddl %0, %1\n"
"movzwl %w0, %2\n\t"
"shrl $16, %0\n\t"
"1:\t"
"cmpl %0, %2\n\t"
"je 2f\n\t"
"rep ; nop\n\t"
"movzwl %1, %2\n\t"
/* don't need lfence here, because loads are in-order */
"jmp 1b\n"
"2:"
:"+Q" (inc), "+m" (*lock), "=r" (tmp)
:
:"memory", "cc");
}static inline int xtrylock(lock_t *lock)
{
lock_t tmp;
lock_t new;
asm volatile(
"movl %2,%0\n\t"
"movl %0,%1\n\t"
"roll $16, %0\n\t"
"cmpl %0,%1\n\t"
"jne 1f\n\t"
"addl $0x00010000, %1\n\t"
"lock ; cmpxchgl %1,%2\n\t"
"1:"
"sete %b1\n\t"
"movzbl %b1,%0\n\t"
:"=&a" (tmp), "=r" (new), "+m" (*lock)
:
: "memory", "cc");
return tmp;
}static inline void xunlock(lock_t *lock)
{
__asm__ __volatile__(
"incw %0"
:"+m" (*lock)
:
:"memory", "cc");
}--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/20 move isolate_lru_page() to vmscan.c
In reply to Rik van RielV1 -> V2 [lts]:
+ fix botched merge -- add back "get_page_unless_zero()"
From: Nick Piggin <[email protected]>
To: Linux Memory Management <[email protected]>
Subject: [patch 1/4] mm: move and rework isolate_lru_page
Date: Mon, 12 Mar 2007 07:38:44 +0100 (CET)
isolate_lru_page logically belongs to be in vmscan.c than migrate.c.
It is tough, because we don't need that function without memory migration so there is a valid argument to have it in migrate.c. However a subsequent patch needs to make use of it in the core mm, so we can happily move it to vmscan.c.
Also, make the function a little more generic by not requiring that it adds an isolated page to a given list. Callers can do that.
Note that we now have '__isolate_lru_page()', that does something quite different, visible outside of vmscan.c for use with memory controller. Methinks we need to
rationalize these names/purposes. --lts
include/linux/migrate.h +0 -3
@@ -25,7 +25,6 @@ static inline int vma_migratable(structreturn 1 ; } -extern int isolate_lru_page (struct page *p,struct list_head *pagelist);extern int putback_lru_pages (struct list_head *l);extern int migrate_page (struct address_space *,struct page *,struct page *);
@@ -42,8 +41,6 @@ extern int migrate_vmas(struct mm_structstatic inline int vma_migratable (struct vm_area_struct *vma) {return 0 ; } -static inline int isolate_lru_page (struct page *p,struct list_head *list) - {return -ENOSYS ; }static inline int putback_lru_pages (struct list_head *l) {return 0 ; }static inline int migrate_pages (struct list_head *l,new_page_t x,unsigned long private) {return -ENOSYS ; }
mm/internal.h +2 -0
@@ -34,6 +34,8 @@ static inline void __put_page(struct pagatomic_dec (&page->_count); } +extern int isolate_lru_page (struct page *page); + extern void fastcall __init __free_pages_bootmem(struct page *page,unsigned int order);
mm/migrate.c +10 -37
60 lines not on this page · raw message
mm/vmscan.c +41 -0
47 lines not on this page · raw message
mm/mempolicy.c +8 -2
@@ -93,6 +93,8 @@#include <asm/tlbflush.h> #include <asm/uaccess.h> +#include "internal.h" +/* Internal flags */ #define MPOL_MF_DISCONTIG_OK (MPOL_MF_INTERNAL << 0)/* Skip checks for continuous vmas */ #define MPOL_MF_INVERT (MPOL_MF_INTERNAL << 1)/* Invert check for nodemask */
@@ -603,8 +605,12 @@ static void migrate_page_add(struct page/* * Avoid migrating a page that is shared with others. */ -if ((flags &MPOL_MF_MOVE_ALL ) ||page_mapcount (page) ==1 ) -isolate_lru_page (page, pagelist); +if ((flags &MPOL_MF_MOVE_ALL ) ||page_mapcount (page) ==1 ) { +if (!isolate_lru_page (page)) { +get_page (page); +list_add_tail (&page->lru, pagelist); + } + } }static struct page *new_node_page (struct page *page,unsigned long node,int **x)
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 03/20] move isolate_lru_page() to vmscan.c
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 4/20 free swap space on swap-in/activation
In reply to Rik van Riel+ lts' convert anon_vma list lock to reader/write lock patch
+ Nick Piggin's move and rework isolate_lru_page() patch
Free swap cache entries when swapping in pages if vm_swap_full() [swap space > 1/2 used?]. Uses new pagevec to reduce pressure on locks.
mm/vmscan.c +7 -0
@@ -632,6 +632,9 @@ free_it:continue ; activate_locked: +/* Not a candidate for swapping, so reclaim swap space. */ +if (PageSwapCache (page) &&vm_swap_full ()) +remove_exclusive_swap_page (page);SetPageActive (page); pgactivate++; keep_locked:
@@ -1213,6 +1216,8 @@ static void shrink_active_list(unsigned__mod_zone_page_state (zone,NR_ACTIVE , pgmoved); pgmoved =0 ;spin_unlock_irq (&zone->lru_lock); +if (vm_swap_full ()) +pagevec_swap_free (&pvec);__pagevec_release (&pvec);spin_lock_irq (&zone->lru_lock); }
@@ -1222,6 +1227,8 @@ static void shrink_active_list(unsigned__count_zone_vm_events (PGREFILL , zone, pgscanned);__count_vm_events (PGDEACTIVATE , pgdeactivate);spin_unlock_irq (&zone->lru_lock); +if (vm_swap_full ()) +pagevec_swap_free (&pvec);pagevec_release (&pvec); }
mm/swap.c +18 -0
@@ -465,6 +465,24 @@ void pagevec_strip(struct pagevec *pvec) } } +/* +* Try to free swap space from the pages in a pagevec +*/ +void pagevec_swap_free (struct pagevec *pvec) +{ +int i; + +for (i =0 ; i <pagevec_count (pvec); i++) { +struct page *page = pvec->pages[i]; + +if (PageSwapCache (page) && !TestSetPageLocked (page)) { +if (PageSwapCache (page)) +remove_exclusive_swap_page (page); +unlock_page (page); + } + } +} +/** * pagevec_lookup - gang pagecache lookup * @pvec: Where the resulting pages are placed
include/linux/pagevec.h +1 -0
@@ -26,6 +26,7 @@ void __pagevec_free(struct pagevec *pvecvoid __pagevec_lru_add (struct pagevec *pvec);void __pagevec_lru_add_active (struct pagevec *pvec);void pagevec_strip (struct pagevec *pvec); +void pagevec_swap_free (struct pagevec *pvec);unsigned pagevec_lookup (struct pagevec *pvec,struct address_space *mapping,pgoff_t start,unsigned nr_pages); unsigned pagevec_lookup_tag(struct pagevec *pvec,
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 5/20 define page_file_cache() function
In reply to Rik van RielDefine page_file_cache() function to answer the question:
is page backed by a file?
Originally part of Rik van Riel's split-lru patch. Extracted to make available for other, independent reclaim patches.
Moved inline function to linux/mm_inline.h where it will be needed by subsequent "split LRU" and "noreclaim" patches.
Unfortunately this needs to use a page flag, since the PG_swapbacked state needs to be preserved all the way to the point where the page is last removed from the LRU. Trying to derive the status from other info in the page resulted in wrong VM statistics in earlier split VM patchsets.
include/linux/mm_inline.h +22 -0
@@ -1,3 +1,24 @@ +#ifndef LINUX_MM_INLINE_H +#define LINUX_MM_INLINE_H + +/** +* page_file_cache(@page) +* Returns !0 if @page is page cache page backed by a regular filesystem, +* or 0 if @page is anonymous, tmpfs or otherwise ram or swap backed. +* +* We would like to get this info without a page flag, but the state +* needs to survive until the page is last deleted from the LRU, which +* could be as far down as __page_cache_release. +*/ +static inline int page_file_cache (struct page *page) +{ +if (PageSwapBacked (page)) +return 0 ; + +/* The page is page cache backed by a normal filesystem. */ +return 2 ; +} +static inline void add_page_to_active_list (struct zone *zone,struct page *page) {
@@ -38,3 +59,4 @@ del_page_from_lru(struct zone *zone, str } } +#endif
mm/shmem.c +1 -0
@@ -1279,6 +1279,7 @@ repeat: goto failed; } +SetPageSwapBacked (filepage);spin_lock (&info->lock); entry =shmem_swp_alloc (info, idx, sgp);if (IS_ERR (entry))
include/linux/page-flags.h +5 -0
@@ -89,6 +89,7 @@#define PG_mappedtodisk 16/* Has blocks allocated on-disk */ #define PG_reclaim 17/* To be reclaimed asap */ #define PG_buddy 19/* Page is free, on buddy lists */ +#define PG_swapbacked 20/* Page is backed by RAM/swap */ /* PG_readahead is only used for file reads; PG_reclaim is only for writes */ #define PG_readahead PG_reclaim/* Reminder to do async read-ahead */
@@ -216,6 +217,10 @@ static inline void SetPageUptodate(struc#define ClearPageReclaim (page) clear_bit(PG_reclaim, &(page)->flags)#define TestClearPageReclaim (page) test_and_clear_bit(PG_reclaim, &(page)->flags) +#define PageSwapBacked (page) test_bit(PG_swapbacked, &(page)->flags) +#define SetPageSwapBacked (page) set_bit(PG_swapbacked, &(page)->flags) +#define __ClearPageSwapBacked (page) __clear_bit(PG_swapbacked, &(page)->flags) +#define PageCompound (page) test_bit(PG_compound, &(page)->flags)#define __SetPageCompound (page) __set_bit(PG_compound, &(page)->flags)#define __ClearPageCompound (page) __clear_bit(PG_compound, &(page)->flags)
mm/memory.c +3 -0
@@ -1664,6 +1664,7 @@ gotten:ptep_clear_flush (vma, address, page_table);set_pte_at (mm, address, page_table, entry);update_mmu_cache (vma, address, entry); +SetPageSwapBacked (new_page);lru_cache_add_active (new_page);page_add_new_anon_rmap (new_page, vma, address);
@@ -2132,6 +2133,7 @@ static int do_anonymous_page(struct mm_sif (!pte_none (*page_table)) goto release;inc_mm_counter (mm, anon_rss); +SetPageSwapBacked (page);lru_cache_add_active (page);page_add_new_anon_rmap (page, vma, address);set_pte_at (mm, address, page_table, entry);
@@ -2285,6 +2287,7 @@ static int __do_fault(struct mm_struct *set_pte_at (mm, address, page_table, entry);if (anon) {inc_mm_counter (mm, anon_rss); +SetPageSwapBacked (page);lru_cache_add_active (page);page_add_new_anon_rmap (page, vma, address); }else {
mm/swap_state.c +1 -0
@@ -86,6 +86,7 @@ static int __add_to_swap_cache(struct paif (!error) {page_cache_get (page);SetPageSwapCache (page); +SetPageSwapBacked (page);set_page_private (page, entry.val); total_swapcache_pages++;__inc_zone_page_state (page,NR_FILE_PAGES );
mm/migrate.c +2 -0
@@ -546,6 +546,8 @@ static int move_to_new_page(struct page/* Prepare mapping for the new page.*/ newpage->index = page->index; newpage->mapping = page->mapping; +if (PageSwapBacked (page)) +SetPageSwapBacked (newpage); mapping =page_mapping (page);if (!mapping)
mm/page_alloc.c +4 -0
@@ -253,6 +253,7 @@ static void bad_page(struct page *page)1 << PG_slab |1 << PG_swapcache |1 << PG_writeback | +1 << PG_swapbacked | 1 << PG_buddy );set_page_count (page,0 );reset_page_mapcount (page);
@@ -486,6 +487,8 @@ static inline int free_pages_check(strucbad_page (page);if (PageDirty (page))__ClearPageDirty (page); +if (PageSwapBacked (page)) +__ClearPageSwapBacked (page);/* * For now, we report if PG_reserved was found set, but do not * clear it, and do not free the page. But we shall soon need
@@ -632,6 +635,7 @@ static int prep_new_page(struct page *pa 1 << PG_swapcache | 1 << PG_writeback | 1 << PG_reserved | + 1 << PG_swapbacked | 1 << PG_buddy ))))bad_page (page);
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 6/20 debugging checks for page_file_cache()
In reply to Rik van RielDebug whether we end up classifying the wrong pages as filesystem backed. This has not triggered in stress tests on my system, but who knows...
include/linux/mm_inline.h +10 -0
@@ -1,6 +1,8 @@#ifndef LINUX_MM_INLINE_H #define LINUX_MM_INLINE_H +#include <linux/fs.h> /* for struct address_space */ +/** * page_file_cache(@page) * Returns !0 if @page is page cache page backed by a regular filesystem,
@@ -10,11 +12,19 @@* needs to survive until the page is last deleted from the LRU, which * could be as far down as __page_cache_release. */ +extern const struct address_space_operations shmem_aops;static inline int page_file_cache (struct page *page) { +struct address_space * mapping =page_mapping (page); +if (PageSwapBacked (page))return 0 ; +/* These pages should all be marked PG_swapbacked */ +WARN_ON (PageAnon (page)); +WARN_ON (PageSwapCache (page)); +WARN_ON (mapping && mapping->a_ops && mapping->a_ops == &shmem_aops); +/* The page is page cache backed by a normal filesystem. */ return 2 ; }
mm/shmem.c +2 -2
@@ -178,7 +178,7 @@ static inline void shmem_unacct_blocks(u }static const struct super_operations shmem_ops; -static const struct address_space_operations shmem_aops; +const struct address_space_operations shmem_aops;static const struct file_operations shmem_file_operations;static const struct inode_operations shmem_inode_operations;static const struct inode_operations shmem_dir_inode_operations;
@@ -2232,7 +2232,7 @@ static void destroy_inodecache(void)kmem_cache_destroy (shmem_inode_cachep); } -static const struct address_space_operations shmem_aops = { +const struct address_space_operations shmem_aops = { .writepage = shmem_writepage, .set_page_dirty = __set_page_dirty_no_writeback, #ifdef CONFIG_TMPFS
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 7/20 Use an indexed array for LRU variables
In reply to Rik van RielV1 -> V2 [lts]:
+ Remove extraneous __dec_zone_state(zone, NR_ACTIVE) pointed out by Mel G.
Quoted 1 line
From [email protected] Wed Aug 29 11:39:51 2007
Currently we are defining explicit variables for the inactive and active list. An indexed array can be more generic and avoid repeating similar code in several places in the reclaim code.
We are saving a few bytes in terms of code size:
Before:
text data bss dec hex filename
4097753 573120 4092484 8763357 85b7dd vmlinux
After:
text data bss dec hex filename
4097729 573120 4092484 8763333 85b7c5 vmlinux
Having an easy way to add new lru lists may ease future work on the reclaim code.
include/linux/mm_inline.h | 34 ++++++++--- include/linux/mmzone.h | 17 +++-- mm/page_alloc.c | 9 +-- mm/swap.c | 2 mm/vmscan.c | 132 ++++++++++++++++++++++------------------------ mm/vmstat.c | 3 - 6 files changed, 107 insertions(+), 90 deletions(-)
include/linux/mmzone.h +11 -6
@@ -80,8 +80,8 @@ struct zone_padding {enum zone_stat_item {/* First 128 byte cacheline (assuming 64 bit words) */ NR_FREE_PAGES , -NR_INACTIVE , -NR_ACTIVE , +NR_INACTIVE ,/* must match order of LRU_[IN]ACTIVE */ +NR_ACTIVE ,/* " " " " " */ NR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED ,/* pagecache pages mapped into pagetables. only modified from process context */
@@ -105,6 +105,13 @@ enum zone_stat_item {#endif NR_VM_ZONE_STAT_ITEMS }; +enum lru_list { +LRU_INACTIVE ,/* must match order of NR_[IN]ACTIVE */ +LRU_ACTIVE ,/* " " " " " */ +NR_LRU_LISTS }; + +#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +struct per_cpu_pages {int count;/* number of pages in the list */ int high;/* high watermark, emptying needed */
@@ -258,10 +265,8 @@ struct zone {/* Fields commonly accessed by the page reclaim scanner */ spinlock_t lru_lock; -struct list_head active_list; -struct list_head inactive_list; -unsigned long nr_scan_active; -unsigned long nr_scan_inactive; +struct list_head list[NR_LRU_LISTS ]; +unsigned long nr_scan[NR_LRU_LISTS ];unsigned long pages_scanned;/* since last reclaim */ unsigned long flags;/* zone flags, see below */
include/linux/mm_inline.h +23 -11
@@ -30,43 +30,55 @@ static inline int page_file_cache(struct }static inline void +add_page_to_lru_list (struct zone *zone,struct page *page,enum lru_list l) +{ +list_add (&page->lru, &zone->list[l]); +__inc_zone_state (zone,NR_INACTIVE + l); +} + +static inline void +del_page_from_lru_list (struct zone *zone,struct page *page,enum lru_list l) +{ +list_del (&page->lru); +__dec_zone_state (zone,NR_INACTIVE + l); +} + + +static inline void add_page_to_active_list (struct zone *zone,struct page *page) { -list_add (&page->lru, &zone->active_list); -__inc_zone_state (zone,NR_ACTIVE ); +add_page_to_lru_list (zone, page,LRU_ACTIVE ); }static inline void add_page_to_inactive_list (struct zone *zone,struct page *page) { -list_add (&page->lru, &zone->inactive_list); -__inc_zone_state (zone,NR_INACTIVE ); +add_page_to_lru_list (zone, page,LRU_INACTIVE ); }static inline void del_page_from_active_list (struct zone *zone,struct page *page) { -list_del (&page->lru); -__dec_zone_state (zone,NR_ACTIVE ); +del_page_from_lru_list (zone, page,LRU_ACTIVE ); }static inline void del_page_from_inactive_list (struct zone *zone,struct page *page) { -list_del (&page->lru); -__dec_zone_state (zone,NR_INACTIVE ); +del_page_from_lru_list (zone, page,LRU_INACTIVE ); }static inline void del_page_from_lru (struct zone *zone,struct page *page) { +enum lru_list l =LRU_INACTIVE ; +list_del (&page->lru);if (PageActive (page)) {__ClearPageActive (page); -__dec_zone_state (zone,NR_ACTIVE ); - }else { -__dec_zone_state (zone,NR_INACTIVE ); + l =LRU_ACTIVE ; } +__dec_zone_state (zone,NR_INACTIVE + l); }#endif
mm/page_alloc.c +5 -4
@@ -3404,6 +3404,7 @@ static void __meminit free_area_init_corfor (j =0 ; j <MAX_NR_ZONES ; j++) {struct zone *zone = pgdat->node_zones + j;unsigned long size, realsize, memmap_pages; +enum lru_list l; size =zone_spanned_pages_in_node (nid, j, zones_size); realsize = size - zone_absent_pages_in_node(nid, j,
@@ -3453,10 +3454,10 @@ static void __meminit free_area_init_cor zone->prev_priority =DEF_PRIORITY ;zone_pcp_init (zone); -INIT_LIST_HEAD (&zone->active_list); -INIT_LIST_HEAD (&zone->inactive_list); - zone->nr_scan_active =0 ; - zone->nr_scan_inactive =0 ; +for_each_lru (l) { +INIT_LIST_HEAD (&zone->list[l]); + zone->nr_scan[l] =0 ; + }zap_zone_vm_stats (zone); zone->flags =0 ;if (!size)
mm/swap.c +1 -1
@@ -118,7 +118,7 @@ static void pagevec_move_tail(struct pagspin_lock (&zone->lru_lock); }if (PageLRU (page) && !PageActive (page)) { -list_move_tail (&page->lru, &zone->inactive_list); +list_move_tail (&page->lru, &zone->list[LRU_INACTIVE ]); pgmoved++; } }
mm/vmscan.c +67 -70
238 lines not on this page · raw message
mm/vmstat.c +2 -1
@@ -765,7 +765,8 @@ static void zoneinfo_show_print(struct s zone->pages_low, zone->pages_high, zone->pages_scanned, - zone->nr_scan_active, zone->nr_scan_inactive, + zone->nr_scan[LRU_ACTIVE ], + zone->nr_scan[LRU_INACTIVE ], zone->spanned_pages, zone->present_pages);
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 8/20 split LRU lists into anon & file sets
In reply to Rik van RielSplit the LRU lists in two, one set for pages that are backed by real file systems ("file") and one for pages that are backed by memory and swap ("anon"). The latter includes tmpfs.
Eventually mlocked pages will be taken off the LRUs alltogether. A patch for that already exists and just needs to be integrated into this series.
This patch mostly has the infrastructure and a basic policy to balance how much we scan the anon lists and how much we scan the file lists. Fancy policy changes will be in separate patches.
fs/proc/proc_misc.c +35 -31
@@ -153,43 +153,47 @@ static int meminfo_read_proc(char *page,* Tagged format, for easy grepping and expansion. */ len = sprintf(page, - "MemTotal: %8lu kB\n" - "MemFree: %8lu kB\n" - "Buffers: %8lu kB\n" - "Cached: %8lu kB\n" - "SwapCached: %8lu kB\n" - "Active: %8lu kB\n" - "Inactive: %8lu kB\n" + "MemTotal: %8lu kB\n" + "MemFree: %8lu kB\n" + "Buffers: %8lu kB\n" + "Cached: %8lu kB\n" + "SwapCached: %8lu kB\n" + "Active(anon): %8lu kB\n" + "Inactive(anon): %8lu kB\n" + "Active(file): %8lu kB\n" + "Inactive(file): %8lu kB\n" #ifdef CONFIG_HIGHMEM - "HighTotal: %8lu kB\n" - "HighFree: %8lu kB\n" - "LowTotal: %8lu kB\n" - "LowFree: %8lu kB\n" -#endif - "SwapTotal: %8lu kB\n" - "SwapFree: %8lu kB\n" - "Dirty: %8lu kB\n" - "Writeback: %8lu kB\n" - "AnonPages: %8lu kB\n" - "Mapped: %8lu kB\n" - "Slab: %8lu kB\n" - "SReclaimable: %8lu kB\n" - "SUnreclaim: %8lu kB\n" - "PageTables: %8lu kB\n" - "NFS_Unstable: %8lu kB\n" - "Bounce: %8lu kB\n" - "CommitLimit: %8lu kB\n" - "Committed_AS: %8lu kB\n" - "VmallocTotal: %8lu kB\n" - "VmallocUsed: %8lu kB\n" - "VmallocChunk: %8lu kB\n", + "HighTotal: %8lu kB\n" + "HighFree: %8lu kB\n" + "LowTotal: %8lu kB\n" + "LowFree: %8lu kB\n" +#endif + "SwapTotal: %8lu kB\n" + "SwapFree: %8lu kB\n" + "Dirty: %8lu kB\n" + "Writeback: %8lu kB\n" + "AnonPages: %8lu kB\n" + "Mapped: %8lu kB\n" + "Slab: %8lu kB\n" + "SReclaimable: %8lu kB\n" + "SUnreclaim: %8lu kB\n" + "PageTables: %8lu kB\n" + "NFS_Unstable: %8lu kB\n" + "Bounce: %8lu kB\n" + "CommitLimit: %8lu kB\n" + "Committed_AS: %8lu kB\n" + "VmallocTotal: %8lu kB\n" + "VmallocUsed: %8lu kB\n" + "VmallocChunk: %8lu kB\n", K(i.totalram), K(i.freeram), K(i.bufferram), K(cached), K(total_swapcache_pages), - K(global_page_state(NR_ACTIVE)), - K(global_page_state(NR_INACTIVE)), + K(global_page_state(NR_ACTIVE_ANON)), + K(global_page_state(NR_INACTIVE_ANON)), + K(global_page_state(NR_ACTIVE_FILE)), + K(global_page_state(NR_INACTIVE_FILE)), #ifdef CONFIG_HIGHMEM K(i.totalhigh), K(i.freehigh),
fs/cifs/file.c +2 -2
@@ -1783,7 +1783,7 @@ static void cifs_copy_cache_pages(structSetPageUptodate (page);unlock_page (page);if (!pagevec_add (plru_pvec, page)) -__pagevec_lru_add (plru_pvec); +__pagevec_lru_add_file (plru_pvec); data +=PAGE_CACHE_SIZE ; }return ;
@@ -1921,7 +1921,7 @@ static int cifs_readpages(struct file *f bytes_read =0 ; } -pagevec_lru_add (&lru_pvec); +pagevec_lru_add_file (&lru_pvec);/* need to free smb_read_data buf before exit */ if (smb_read_data) {
fs/ntfs/file.c +2 -2
@@ -439,7 +439,7 @@ static inline int __ntfs_grab_cache_page pages[nr] = *cached_page;page_cache_get (*cached_page);if (unlikely (!pagevec_add (lru_pvec, *cached_page))) -__pagevec_lru_add (lru_pvec); +__pagevec_lru_add_file (lru_pvec); *cached_page =NULL ; } index++;
@@ -2084,7 +2084,7 @@ err_out: OSYNC_METADATA|OSYNC_DATA); } } -pagevec_lru_add (&lru_pvec); +pagevec_lru_add_file (&lru_pvec);ntfs_debug ("Done. Returning %s (written 0x%lx, status %li)." , written ?"written" :"status" , (unsigned long )written, (long )status);
fs/nfs/dir.c +1 -1
@@ -1497,7 +1497,7 @@ static int nfs_symlink(struct inode *dirif (!add_to_page_cache (page, dentry->d_inode->i_mapping,0 ,GFP_KERNEL )) {pagevec_add (&lru_pvec, page); -pagevec_lru_add (&lru_pvec); +pagevec_lru_add_file (&lru_pvec);SetPageUptodate (page);unlock_page (page); }else
fs/ramfs/file-nommu.c +2 -2
@@ -111,12 +111,12 @@ static int ramfs_nommu_expand_for_mappin goto add_error;if (!pagevec_add (&lru_pvec, page)) -__pagevec_lru_add (&lru_pvec); +__pagevec_lru_add_file (&lru_pvec);unlock_page (page); } -pagevec_lru_add (&lru_pvec); +pagevec_lru_add_file (&lru_pvec);return 0 ; fsize_exceeded:
drivers/base/node.c +26 -22
59 lines not on this page · raw message
mm/memory.c +3 -3
@@ -1665,7 +1665,7 @@ gotten:set_pte_at (mm, address, page_table, entry);update_mmu_cache (vma, address, entry);SetPageSwapBacked (new_page); -lru_cache_add_active (new_page); +lru_cache_add_active_anon (new_page);page_add_new_anon_rmap (new_page, vma, address);/* Free the old page.. */
@@ -2134,7 +2134,7 @@ static int do_anonymous_page(struct mm_s goto release;inc_mm_counter (mm, anon_rss);SetPageSwapBacked (page); -lru_cache_add_active (page); +lru_cache_add_active_anon (page);page_add_new_anon_rmap (page, vma, address);set_pte_at (mm, address, page_table, entry);
@@ -2288,7 +2288,7 @@ static int __do_fault(struct mm_struct *if (anon) {inc_mm_counter (mm, anon_rss);SetPageSwapBacked (page); -lru_cache_add_active (page); +lru_cache_add_active_anon (page);page_add_new_anon_rmap (page, vma, address); }else {inc_mm_counter (mm, file_rss);
mm/page_alloc.c +17 -7
@@ -1879,10 +1879,13 @@ void show_free_areas(void) } } - printk("Active:%lu inactive:%lu dirty:%lu writeback:%lu unstable:%lu\n" + printk("Active_anon:%lu active_file:%lu inactive_anon%lu\n" + " inactive_file:%lu dirty:%lu writeback:%lu unstable:%lu\n" " free:%lu slab:%lu mapped:%lu pagetables:%lu bounce:%lu\n", - global_page_state(NR_ACTIVE), - global_page_state(NR_INACTIVE), + global_page_state(NR_ACTIVE_ANON), + global_page_state(NR_ACTIVE_FILE), + global_page_state(NR_INACTIVE_ANON), + global_page_state(NR_INACTIVE_FILE), global_page_state(NR_FILE_DIRTY), global_page_state(NR_WRITEBACK), global_page_state(NR_UNSTABLE_NFS),
@@ -1905,8 +1908,10 @@ void show_free_areas(void)" min:%lukB" " low:%lukB" " high:%lukB" -" active:%lukB" -" inactive:%lukB" +" active_anon:%lukB" +" inactive_anon:%lukB" +" active_file:%lukB" +" inactive_file:%lukB" " present:%lukB" " pages_scanned:%lu" " all_unreclaimable? %s"
@@ -1916,8 +1921,10 @@ void show_free_areas(void)K (zone->pages_min),K (zone->pages_low),K (zone->pages_high), -K (zone_page_state (zone,NR_ACTIVE )), -K (zone_page_state (zone,NR_INACTIVE )), +K (zone_page_state (zone,NR_ACTIVE_ANON )), +K (zone_page_state (zone,NR_INACTIVE_ANON )), +K (zone_page_state (zone,NR_ACTIVE_FILE )), +K (zone_page_state (zone,NR_INACTIVE_FILE )),K (zone->present_pages), zone->pages_scanned, (zone_is_all_unreclaimable (zone) ?"yes" :"no" )
@@ -3458,6 +3465,9 @@ static void __meminit free_area_init_corINIT_LIST_HEAD (&zone->list[l]); zone->nr_scan[l] =0 ; } + zone->recent_rotated_anon =0 ; + zone->recent_rotated_file =0 ; +//TODO recent_scanned_* ??? zap_zone_vm_stats (zone); zone->flags =0 ;if (!size)
mm/swap.c +112 -21
205 lines not on this page · raw message
mm/migrate.c +8 -2
@@ -60,9 +60,15 @@ static inline void move_to_lru(struct pa* the PG_active bit is off. */ ClearPageActive (page); -lru_cache_add_active (page); +if (page_file_cache (page)) +lru_cache_add_active_file (page); +else +lru_cache_add_active_anon (page); }else { -lru_cache_add (page); +if (page_file_cache (page)) +lru_cache_add_file (page); +else +lru_cache_add_anon (page); }put_page (page); }
mm/readahead.c +1 -1
@@ -229,7 +229,7 @@ int do_page_cache_readahead(struct addre*/ unsigned long max_sane_readahead (unsigned long nr) { -return min (nr, (node_page_state (numa_node_id (),NR_INACTIVE ) +return min (nr, (node_page_state (numa_node_id (),NR_INACTIVE_FILE ) +node_page_state (numa_node_id (),NR_FREE_PAGES )) /2 ); }
mm/filemap.c +7 -2
@@ -34,6 +34,7 @@#include <linux/cpuset.h> #include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */ #include <linux/memcontrol.h> +#include <linux/mm_inline.h> /* for page_file_cache() */ #include "internal.h" /*
@@ -481,8 +482,12 @@ int add_to_page_cache_lru(struct page *p pgoff_t offset, gfp_t gfp_mask) { int ret = add_to_page_cache(page, mapping, offset, gfp_mask); -if (ret ==0 ) -lru_cache_add (page); +if (ret ==0 ) { +if (page_file_cache (page)) +lru_cache_add_file (page); +else +lru_cache_add_active_anon (page); + }return ret; }
mm/vmstat.c +9 -5
@@ -693,8 +693,10 @@ const struct seq_operations pagetypeinfostatic const char *const vmstat_text[] = {/* Zoned VM counters */ "nr_free_pages" , -"nr_inactive" , -"nr_active" , +"nr_inactive_anon" , +"nr_active_anon" , +"nr_inactive_file" , +"nr_active_file" ,"nr_anon_pages" ,"nr_mapped" ,"nr_file_pages" ,
@@ -757,7 +759,7 @@ static void zoneinfo_show_print(struct s"\n min %lu" "\n low %lu" "\n high %lu" -"\n scanned %lu (a: %lu i: %lu)" +"\n scanned %lu (aa: %lu ia: %lu af: %lu if: %lu)" "\n spanned %lu" "\n present %lu" , zone_page_state(zone, NR_FREE_PAGES),
@@ -765,8 +767,10 @@ static void zoneinfo_show_print(struct s zone->pages_low, zone->pages_high, zone->pages_scanned, - zone->nr_scan[LRU_ACTIVE ], - zone->nr_scan[LRU_INACTIVE ], + zone->nr_scan[LRU_ACTIVE_ANON ], + zone->nr_scan[LRU_INACTIVE_ANON ], + zone->nr_scan[LRU_ACTIVE_FILE ], + zone->nr_scan[LRU_INACTIVE_FILE ], zone->spanned_pages, zone->present_pages);
mm/vmscan.c +200 -222
735 lines not on this page · raw message
mm/swap_state.c +1 -1
@@ -360,7 +360,7 @@ struct page *read_swap_cache_async(swp_e/* * Initiate read into locked page and return. */ -lru_cache_add_active (new_page); +lru_cache_add_active_anon (new_page);swap_readpage (NULL , new_page);return new_page; }
include/linux/mmzone.h +30 -5
@@ -80,21 +80,23 @@ struct zone_padding {enum zone_stat_item {/* First 128 byte cacheline (assuming 64 bit words) */ NR_FREE_PAGES , -NR_INACTIVE ,/* must match order of LRU_[IN]ACTIVE */ -NR_ACTIVE ,/* " " " " " */ +NR_INACTIVE_ANON ,/* must match order of LRU_[IN]ACTIVE_* */ +NR_ACTIVE_ANON ,/* " " " " " */ +NR_INACTIVE_FILE ,/* " " " " " */ +NR_ACTIVE_FILE ,/* " " " " " */ NR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED ,/* pagecache pages mapped into pagetables. only modified from process context */ NR_FILE_PAGES ,NR_FILE_DIRTY ,NR_WRITEBACK , -/* Second 128 byte cacheline */ NR_SLAB_RECLAIMABLE ,NR_SLAB_UNRECLAIMABLE ,NR_PAGETABLE ,/* used for pagetables */ NR_UNSTABLE_NFS ,/* NFS unstable pages */ NR_BOUNCE ,NR_VMSCAN_WRITE , +/* Second 128 byte cacheline */ #ifdef CONFIG_NUMA NUMA_HIT ,/* allocated in intended node */ NUMA_MISS ,/* allocated in non intended node */
@@ -105,13 +107,32 @@ enum zone_stat_item {#endif NR_VM_ZONE_STAT_ITEMS }; +/* +* We do arithmetic on the LRU lists in various places in the code, +* so it is important to keep the active lists LRU_ACTIVE higher in +* the array than the corresponding inactive lists, and to keep +* the *_FILE lists LRU_FILE higher than the corresponding _ANON lists. +*/ +#define LRU_BASE 0 +#define LRU_ANON LRU_BASE +#define LRU_ACTIVE 1 +#define LRU_FILE 2 +enum lru_list { -LRU_INACTIVE ,/* must match order of NR_[IN]ACTIVE */ -LRU_ACTIVE ,/* " " " " " */ +LRU_INACTIVE_ANON =LRU_BASE , +LRU_ACTIVE_ANON =LRU_BASE +LRU_ACTIVE , +LRU_INACTIVE_FILE =LRU_BASE +LRU_FILE , +LRU_ACTIVE_FILE =LRU_BASE +LRU_FILE +LRU_ACTIVE ,NR_LRU_LISTS };#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +static inline int is_file_lru (enum lru_list l) +{ +BUILD_BUG_ON (LRU_INACTIVE_FILE !=2 ||LRU_ACTIVE_FILE !=3 ); +return (l/2 ==1 ); +} +struct per_cpu_pages {int count;/* number of pages in the list */ int high;/* high watermark, emptying needed */
@@ -267,6 +288,10 @@ struct zone {spinlock_t lru_lock;struct list_head list[NR_LRU_LISTS ];unsigned long nr_scan[NR_LRU_LISTS ]; + +unsigned long recent_rotated_anon; +unsigned long recent_rotated_file; +unsigned long pages_scanned;/* since last reclaim */ unsigned long flags;/* zone flags, see below */
include/linux/mm_inline.h +39 -14
98 lines not on this page · raw message
include/linux/pagevec.h +12 -4
@@ -23,8 +23,10 @@ struct pagevec {void __pagevec_release (struct pagevec *pvec);void __pagevec_release_nonlru (struct pagevec *pvec);void __pagevec_free (struct pagevec *pvec); -void __pagevec_lru_add (struct pagevec *pvec); -void __pagevec_lru_add_active (struct pagevec *pvec); +void __pagevec_lru_add_file (struct pagevec *pvec); +void __pagevec_lru_add_active_file (struct pagevec *pvec); +void __pagevec_lru_add_anon (struct pagevec *pvec); +void __pagevec_lru_add_active_anon (struct pagevec *pvec);void pagevec_strip (struct pagevec *pvec);void pagevec_swap_free (struct pagevec *pvec); unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
@@ -82,10 +84,16 @@ static inline void pagevec_free(struct p __pagevec_free(pvec); } -static inline void pagevec_lru_add (struct pagevec *pvec) +static inline void pagevec_lru_add_file (struct pagevec *pvec) {if (pagevec_count (pvec)) -__pagevec_lru_add (pvec); +__pagevec_lru_add_file (pvec); +} + +static inline void pagevec_lru_add_anon (struct pagevec *pvec) +{ +if (pagevec_count (pvec)) +__pagevec_lru_add_anon (pvec); }#endif /* _LINUX_PAGEVEC_H */
include/linux/vmstat.h +10 -0
@@ -149,6 +149,16 @@ static inline unsigned long zone_page_streturn x; } +extern unsigned long global_lru_pages (void ); + +static inline unsigned long zone_lru_pages (struct zone *zone) +{ +return (zone_page_state (zone,NR_ACTIVE_ANON ) + +zone_page_state (zone,NR_ACTIVE_FILE ) + +zone_page_state (zone,NR_INACTIVE_ANON ) + +zone_page_state (zone,NR_INACTIVE_FILE )); +} +#ifdef CONFIG_NUMA /* * Determine the per node value of a stat item. This function
mm/page-writeback.c +2 -6
@@ -270,9 +270,7 @@ static unsigned long highmem_dirtyable_mstruct zone *z = &NODE_DATA (node)->node_zones[ZONE_HIGHMEM ]; - x +=zone_page_state (z,NR_FREE_PAGES ) - +zone_page_state (z,NR_INACTIVE ) - +zone_page_state (z,NR_ACTIVE ); + x +=zone_page_state (z,NR_FREE_PAGES ) +zone_lru_pages (z); }/* * Make sure that the number of highmem pages is never larger
@@ -290,9 +288,7 @@ static unsigned long determine_dirtyable {unsigned long x; - x =global_page_state (NR_FREE_PAGES ) - +global_page_state (NR_INACTIVE ) - +global_page_state (NR_ACTIVE ); + x =global_page_state (NR_FREE_PAGES ) +global_lru_pages ();if (!vm_highmem_is_dirtyable) x -=highmem_dirtyable_memory (x);
include/linux/swap.h +5 -3
@@ -171,8 +171,10 @@ extern unsigned int nr_free_pagecache_pa/* linux/mm/swap.c */ -extern void FASTCALL (lru_cache_add (struct page *)); -extern void FASTCALL (lru_cache_add_active (struct page *)); +extern void FASTCALL (lru_cache_add_file (struct page *)); +extern void FASTCALL (lru_cache_add_anon (struct page *)); +extern void FASTCALL (lru_cache_add_active_file (struct page *)); +extern void FASTCALL (lru_cache_add_active_anon (struct page *));extern void FASTCALL (activate_page (struct page *));extern void FASTCALL (mark_page_accessed (struct page *));extern void lru_add_drain (void );
@@ -185,7 +187,7 @@ extern unsigned long try_to_free_pages(s gfp_t gfp_mask);extern unsigned long try_to_free_mem_cgroup_pages (struct mem_cgroup *mem,gfp_t gfp_mask); -extern int __isolate_lru_page (struct page *page,int mode); +extern int __isolate_lru_page (struct page *page,int mode,int file);extern unsigned long shrink_all_memory (unsigned long nr_pages);extern int vm_swappiness;extern int remove_mapping (struct address_space *mapping,struct page *page);
include/linux/memcontrol.h +1 -1
@@ -41,7 +41,7 @@ extern unsigned long mem_cgroup_isolate_ unsigned long *scanned, int order, int mode, struct zone *z, struct mem_cgroup *mem_cont, - int active); + int active, int file);extern void mem_cgroup_out_of_memory (struct mem_cgroup *mem,gfp_t gfp_mask);extern int mem_cgroup_cache_charge (struct page *page,struct mm_struct *mm,gfp_t gfp_mask);
mm/memcontrol.c +7 -2
@@ -30,6 +30,7 @@#include <linux/spinlock.h> #include <linux/fs.h> #include <linux/seq_file.h> +#include <linux/mm_inline.h> #include <asm/uaccess.h>
@@ -511,7 +512,7 @@ unsigned long mem_cgroup_isolate_pages(u unsigned long *scanned, int order, int mode, struct zone *z, struct mem_cgroup *mem_cont, - int active) + int active, int file) { unsigned long nr_taken = 0;struct page *page;
@@ -523,6 +524,7 @@ unsigned long mem_cgroup_isolate_pages(uint zid =zone_idx (z);struct mem_cgroup_per_zone *mz; +/* TODO: split file and anon LRUs - Rik */ mz =mem_cgroup_zoneinfo (mem_cont, nid, zid);if (active) src = &mz->active_list;
@@ -541,6 +543,9 @@ unsigned long mem_cgroup_isolate_pages(uif (unlikely (!PageLRU (page)))continue ; +/* +* TODO: play better with lumpy reclaim, grabbing anything. +*/ if (PageActive (page) && !active) {__mem_cgroup_move_lists (pc, true);continue ;
@@ -553,7 +558,7 @@ unsigned long mem_cgroup_isolate_pages(u scan++;list_move (&pc->lru, &pc_list); -if (__isolate_lru_page (page, mode) ==0 ) { +if (__isolate_lru_page (page, mode, file) ==0 ) {list_move (&page->lru, dst); nr_taken++; }
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 9/20 split anon & file LRUs for memcontrol code
In reply to Rik van RielUpdate the split anon & file LRU code to deal with the recent memory controller changes.
include/linux/memcontrol.h +5 -12
@@ -73,10 +73,8 @@ extern void mem_cgroup_note_reclaim_prioextern void mem_cgroup_record_reclaim_priority (struct mem_cgroup *mem,int priority); -extern long mem_cgroup_calc_reclaim_active (struct mem_cgroup *mem, -struct zone *zone,int priority); -extern long mem_cgroup_calc_reclaim_inactive (struct mem_cgroup *mem, -struct zone *zone,int priority); +extern long mem_cgroup_calc_reclaim (struct mem_cgroup *mem,struct zone *zone, +int priority,int active,int file);#else /* CONFIG_CGROUP_MEM_CONT */ static inline void mm_init_cgroup(struct mm_struct *mm,
@@ -174,14 +172,9 @@ static inline void mem_cgroup_record_rec { } -static inline long mem_cgroup_calc_reclaim_active (struct mem_cgroup *mem, -struct zone *zone,int priority) -{ -return 0 ; -} - -static inline long mem_cgroup_calc_reclaim_inactive (struct mem_cgroup *mem, -struct zone *zone,int priority) +static inline long mem_cgroup_calc_reclaim (struct mem_cgroup *mem, +struct zone *zone,int priority, +int active,int file) {return 0 ; }
mm/memcontrol.c +67 -90
278 lines not on this page · raw message
mm/vmscan.c +9 -5
@@ -1250,11 +1250,15 @@ static unsigned long shrink_zone(int pri* because memory controller hits its limit. * Then, don't modify zone reclaim related data. */ - nr[LRU_ACTIVE ] =mem_cgroup_calc_reclaim_active (sc->mem_cgroup, - zone, priority); - - nr[LRU_INACTIVE ] =mem_cgroup_calc_reclaim_inactive (sc->mem_cgroup, - zone, priority); + nr[LRU_ACTIVE_FILE ] =mem_cgroup_calc_reclaim (sc->mem_cgroup, + zone, priority,1 ,1 ); + nr[LRU_INACTIVE_FILE ] =mem_cgroup_calc_reclaim (sc->mem_cgroup, + zone, priority,0 ,1 ); + + nr[LRU_ACTIVE_ANON ] =mem_cgroup_calc_reclaim (sc->mem_cgroup, + zone, priority,1 ,0 ); + nr[LRU_INACTIVE_ANON ] =mem_cgroup_calc_reclaim (sc->mem_cgroup, + zone, priority,0 ,0 ); } while (nr[LRU_ACTIVE_ANON] || nr[LRU_INACTIVE_ANON] ||
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 10/20 SEQ replacement for anonymous pages
In reply to Rik van RielWe avoid evicting and scanning anonymous pages for the most part, but under some workloads we can end up with most of memory filled with anonymous pages. At that point, we suddenly need to clear the referenced bits on all of memory, which can take ages on very large memory systems.
We can reduce the maximum number of pages that need to be scanned by not taking the referenced state into account when deactivating an anonymous page. After all, every anonymous page starts out referenced, so why check?
If an anonymous page gets referenced again before it reaches the end of the inactive list, we move it back to the active list.
To keep the maximum amount of necessary work reasonable, we scale the active to inactive ratio with the size of memory, using the formula active:inactive ratio = sqrt(memory in GB * 10).
Kswapd CPU use now seems to scale by the amount of pageout bandwidth, instead of by the amount of memory present in the system.
include/linux/mm_inline.h +12 -0
@@ -106,4 +106,16 @@ del_page_from_lru(struct zone *zone, str __dec_zone_state(zone, NR_INACTIVE_ANON + l); } +static inline int inactive_anon_low (struct zone *zone) +{ +unsigned long active, inactive; + + active =zone_page_state (zone,NR_ACTIVE_ANON ); + inactive =zone_page_state (zone,NR_INACTIVE_ANON ); + +if (inactive * zone->inactive_ratio < active) +return 1 ; + +return 0 ; +}#endif
include/linux/mmzone.h +5 -0
@@ -313,6 +313,11 @@ struct zone {*/ int prev_priority; +/* +* The ratio of active to inactive pages. +*/ +unsigned int inactive_ratio; +ZONE_PADDING (_pad2_)/* Rarely used or read-mostly fields */
mm/page_alloc.c +29 -0
@@ -4221,6 +4221,34 @@ void setup_per_zone_pages_min(void)calculate_totalreserve_pages (); } +/** +* setup_per_zone_inactive_ratio - called when min_free_kbytes changes. +* +* The inactive anon list should be small enough that the VM never has to +* do too much work, but large enough that each inactive page has a chance +* to be referenced again before it is swapped out. +* +* The inactive_anon ratio is the ratio of active to inactive anonymous +* pages. Ie. a ratio of 3 means 3:1 or 25% of the anonymous pages are +* on the inactive list. +*/ +void setup_per_zone_inactive_ratio (void ) +{ +struct zone *zone; + +for_each_zone (zone) { +unsigned int gb, ratio; + +/* Zone size in gigabytes */ + gb = zone->present_pages >> (30 -PAGE_SHIFT ); + ratio =int_sqrt (10 * gb); +if (!ratio) + ratio =1 ; + + zone->inactive_ratio = ratio; + } +} +/* * Initialise min_free_kbytes. *
@@ -4258,6 +4286,7 @@ static int __init init_per_zone_pages_mi min_free_kbytes =65536 ;setup_per_zone_pages_min ();setup_per_zone_lowmem_reserve (); +setup_per_zone_inactive_ratio ();return 0 ; }module_init (init_per_zone_pages_min)
mm/vmscan.c +32 -4
@@ -1018,7 +1018,7 @@ static inline int zone_is_near_oom(strucstatic void shrink_active_list (unsigned long nr_pages,struct zone *zone,struct scan_control *sc,int priority,int file) { -unsigned long pgmoved; +unsigned long pgmoved =0 ;int pgdeactivate =0 ;unsigned long pgscanned;LIST_HEAD (l_hold);/* The pages which were snipped off */
@@ -1057,12 +1057,25 @@ static void shrink_active_list(unsignedcond_resched (); page =lru_to_page (&l_hold);list_del (&page->lru); -if (page_referenced (page,0 , sc->mem_cgroup)) - lru =LRU_ACTIVE_ANON ; +if (page_referenced (page,0 , sc->mem_cgroup)) { +if (file) +/* Referenced file pages stay active. */ + lru =LRU_ACTIVE_ANON ; +else +/* Anonymous pages always get deactivated. */ + pgmoved++; + }list_add (&page->lru, &list[lru]); }/* +* Count the referenced anon pages as rotated, to balance pageout +* scan pressure between file and anonymous pages in get_scan_ratio. +*/ +if (!file) + zone->recent_rotated_anon += pgmoved; + +/* * Now put the pages back to the appropriate [file or anon] inactive * and active lists. */
@@ -1144,7 +1157,11 @@ static unsigned long shrink_list(enum lr {int file =is_file_lru (lru); -if (lru ==LRU_ACTIVE_ANON || lru ==LRU_ACTIVE_FILE ) { +if (lru ==LRU_ACTIVE_FILE ) { +shrink_active_list (nr_to_scan, zone, sc, priority, file); +return 0 ; + } +if (lru ==LRU_ACTIVE_ANON &&inactive_anon_low (zone)) {shrink_active_list (nr_to_scan, zone, sc, priority, file);return 0 ; }
@@ -1261,6 +1278,9 @@ static unsigned long shrink_zone(int pri zone, priority, 0, 0); } +if (!inactive_anon_low (zone)) + nr[LRU_ACTIVE_ANON ] =0 ; +while (nr[LRU_ACTIVE_ANON ] || nr[LRU_INACTIVE_ANON ] || nr[LRU_ACTIVE_FILE ] || nr[LRU_INACTIVE_FILE ]) {for_each_lru (l) {
@@ -1565,6 +1585,14 @@ loop_again: priority != DEF_PRIORITY)continue ; +/* +* Do some background aging of the anon list, to give +* pages a chance to be referenced before reclaiming. +*/ +if (inactive_anon_low (zone)) +shrink_active_list (SWAP_CLUSTER_MAX , zone, + &sc, priority,0 ); +if (!zone_watermark_ok (zone, order, zone->pages_high,0 ,0 )) { end_zone = i;
mm/vmstat.c +4 -2
@@ -807,10 +807,12 @@ static void zoneinfo_show_print(struct sseq_printf (m,"\n all_unreclaimable: %u" "\n prev_priority: %i" -"\n start_pfn: %lu" , +"\n start_pfn: %lu" +"\n inactive_ratio: %u" ,zone_is_all_unreclaimable (zone), zone->prev_priority, - zone->zone_start_pfn); + zone->zone_start_pfn, + zone->inactive_ratio);seq_putc (m,'\n' ); }
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 10/20] SEQ replacement for anonymous pages
Hi Rik-san,
Quoted 3 lines
To keep the maximum amount of necessary work reasonable, we scale the active to inactive ratio with the size of memory, using the formula active:inactive ratio =
sqrt(memory in GB * 10).
Great.
why do you think best formula is sqrt(GB*10)?
please tell me if you don't mind.
and i have a bit worry to it works well or not on small systems. because it is indicate 1:1 ratio on less than 100MB memory system. Do you think this viewpoint?
/kosaki
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 10/20] SEQ replacement for anonymous pages
Quoted 8 lines · On Wed, 19 Dec 2007 14:17:53 +0900 KOSAKI Motohiro…
Hi Rik-san,
Quoted 3 lines
To keep the maximum amount of necessary work reasonable, we scale the active to inactive ratio with the size of memory, using the formula active:inactive ratio =
sqrt(memory in GB * 10).why do you think best formula is
sqrt(GB*10)?
please tell me if you don't mind.
On a 1GB system, this leads to a ratio of 3 active anon pages to 1 inactive anon page, and a maximum inactive anon list size of 250MB.
On a 1TB system, this leads to a ratio of 100 active anon pages to 1 inactive anon page, and a maximum inactive anon list size of 10GB.
The numbers in-between looked reasonable :)
Basically the requirement is that the inactive anon list is large enough that pages get a chance to be referenced again, but small enough that the maximum amount of work the VM needs to do is bounded to something reasonable.
Quoted 3 lines
and i have a bit worry to it works well or not on small systems. because it is indicate 1:1 ratio on less than 100MB memory system. Do you think this viewpoint?
A 1:1 ratio simply means that the inactive anon list is the same size as the active anon list. Page replacement should still work fine that way.
Signature · 9 lines
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." - Brian W. Kernighan -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 10/20] SEQ replacement for anonymous pages
Hi Rik-san
Quoted 11 lines
Quoted 6 lines
Quoted 3 lines
To keep the maximum amount of necessary work reasonable, we scale the active to inactive ratio with the size of memory, using the formula active:inactive ratio =
sqrt(memory in GB * 10).why do you think best formula is
sqrt(GB*10)?
please tell me if you don't mind.On a 1GB system, this leads to a ratio of 3 active anon pages to 1 inactive anon page, and a maximum inactive anon list size of 250MB.
Quoted 5 lines
On a 1TB system, this leads to a ratio of 100 active anon pages to 1 inactive anon page, and a maximum inactive anon list size of 10GB.
The numbers in-between looked reasonable :)
thanks for your kind description.
I think it make sense.
and, please add comment liked blow table if you don't mind. for take more intuitive description.
total return max memory value inactive anon ------------------------------------- 10MB 1 5MB 100MB 1 50MB 1GB 3 250MB 10GB 10 0.9GB 100GB 31 3GB 1TB 101 10GB 10TB 320 32GB
Quoted 5 lines
Basically the requirement is that the inactive anon list is large enough that pages get a chance to be referenced again, but small enough that the maximum amount of work the VM needs to do is bounded to something reasonable.
Quoted 7 lines
Quoted 3 lines
and i have a bit worry to it works well or not on small systems. because it is indicate 1:1 ratio on less than 100MB memory system. Do you think this viewpoint?
A 1:1 ratio simply means that the inactive anon list is the same size as the active anon list. Page replacement should still work fine that way.
I'm sold. thanks.
/kosaki
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 11/20 add newly swapped in pages to the inactive list
In reply to Rik van RielSwapin_readahead can read in a lot of data that the processes in memory never need. Adding swap cache pages to the inactive list prevents them from putting too much pressure on the working set.
This has the potential to help the programs that are already in memory, but it could also be a disadvantage to processes that are trying to get swapped in.
In short, this patch needs testing.
mm/swap_state.c +1 -1
@@ -370,7 +370,7 @@ struct page *read_swap_cache_async(swp_e/* * Initiate read into locked page and return. */ -lru_cache_add_active_anon (new_page); +lru_cache_add_anon (new_page);swap_readpage (NULL , new_page);return new_page; }
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 12/20 No Reclaim LRU Infrastructure
In reply to Rik van RielV1 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series
+ define NR_NORECLAIM and LRU_NORECLAIM to avoid errors when not configured.
V1 -> V2:
+ handle review comments -- various typos and errors.
+ extract "putback_all_noreclaim_pages()" into a separate patch and rework as "scan_all_zones_noreclaim_pages().
Infrastructure to manage pages excluded from reclaim--i.e., hidden from vmscan. Based on a patch by Larry Woodman of Red Hat. Reworked to maintain "nonreclaimable" pages on a separate per-zone LRU list, to "hide" them from vmscan. A separate noreclaim pagevec is provided for shrink_active_list() to move nonreclaimable pages to the noreclaim list without over burdening the zone lru_lock.
Pages on the noreclaim list have both PG_noreclaim and PG_lru set. Thus, PG_noreclaim is analogous to and mutually exclusive with PG_active--it specifies which LRU list the page is on.
The noreclaim infrastructure is enabled by a new mm Kconfig option [CONFIG_]NORECLAIM.
A new function 'page_reclaimable(page, vma)' in vmscan.c tests whether or not a page is reclaimable. Subsequent patches will add the various !reclaimable tests. We'll want to keep these tests light-weight for use in shrink_active_list() and, possibly, the fault path.
Notes:
1. for now, use bit 30 in page flags. This restricts the no reclaim infrastructure to 64-bit systems. [The mlock patch, later in this series, uses another of these 64-bit-system-only flags.]
Rationale: 32-bit systems have no free page flags and are less likely to have the large amounts of memory that exhibit the problems this series attempts to solve. [I'm sure someone will disabuse me of this notion.]
Thus, NORECLAIM currently depends on [CONFIG_]64BIT.
2. The pagevec to move pages to the noreclaim list results in another loop at the end of shrink_active_list(). If we ultimately adopt Rik van Riel's split lru approach, I think we'll need to find a way to factor all of these loops into some common code.
3. TODO: Memory Controllers maintain separate active and inactive lists. Need to consider whether they should also maintain a noreclaim list. Also, convert to use Christoph's array of indexed lru variables?
See //TODO note in mm/memcontrol.c re: isolating non-reclaimable pages.
4. TODO: more factoring of lru list handling. But, I want to get this as close to functionally correct as possible before introducing those perturbations.
mm/Kconfig +10 -0
@@ -194,3 +194,13 @@ config NR_QUICK config VIRT_TO_BUS def_bool y depends on !ARCH_NO_VIRT_TO_BUS + +config NORECLAIM + bool "Track non-reclaimable pages (EXPERIMENTAL; 64BIT only)" + depends on EXPERIMENTAL && 64BIT + help + Supports tracking of non-reclaimable pages off the [in]active lists + to avoid excessive reclaim overhead on large memory systems. Pages + may be non-reclaimable because: they are locked into memory, they + are anonymous pages for which no swap space exists, or they are anon + pages that are expensive to unmap [long anon_vma "related vma" list.]
include/linux/page-flags.h +19 -0
@@ -94,6 +94,7 @@/* PG_readahead is only used for file reads; PG_reclaim is only for writes */ #define PG_readahead PG_reclaim/* Reminder to do async read-ahead */ +/* PG_owner_priv_1 users should have descriptive aliases */ #define PG_checked PG_owner_priv_1/* Used by some filesystems */ #define PG_pinned PG_owner_priv_1/* Xen pinned pagetable */
@@ -107,6 +108,8 @@* 63 32 0 */ #define PG_uncached 31/* Page has been mapped as uncached */ + +#define PG_noreclaim 30/* Page is "non-reclaimable" */ #endif /*
@@ -160,6 +163,7 @@ static inline void SetPageUptodate(struc#define SetPageActive (page) set_bit(PG_active, &(page)->flags)#define ClearPageActive (page) clear_bit(PG_active, &(page)->flags)#define __ClearPageActive (page) __clear_bit(PG_active, &(page)->flags) +#define TestClearPageActive (page) test_and_clear_bit(PG_active, &(page)->flags)#define PageSlab (page) test_bit(PG_slab, &(page)->flags)#define __SetPageSlab (page) __set_bit(PG_slab, &(page)->flags)
@@ -261,6 +265,21 @@ static inline void __ClearPageTail(struc#define PageSwapCache (page) 0#endif +#ifdef CONFIG_NORECLAIM +#define PageNoreclaim (page) test_bit(PG_noreclaim, &(page)->flags) +#define SetPageNoreclaim (page) set_bit(PG_noreclaim, &(page)->flags) +#define ClearPageNoreclaim (page) clear_bit(PG_noreclaim, &(page)->flags) +#define __ClearPageNoreclaim (page) __clear_bit(PG_noreclaim, &(page)->flags) +#define TestClearPageNoreclaim (page) test_and_clear_bit(PG_noreclaim, \ + &(page)->flags) +#else +#define PageNoreclaim (page) 0 +#define SetPageNoreclaim (page) +#define ClearPageNoreclaim (page) +#define __ClearPageNoreclaim (page) +#define TestClearPageNoreclaim (page) 0 +#endif +#define PageUncached (page) test_bit(PG_uncached, &(page)->flags)#define SetPageUncached (page) set_bit(PG_uncached, &(page)->flags)#define ClearPageUncached (page) clear_bit(PG_uncached, &(page)->flags)
include/linux/mmzone.h +14 -1
@@ -84,6 +84,11 @@ enum zone_stat_item {NR_ACTIVE_ANON ,/* " " " " " */ NR_INACTIVE_FILE ,/* " " " " " */ NR_ACTIVE_FILE ,/* " " " " " */ +#ifdef CONFIG_NORECLAIM +NR_NORECLAIM ,/* " " " " " */ +#else +NR_NORECLAIM =NR_ACTIVE_FILE ,/* avoid compiler errors in dead code */ +#endifNR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED ,/* pagecache pages mapped into pagetables. only modified from process context */
@@ -123,10 +128,18 @@ enum lru_list {LRU_ACTIVE_ANON =LRU_BASE +LRU_ACTIVE ,LRU_INACTIVE_FILE =LRU_BASE +LRU_FILE ,LRU_ACTIVE_FILE =LRU_BASE +LRU_FILE +LRU_ACTIVE , - NR_LRU_LISTS }; +#ifdef CONFIG_NORECLAIM +LRU_NORECLAIM , +#else +LRU_NORECLAIM =LRU_ACTIVE_FILE ,/* avoid compiler errors in dead code */ +#endif + NR_LRU_LISTS +};#define for_each_lru (l) for (l = 0; l < NR_LRU_LISTS; l++) +#define for_each_reclaimable_lru (l) for (l = 0; l <= LRU_ACTIVE_FILE; l++) +static inline int is_file_lru (enum lru_list l) {BUILD_BUG_ON (LRU_INACTIVE_FILE !=2 ||LRU_ACTIVE_FILE !=3 );
mm/page_alloc.c +3 -0
@@ -248,6 +248,7 @@ static void bad_page(struct page *page)1 << PG_private |1 << PG_locked |1 << PG_active | +1 << PG_noreclaim |1 << PG_dirty |1 << PG_reclaim | 1 << PG_slab |
@@ -482,6 +483,7 @@ static inline int free_pages_check(struc 1 << PG_swapcache | 1 << PG_writeback | 1 << PG_reserved | + 1 << PG_noreclaim | 1 << PG_buddy ))))bad_page (page);if (PageDirty (page))
@@ -629,6 +631,7 @@ static int prep_new_page(struct page *pa1 << PG_private |1 << PG_locked |1 << PG_active | +1 << PG_noreclaim |1 << PG_dirty |1 << PG_slab | 1 << PG_swapcache |
include/linux/mm_inline.h +24 -1
@@ -92,13 +92,36 @@ del_page_from_inactive_file_list(structdel_page_from_lru_list (zone, page,LRU_INACTIVE_FILE ); } +#ifdef CONFIG_NORECLAIM +static inline void +add_page_to_noreclaim_list (struct zone *zone,struct page *page) +{ +add_page_to_lru_list (zone, page,LRU_NORECLAIM ); +} + +static inline void +del_page_from_noreclaim_list (struct zone *zone,struct page *page) +{ +del_page_from_lru_list (zone, page,LRU_NORECLAIM ); +} +#else +static inline void +add_page_to_noreclaim_list (struct zone *zone,struct page *page) { } + +static inline void +del_page_from_noreclaim_list (struct zone *zone,struct page *page) { } +#endif +static inline void del_page_from_lru (struct zone *zone,struct page *page) {enum lru_list l =LRU_INACTIVE_ANON ;list_del (&page->lru); -if (PageActive (page)) { +if (PageNoreclaim (page)) { +__ClearPageNoreclaim (page); + l =LRU_NORECLAIM ; + }else if (PageActive (page)) {__ClearPageActive (page); l =LRU_ACTIVE_ANON ; }
include/linux/swap.h +17 -0
@@ -175,6 +175,13 @@ extern void FASTCALL(lru_cache_add_file(extern void FASTCALL (lru_cache_add_anon (struct page *));extern void FASTCALL (lru_cache_add_active_file (struct page *));extern void FASTCALL (lru_cache_add_active_anon (struct page *)); +extern void FASTCALL (lru_cache_add_active_or_noreclaim (struct page *page, +struct vm_area_struct *vma)); +#ifdef CONFIG_NORECLAIM +extern void FASTCALL (lru_cache_add_noreclaim (struct page *page)); +#else +static inline void lru_cache_add_noreclaim (struct page *page) { } +#endif extern void FASTCALL (activate_page (struct page *));extern void FASTCALL (mark_page_accessed (struct page *));extern void lru_add_drain (void );
@@ -206,6 +213,16 @@ static inline int zone_reclaim(struct zo }#endif +#ifdef CONFIG_NORECLAIM +extern int page_reclaimable (struct page *page,struct vm_area_struct *vma); +#else +static inline int page_reclaimable (struct page *page, +struct vm_area_struct *vma) +{ +return 1 ; +} +#endif +extern int kswapd_run (int nid);#ifdef CONFIG_MMU
include/linux/pagevec.h +5 -0
@@ -27,6 +27,11 @@ void __pagevec_lru_add_file(struct pagevvoid __pagevec_lru_add_active_file (struct pagevec *pvec);void __pagevec_lru_add_anon (struct pagevec *pvec);void __pagevec_lru_add_active_anon (struct pagevec *pvec); +#ifdef CONFIG_NORECLAIM +void __pagevec_lru_add_noreclaim (struct pagevec *pvec); +#else +static inline void __pagevec_lru_add_noreclaim (struct pagevec *pvec) { } +#endif void pagevec_strip (struct pagevec *pvec);void pagevec_swap_free (struct pagevec *pvec); unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping,
mm/swap.c +89 -7
162 lines not on this page · raw message
mm/migrate.c +15 -3
@@ -52,9 +52,18 @@ int migrate_prep(void)return 0 ; } +/* +* move_to_lru() - place @page onto appropriate lru list +* based on preserved page flags: active, noreclaim, none +*/ static inline void move_to_lru (struct page *page) { -if (PageActive (page)) { +if (PageNoreclaim (page)) { +VM_BUG_ON (PageActive (page)); +ClearPageNoreclaim (page); +lru_cache_add_noreclaim (page); + }else if (PageActive (page)) { +VM_BUG_ON (PageNoreclaim (page));/* race ? */ /* * lru_cache_add_active checks that * the PG_active bit is off.
@@ -65,6 +74,7 @@ static inline void move_to_lru(struct paelse lru_cache_add_active_anon (page); }else { +VM_BUG_ON (PageNoreclaim (page));/* race ? */ if (page_file_cache (page))lru_cache_add_file (page);else
@@ -341,8 +351,11 @@ static void migrate_page_copy(struct pagSetPageReferenced (newpage);if (PageUptodate (page))SetPageUptodate (newpage); -if (PageActive (page)) +if (TestClearPageActive (page)) { +VM_BUG_ON (PageNoreclaim (page));SetPageActive (newpage); + }else if (TestClearPageNoreclaim (page)) +SetPageNoreclaim (newpage);if (PageChecked (page))SetPageChecked (newpage);if (PageMappedToDisk (page))
@@ -356,7 +369,6 @@ static void migrate_page_copy(struct pag#ifdef CONFIG_SWAP ClearPageSwapCache (page);#endif -ClearPageActive (page);ClearPagePrivate (page);set_page_private (page,0 ); page->mapping =NULL ;
mm/vmscan.c +100 -15
198 lines not on this page · raw message
mm/mempolicy.c +1 -1
@@ -1912,7 +1912,7 @@ static void gather_stats(struct page *paif (PageSwapCache (page)) md->swapcache++; -if (PageActive (page)) +if (PageActive (page) ||PageNoreclaim (page)) md->active++;if (PageWriteback (page))
mm/memcontrol.c +4 -0
@@ -521,6 +521,10 @@ unsigned long mem_cgroup_isolate_pages(u scan++;list_move (&pc->lru, &pc_list); +//TODO: for now, don't isolate non-reclaimable pages. When/if +// mem controller supports a noreclaim list, we'll need to make +// at least ISOLATE_ACTIVE visible outside of vm_scan and pass +// the 'take_nonreclaimable' flag accordingly. if (__isolate_lru_page (page, mode, file) ==0 ) {list_move (&page->lru, dst); nr_taken++;
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 13/20 Non-reclaimable page statistics
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series
V1 -> V2:
no changes
Report non-reclaimable pages per zone and system wide.
Note: may want to track/report some specific reasons for nonreclaimability for deciding when to splice the noreclaim lists back to the normal lru. That will be tricky, especially in shrink_active_list(), where we'd need someplace to save the per page reason for non-reclaimability until the pages are dumped back onto the noreclaim list from the pagevec.
Note: my tests indicate that NR_NORECLAIM and probably the other LRU stats aren't being maintained properly--especially with large amounts of mlocked memory and the mlock patch in this series installed. Can't be sure of this, as I don't know why the pages are on the noreclaim list. Needs further investigation.
mm/page_alloc.c +15 -1
@@ -1882,12 +1882,20 @@ void show_free_areas(void) } printk("Active_anon:%lu active_file:%lu inactive_anon%lu\n" - " inactive_file:%lu dirty:%lu writeback:%lu unstable:%lu\n" + " inactive_file:%lu" +//TODO: check/adjust line lengths +#ifdef CONFIG_NORECLAIM +" noreclaim:%lu" +#endif +" dirty:%lu writeback:%lu unstable:%lu\n" " free:%lu slab:%lu mapped:%lu pagetables:%lu bounce:%lu\n" ,global_page_state (NR_ACTIVE_ANON ),global_page_state (NR_ACTIVE_FILE ),global_page_state (NR_INACTIVE_ANON ),global_page_state (NR_INACTIVE_FILE ), +#ifdef CONFIG_NORECLAIM +global_page_state (NR_NORECLAIM ), +#endifglobal_page_state (NR_FILE_DIRTY ),global_page_state (NR_WRITEBACK ), global_page_state(NR_UNSTABLE_NFS),
@@ -1914,6 +1922,9 @@ void show_free_areas(void) " inactive_anon:%lukB" " active_file:%lukB" " inactive_file:%lukB" +#ifdef CONFIG_NORECLAIM + " noreclaim:%lukB" +#endif" present:%lukB" " pages_scanned:%lu" " all_unreclaimable? %s"
@@ -1927,6 +1938,9 @@ void show_free_areas(void)K (zone_page_state (zone,NR_INACTIVE_ANON )),K (zone_page_state (zone,NR_ACTIVE_FILE )),K (zone_page_state (zone,NR_INACTIVE_FILE )), +#ifdef CONFIG_NORECLAIM +K (zone_page_state (zone,NR_NORECLAIM )), +#endifK (zone->present_pages), zone->pages_scanned, (zone_is_all_unreclaimable (zone) ?"yes" :"no" )
mm/vmstat.c +3 -0
@@ -690,6 +690,9 @@ static const char * const vmstat_text[]"nr_active_anon" ,"nr_inactive_file" ,"nr_active_file" , +#ifdef CONFIG_NORECLAIM +"nr_noreclaim" , +#endif"nr_anon_pages" ,"nr_mapped" , "nr_file_pages",
drivers/base/node.c +6 -0
@@ -52,6 +52,9 @@ static ssize_t node_read_meminfo(struct "Node %d Inactive(anon): %8lu kB\n" "Node %d Active(file): %8lu kB\n" "Node %d Inactive(file): %8lu kB\n" +#ifdef CONFIG_NORECLAIM + "Node %d Noreclaim: %8lu kB\n" +#endif#ifdef CONFIG_HIGHMEM "Node %d HighTotal: %8lu kB\n" "Node %d HighFree: %8lu kB\n"
@@ -76,6 +79,9 @@ static ssize_t node_read_meminfo(struct nid,node_page_state (nid,NR_INACTIVE_ANON ), nid,node_page_state (nid,NR_ACTIVE_FILE ), nid,node_page_state (nid,NR_INACTIVE_FILE ), +#ifdef CONFIG_NORECLAIM + nid,node_page_state (nid,NR_NORECLAIM ), +#endif #ifdef CONFIG_HIGHMEM nid,K (i.totalhigh), nid, K(i.freehigh),
fs/proc/proc_misc.c +6 -0
@@ -162,6 +162,9 @@ static int meminfo_read_proc(char *page, "Inactive(anon): %8lu kB\n" "Active(file): %8lu kB\n" "Inactive(file): %8lu kB\n" +#ifdef CONFIG_NORECLAIM + "Noreclaim: %8lu kB\n" +#endif#ifdef CONFIG_HIGHMEM "HighTotal: %8lu kB\n" "HighFree: %8lu kB\n"
@@ -194,6 +197,9 @@ static int meminfo_read_proc(char *page,K (global_page_state (NR_INACTIVE_ANON )),K (global_page_state (NR_ACTIVE_FILE )),K (global_page_state (NR_INACTIVE_FILE )), +#ifdef CONFIG_NORECLAIM +K (global_page_state (NR_NORECLAIM )), +#endif #ifdef CONFIG_HIGHMEMK (i.totalhigh), K(i.freehigh),
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 14/20 Scan noreclaim list for reclaimable pages
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series
New in V2
This patch adds a function to scan individual or all zones' noreclaim lists and move any pages that have become reclaimable onto the respective zone's inactive list, where shrink_inactive_list() will deal with them.
This replaces the function to splice the entire noreclaim list onto the active list for rescan by shrink_active_list(). That method had problems with vmstat accounting and complicated '[__]isolate_lru_pages()'. Now, __isolate_lru_page() will never isolate a non-reclaimable page. The only time it should see one is when scanning nearby pages for lumpy reclaim.
TODO: This approach may still need some refinement.
E.g., put back to active list?
include/linux/swap.h +15 -0
@@ -7,6 +7,7 @@#include <linux/list.h> #include <linux/sched.h> #include <linux/memcontrol.h> +#include <linux/node.h> #include <asm/atomic.h> #include <asm/page.h>
@@ -215,12 +216,26 @@ static inline int zone_reclaim(struct zo#ifdef CONFIG_NORECLAIM extern int page_reclaimable (struct page *page,struct vm_area_struct *vma); +extern void scan_zone_noreclaim_pages (struct zone *); +extern void scan_all_zones_noreclaim_pages (void ); +extern unsigned long scan_noreclaim_pages; +extern int scan_noreclaim_handler (struct ctl_table *,int ,struct file *, +void __user *,size_t *,loff_t *); +extern int scan_noreclaim_register_node (struct node *node); +extern void scan_noreclaim_unregister_node (struct node *node);#else static inline int page_reclaimable (struct page *page,struct vm_area_struct *vma) {return 1 ; } +static inline void scan_zone_noreclaim_pages (struct zone *z) { } +static inline void scan_all_zones_noreclaim_pages (void ) { } +static inline int scan_noreclaim_register_node (struct node *node) +{ +return 0 ; +} +static inline void scan_noreclaim_unregister_node (struct node *node) { }#endif extern int kswapd_run (int nid);
mm/vmscan.c +141 -0
151 lines not on this page · raw message
kernel/sysctl.c +10 -0
@@ -1150,6 +1150,16 @@ static struct ctl_table vm_table[] = { .extra2 = &one, },#endif +#ifdef CONFIG_NORECLAIM + { + .ctl_name = CTL_UNNUMBERED, + .procname = "scan_noreclaim_pages", + .data = &scan_noreclaim_pages, + .maxlen = sizeof(scan_noreclaim_pages), + .mode = 0644, + .proc_handler = &scan_noreclaim_handler, + }, +#endif /* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt
drivers/base/node.c +5 -0
@@ -13,6 +13,7 @@#include <linux/nodemask.h> #include <linux/cpu.h> #include <linux/device.h> +#include <linux/swap.h> static struct sysdev_class node_class = {set_kset_name ("node" ),
@@ -162,6 +163,8 @@ int register_node(struct node *node, intsysdev_create_file (&node->sysdev, &attr_meminfo);sysdev_create_file (&node->sysdev, &attr_numastat);sysdev_create_file (&node->sysdev, &attr_distance); + +scan_noreclaim_register_node (node); }return error; }
@@ -180,6 +183,8 @@ void unregister_node(struct node *node)sysdev_remove_file (&node->sysdev, &attr_numastat);sysdev_remove_file (&node->sysdev, &attr_distance); +scan_noreclaim_unregister_node (node); +sysdev_unregister (&node->sysdev); }
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 15/20 ramfs pages are non-reclaimable
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series [no changes]
V1 -> V2:
+ add ramfs pages to this class of non-reclaimable pages by marking ramfs address_space [mapping] as non-reclaimble.
Christoph Lameter pointed out that ram disk pages also clutter the LRU lists. When vmscan finds them dirty and tries to clean them, the ram disk writeback function just redirties the page so that it goes back onto the active list. Round and round she goes...
Define new address_space flag [shares address_space flags member with mapping's gfp mask] to indicate that the address space contains all non-reclaimable pages. This will provide for efficient testing of ramdisk pages in page_reclaimable().
Also provide wrapper functions to set/test the noreclaim state to minimize #ifdefs in ramdisk driver and any other users of this facility.
Set the noreclaim state on address_space structures for new ramdisk inodes. Test the noreclaim state in page_reclaimable() to cull non-reclaimable pages.
Similarly, ramfs pages are non-reclaimable. Set the 'noreclaim' address_space flag for new ramfs inodes.
These changes depend on [CONFIG_]NORECLAIM.
include/linux/pagemap.h +22 -0
@@ -30,6 +30,28 @@ static inline void mapping_set_error(str } } +#ifdef CONFIG_NORECLAIM +#define AS_NORECLAIM (__GFP_BITS_SHIFT + 2)/* e.g., ramdisk, SHM_LOCK */ + +static inline void mapping_set_noreclaim (struct address_space *mapping) +{ +set_bit (AS_NORECLAIM , &mapping->flags); +} + +static inline int mapping_non_reclaimable (struct address_space *mapping) +{ +if (mapping && (mapping->flags &AS_NORECLAIM )) +return 1 ; +return 0 ; +} +#else +static inline void mapping_set_noreclaim (struct address_space *mapping) { } +static inline int mapping_non_reclaimable (struct address_space *mapping) +{ +return 0 ; +} +#endif +static inline gfp_t mapping_gfp_mask (struct address_space * mapping) {return (__force gfp_t )mapping->flags & __GFP_BITS_MASK;
mm/vmscan.c +4 -0
@@ -2241,6 +2241,7 @@ int zone_reclaim(struct zone *zone, gfp_* If !NULL, called from fault path. * * Reasons page might not be reclaimable: +* + page's mapping marked non-reclaimable * TODO - later patches * * TODO: specify locking assumptions
@@ -2250,6 +2251,9 @@ int page_reclaimable(struct page *page,VM_BUG_ON (PageNoreclaim (page)); +if (mapping_non_reclaimable (page_mapping (page))) +return 0 ; +/* TODO: test page [!]reclaimable conditions */ return 1 ;
fs/ramfs/inode.c +1 -0
@@ -61,6 +61,7 @@ struct inode *ramfs_get_inode(struct sup inode->i_mapping->a_ops = &ramfs_aops; inode->i_mapping->backing_dev_info = &ramfs_backing_dev_info;mapping_set_gfp_mask (inode->i_mapping,GFP_HIGHUSER ); +mapping_set_noreclaim (inode->i_mapping); inode->i_atime = inode->i_mtime = inode->i_ctime =CURRENT_TIME ;switch (mode &S_IFMT ) {default :
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 16/20 SHM_LOCKED pages are nonreclaimable
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split LRU series.
+ Use scan_mapping_noreclaim_page() on unlock. See below.
V1 -> V2:
+ modify to use reworked 'scan_all_zones_noreclaim_pages()' See 'TODO' below - still pending.
While working with Nick Piggin's mlock patches, I noticed that shmem segments locked via shmctl(SHM_LOCKED) were not being handled. SHM_LOCKed pages work like ramdisk pages--the writeback function just redirties the page so that it can't be reclaimed. Deal with these using the same approach as for ram disk pages.
Use the AS_NORECLAIM flag to mark address_space of SHM_LOCKed shared memory regions as non-reclaimable. Then these pages will be culled off the normal LRU lists during vmscan.
Add new wrapper function to clear the mapping's noreclaim state when/if shared memory segment is munlocked.
Add 'scan_mapping_noreclaim_page()' to mm/vmscan.c to scan all pages in the shmem segment's mapping [struct address_space] for reclaimability now that they're no longer locked. If so, move them to the appropriate zone lru list.
Changes depend on [CONFIG_]NORECLAIM.
mm/shmem.c +3 -0
@@ -1366,10 +1366,13 @@ int shmem_lock(struct file *file, int loif (!user_shm_lock (inode->i_size, user)) goto out_nomem; info->flags |=VM_LOCKED ; +mapping_set_noreclaim (file->f_mapping); }if (!lock && (info->flags &VM_LOCKED ) && user) {user_shm_unlock (inode->i_size, user); info->flags &= ~VM_LOCKED ; +mapping_clear_noreclaim (file->f_mapping); +scan_mapping_noreclaim_pages (file->f_mapping); } retval =0 ; out_nomem:
include/linux/pagemap.h +8 -2
@@ -38,14 +38,20 @@ static inline void mapping_set_noreclaim set_bit(AS_NORECLAIM, &mapping->flags); } +static inline void mapping_clear_noreclaim (struct address_space *mapping) +{ +clear_bit (AS_NORECLAIM , &mapping->flags); +} +static inline int mapping_non_reclaimable (struct address_space *mapping) { -if (mapping && (mapping->flags &AS_NORECLAIM )) -return 1 ; +if (mapping) +return test_bit (AS_NORECLAIM , &mapping->flags);return 0 ; }#else static inline void mapping_set_noreclaim (struct address_space *mapping) { } +static inline void mapping_clear_noreclaim (struct address_space *mapping) { }static inline int mapping_non_reclaimable (struct address_space *mapping) {return 0 ;
mm/vmscan.c +83 -17
129 lines not on this page · raw message
include/linux/swap.h +4 -0
@@ -218,6 +218,7 @@ static inline int zone_reclaim(struct zoextern int page_reclaimable (struct page *page,struct vm_area_struct *vma);extern void scan_zone_noreclaim_pages (struct zone *);extern void scan_all_zones_noreclaim_pages (void ); +extern void scan_mapping_noreclaim_pages (struct address_space *);extern unsigned long scan_noreclaim_pages;extern int scan_noreclaim_handler (struct ctl_table *,int ,struct file *,void __user *,size_t *,loff_t *);
@@ -231,6 +232,9 @@ static inline int page_reclaimable(struc }static inline void scan_zone_noreclaim_pages (struct zone *z) { }static inline void scan_all_zones_noreclaim_pages (void ) { } +static inline void scan_mapping_noreclaim_pages (struct address_space *mapping) +{ +}static inline int scan_noreclaim_register_node (struct node *node) {return 0 ;
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 17/20 non-reclaimable mlocked pages
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series
+ fix page flags macros for *PageMlocked() when not configured.
+ ensure lru_add_drain_all() runs on all cpus when NORECLIM_MLOCK configured. Was just for NUMA.
V1 -> V2:
+ moved this patch [and related patches] up to right after ramdisk/ramfs and SHM_LOCKed patches.
+ add [back] missing put_page() in putback_lru_page(). This solved page leakage as seen by stats in previous version.
+ fix up munlock_vma_page() to isolate page from lru before calling try_to_unlock(). Think I detected a race here.
+ use TestClearPageMlock() on old page in migrate.c's migrate_page_copy() to clean up old page.
+ live dangerously: remove TestSetPageLocked() in is_mlocked_vma()--should only be called on new pages in the fault path--iff we chose to cull there [later patch].
+ Add PG_mlocked to free_pages_check() etc to detect mlock state mismanagement.
NOTE: temporarily [???] commented out--tripping over it under load. Why?
Rework of a patch by Nick Piggin -- part 1 of 2.
This patch:
1) defines the [CONFIG_]NORECLAIM_MLOCK sub-option and the stub version of the mlock/noreclaim APIs when it's not configured. Depends on [CONFIG_]NORECLAIM.
2) add yet another page flag--PG_mlocked--to indicate that the page is locked for efficient testing in vmscan and, optionally, fault path. This allows early culling of nonreclaimable pages, preventing them from getting to page_referenced()/try_to_unmap(). Also allows separate accounting of mlock'd pages, as Nick's original patch did.
Uses a bit available only to 64-bit systems.
Note: Nick's original mlock patch used a PG_mlocked flag. I had removed this in favor of the PG_noreclaim flag + an mlock_count [new page struct member]. I restored the PG_mlocked flag to eliminate the new count field.
3) add the mlock/noreclaim infrastructure to mm/mlock.c, with internal APIs in mm/internal.h. This is a rework of Nick's original patch to these files, taking into account that mlocked pages are now kept on noreclaim LRU list.
4) update vmscan.c:page_reclaimable() to check PageMlocked() and, if vma passed in, the vm_flags. Note that the vma will only be passed in for new pages in the fault path; and then only if the "cull nonreclaimable pages in fault path" patch is included.
5) add try_to_unlock() to rmap.c to walk a page's rmap and ClearPageMlocked() if no other vmas have it mlocked. Reuses as much of try_to_unmap() as possible. This effectively replaces the use of one of the lru list links as an mlock count. If this mechanism let's pages in mlocked vmas leak through w/o PG_mlocked set [I don't know that it does], we should catch them later in try_to_unmap(). One hopes this will be rare, as it will be relatively expensive.
mm/internal.h and mm/mlock.c changes:
Originally Signed-off-by: Nick Piggin <[email protected]>
mm/Kconfig +14 -0
@@ -204,3 +204,17 @@ config NORECLAIM may be non-reclaimable because: they are locked into memory, they are anonymous pages for which no swap space exists, or they are anon pages that are expensive to unmap [long anon_vma "related vma" list.] + +config NORECLAIM_MLOCK + bool "Exclude mlock'ed pages from reclaim" + depends on NORECLAIM + help + Treats mlock'ed pages as no-reclaimable. Removing these pages from + the LRU [in]active lists avoids the overhead of attempting to reclaim + them. Pages marked non-reclaimable for this reason will become + reclaimable again when the last mlock is removed. + when no swap space exists. Removing these pages from the LRU lists + avoids the overhead of attempting to reclaim them. Pages marked + non-reclaimable for this reason will become reclaimable again when/if + sufficient swap space is added to the system. +
mm/internal.h +54 -0
60 lines not on this page · raw message
mm/mlock.c +225 -13
278 lines not on this page · raw message
mm/vmscan.c +8 -2
@@ -2238,10 +2238,11 @@ int zone_reclaim(struct zone *zone, gfp_* * @page - page to test * @vma - vm area in which page is/will be mapped. May be NULL. -* If !NULL, called from fault path. +* If !NULL, called from fault path for a new page. * * Reasons page might not be reclaimable: -* + page's mapping marked non-reclaimable +* 1) page's mapping marked non-reclaimable +* 2) page is mlock'ed into memory. * TODO - later patches * * TODO: specify locking assumptions
@@ -2254,6 +2255,11 @@ int page_reclaimable(struct page *page,if (mapping_non_reclaimable (page_mapping (page)))return 0 ; +#ifdef CONFIG_NORECLAIM_MLOCK +if (PageMlocked (page) || (vma &&is_mlocked_vma (vma, page))) +return 0 ; +#endif +/* TODO: test page [!]reclaimable conditions */ return 1 ;
include/linux/page-flags.h +21 -2
@@ -110,6 +110,7 @@#define PG_uncached 31/* Page has been mapped as uncached */ #define PG_noreclaim 30/* Page is "non-reclaimable" */ +#define PG_mlocked 29/* Page is vma mlocked */ #endif /*
@@ -163,6 +164,7 @@ static inline void SetPageUptodate(struc#define SetPageActive (page) set_bit(PG_active, &(page)->flags)#define ClearPageActive (page) clear_bit(PG_active, &(page)->flags)#define __ClearPageActive (page) __clear_bit(PG_active, &(page)->flags) +#define TestSetPageActive (page) test_and_set_bit(PG_active, &(page)->flags)#define TestClearPageActive (page) test_and_clear_bit(PG_active, &(page)->flags)#define PageSlab (page) test_bit(PG_slab, &(page)->flags)
@@ -270,8 +272,17 @@ static inline void __ClearPageTail(struc#define SetPageNoreclaim (page) set_bit(PG_noreclaim, &(page)->flags)#define ClearPageNoreclaim (page) clear_bit(PG_noreclaim, &(page)->flags)#define __ClearPageNoreclaim (page) __clear_bit(PG_noreclaim, &(page)->flags) -#define TestClearPageNoreclaim (page) test_and_clear_bit(PG_noreclaim, \ - &(page)->flags) +#define TestClearPageNoreclaim (page) \ + test_and_clear_bit(PG_noreclaim, &(page)->flags) +#ifdef CONFIG_NORECLAIM_MLOCK +#define PageMlocked (page) test_bit(PG_mlocked, &(page)->flags) +#define SetPageMlocked (page) set_bit(PG_mlocked, &(page)->flags) +#define ClearPageMlocked (page) clear_bit(PG_mlocked, &(page)->flags) +#define __ClearPageMlocked (page) __clear_bit(PG_mlocked, &(page)->flags) +#define TestSetPageMlocked (page) test_and_set_bit(PG_mlocked, &(page)->flags) +#define TestClearPageMlocked (page) \ + test_and_clear_bit(PG_mlocked, &(page)->flags) +#endif #else #define PageNoreclaim (page) 0#define SetPageNoreclaim (page)
@@ -279,6 +290,14 @@ static inline void __ClearPageTail(struc#define __ClearPageNoreclaim (page)#define TestClearPageNoreclaim (page) 0#endif +#ifndef CONFIG_NORECLAIM_MLOCK +#define PageMlocked (page) 0 +#define SetPageMlocked (page) +#define ClearPageMlocked (page) +#define __ClearPageMlocked (page) +#define TestSetPageMlocked (page) 0 +#define TestClearPageMlocked (page) 0 +#endif #define PageUncached (page) test_bit(PG_uncached, &(page)->flags)#define SetPageUncached (page) set_bit(PG_uncached, &(page)->flags)
include/linux/rmap.h +12 -0
@@ -112,6 +112,17 @@ unsigned long page_address_in_vma(struct*/ int page_mkclean (struct page *); +#ifdef CONFIG_NORECLAIM_MLOCK +/* +* called in munlock()/munmap() path to check for other vmas holding +* the page mlocked. +*/ +int try_to_unlock (struct page *); +#define TRY_TO_UNLOCK 1 +#else +#define TRY_TO_UNLOCK 0/* for compiler -- dead code elimination */ +#endif +#else /* !CONFIG_MMU */ #define anon_vma_init () do {} while (0)
@@ -135,5 +146,6 @@ static inline int page_mkclean(struct pa#define SWAP_SUCCESS 0#define SWAP_AGAIN 1#define SWAP_FAIL 2 +#define SWAP_MLOCK 3#endif /* _LINUX_RMAP_H */
mm/rmap.c +136 -26
272 lines not on this page · raw message
mm/migrate.c +3 -0
@@ -366,6 +366,9 @@ static void migrate_page_copy(struct pagset_page_dirty (newpage); } +if (TestClearPageMlocked (page)) +SetPageMlocked (newpage); +#ifdef CONFIG_SWAP ClearPageSwapCache (page);#endif
mm/page_alloc.c +9 -1
@@ -255,6 +255,7 @@ static void bad_page(struct page *page)1 << PG_swapcache |1 << PG_writeback |1 << PG_swapbacked | +1 << PG_mlocked | 1 << PG_buddy );set_page_count (page,0 );reset_page_mapcount (page);
@@ -484,6 +485,9 @@ static inline int free_pages_check(struc1 << PG_writeback |1 << PG_reserved |1 << PG_noreclaim | +// TODO: always trip this under heavy workloads. +// Why isn't this being cleared on last unmap/unlock? +// 1 << PG_mlocked | 1 << PG_buddy )))) bad_page(page);if (PageDirty (page))
@@ -638,6 +642,8 @@ static int prep_new_page(struct page *pa 1 << PG_writeback | 1 << PG_reserved | 1 << PG_swapbacked | +//TODO: why hitting this? +// 1 << PG_mlocked | 1 << PG_buddy ))))bad_page (page);
@@ -650,7 +656,9 @@ static int prep_new_page(struct page *pa page->flags &= ~(1 << PG_uptodate |1 << PG_error |1 << PG_readahead |1 << PG_referenced |1 << PG_arch_1 | -1 << PG_owner_priv_1 |1 << PG_mappedtodisk); +1 << PG_owner_priv_1 |1 << PG_mappedtodisk | +//TODO take care of it here, for now. +1 << PG_mlocked );set_page_private (page,0 );set_page_refcounted (page);
mm/swap.c +1 -1
@@ -346,7 +346,7 @@ void lru_add_drain(void)put_cpu (); } -#ifdef CONFIG_NUMA +#if defined(CONFIG_NUMA ) || defined(CONFIG_NORECLAIM_MLOCK )static void lru_add_drain_per_cpu (struct work_struct *dummy) {lru_add_drain ();
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 36 lines · Rik van Riel
Rework of a patch by Nick Piggin -- part 1 of 2.
This patch:
1) defines the [CONFIG_]NORECLAIM_MLOCK sub-option and the stub version of the mlock/noreclaim APIs when it's not configured. Depends on [CONFIG_]NORECLAIM.
2) add yet another page flag--PG_mlocked--to indicate that the page is locked for efficient testing in vmscan and, optionally, fault path. This allows early culling of nonreclaimable pages, preventing them from getting to page_referenced()/try_to_unmap(). Also allows separate accounting of mlock'd pages, as Nick's original patch did.
Uses a bit available only to 64-bit systems.
Note: Nick's original mlock patch used a
PG_mlockedflag. I had removed this in favor of thePG_noreclaimflag + anmlock_count[new page struct member]. I restored thePG_mlockedflag to eliminate the new count field.3) add the mlock/noreclaim infrastructure to
mm/mlock.c, with internal APIs inmm/internal.h. This is a rework of Nick's original patch to these files, taking into account that mlocked pages are now kept on noreclaim LRU list.4) update vmscan.c:page_reclaimable() to check
PageMlocked()and, if vma passed in, thevm_flags. Note that the vma will only be passed in for new pages in the fault path; and then only if the "cull nonreclaimable pages in fault path" patch is included.
Quoted 8 lines
5) add
try_to_unlock()tormap.cto walk a page's rmap andClearPageMlocked()if no other vmas have it mlocked. Reuses as much oftry_to_unmap()as possible. This effectively replaces the use of one of the lru list links as an mlock count. If this mechanism let's pages in mlocked vmas leak through w/oPG_mlockedset [I don't know that it does], we should catch them later intry_to_unmap(). One hopes this will be rare, as it will be relatively expensive.
Hmm, I still don't know (or forgot) why you don't just use the old scheme of having an mlock count in the LRU bit, and removing the mlocked page from the LRU completely.
These mlocked pages don't need to be on a non-reclaimable list, because we can find them again via the ptes when they become unlocked, and there is no point background scanning them, because they're always going to be locked while they're mlocked.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 6 lines · On Wed, 19 Dec 2007 11:56:48 +1100 Nick Piggin <[email protected]> wrote:
Quoted 4 lines · Rik van Riel
Rework of a patch by Nick Piggin -- part 1 of 2.
This patch:
Quoted 7 lines
Quoted 3 lines
1) defines the [CONFIG_]NORECLAIM_MLOCK sub-option and the stub version of the mlock/noreclaim APIs when it's not configured. Depends on [CONFIG_]NORECLAIM.
Hmm, I still don't know (or forgot) why you don't just use the old scheme of having an mlock count in the LRU bit, and removing the mlocked page from the LRU completely.
How do we detect those pages reliably in the lumpy reclaim code?
Quoted 4 lines
These mlocked pages don't need to be on a non-reclaimable list, because we can find them again via the ptes when they become unlocked, and there is no point background scanning them, because they're always going to be locked while they're mlocked.
Agreed.
The main reason I sent out these patches now is that I just wanted to get some comments from other upstream developers.
I have gotten distracted by other work so much that I spent most of my time forward porting the patch set, and not enough time working with the rest of the upstream community to get the code moving forward.
To be honest, I have only briefly looked at the non-reclaimable code. I would be more than happy to merge any improvements to that code.
Signature · 9 lines
"Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it." - Brian W. Kernighan -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Peter Zijlstra
maintainerRe: [patch 17/20] non-reclaimable mlocked pages
Quoted 13 lines · Rik van Riel
Quoted 9 lines · On Wed, 19 Dec 2007 11:56:48 +1100 Nick Piggin <[email protected]> wrote:
Quoted 7 lines · Rik van Riel
Rework of a patch by Nick Piggin -- part 1 of 2.
This patch:
1) defines the [CONFIG_]NORECLAIM_MLOCK sub-option and the stub version of the mlock/noreclaim APIs when it's not configured. Depends on [CONFIG_]NORECLAIM.
Quoted 10 lines
Quoted 3 lines
Hmm, I still don't know (or forgot) why you don't just use the old scheme of having an mlock count in the LRU bit, and removing the mlocked page from the LRU completely.
How do we detect those pages reliably in the lumpy reclaim code?
Quoted 4 lines
These mlocked pages don't need to be on a non-reclaimable list, because we can find them again via the ptes when they become unlocked, and there is no point background scanning them, because they're always going to be locked while they're mlocked.
I thought Lee had patches that moved pages with long rmap chains (both anon and file) out onto the non-reclaim list, for those a slow background scan does make sense.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 3 lines · On Wed, 19 Dec 2007 15:24:07 +0100 Peter Zijlstra <[email protected]> wrote:
I thought Lee had patches that moved pages with long rmap chains (both anon and file) out onto the non-reclaim list, for those a slow background scan does make sense.
I suspect we won't be needing that code. The SEQ replacement for swap backed pages might reduce the number of pages that need to be scanned to a reasonable number.
Remember, steady states are not a big problem with the current VM. It's the sudden burst of scanning that happens when the VM decides that it should start swapping (and every anonymous page is referenced) that kills large systems.
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 7 lines · Rik van Riel
Quoted 3 lines · On Wed, 19 Dec 2007 15:24:07 +0100 Peter Zijlstra <[email protected]> wrote:
I thought Lee had patches that moved pages with long rmap chains (both anon and file) out onto the non-reclaim list, for those a slow background scan does make sense.
Quoted 8 lines
I suspect we won't be needing that code. The SEQ replacement for swap backed pages might reduce the number of pages that need to be scanned to a reasonable number.
Remember, steady states are not a big problem with the current VM. It's the sudden burst of scanning that happens when the VM decides that it should start swapping (and every anonymous page is referenced) that kills large systems.
Yes, I still have the patch [for long anon_vma lists--not for excessively mapped file, yet] and I'm keeping it up to date and tested. I do see softlockups on the anon_vma and i_mmap_locks under stress, even with the reader/writer lock patches. I'll be trying the workloads on Rik's latest patches to see if they address these lockups.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
In reply to Rik van RielQuoted 13 lines · Rik van Riel
Quoted 9 lines · On Wed, 19 Dec 2007 11:56:48 +1100 Nick Piggin <[email protected]> wrote:
Quoted 7 lines · Rik van Riel
Rework of a patch by Nick Piggin -- part 1 of 2.
This patch:
1) defines the [CONFIG_]NORECLAIM_MLOCK sub-option and the stub version of the mlock/noreclaim APIs when it's not configured. Depends on [CONFIG_]NORECLAIM.
Quoted 5 lines
Quoted 3 lines
Hmm, I still don't know (or forgot) why you don't just use the old scheme of having an mlock count in the LRU bit, and removing the mlocked page from the LRU completely.
How do we detect those pages reliably in the lumpy reclaim code?
I wanted to try to treat nonreclaimable pages, whatever the reason, uniformly. Lumpy reclaim wasn't there when I started on this, but we've been able to handle them. I was more interested in page migration. The act of isolating the page from the LRU [under zone lru_lock] arbitrates between racing tasks attempting to migrate the same page. That and we keep the isolated pages on a list using the LRU links. We can't migrate pages that we can't successfully isolate from the LRU list. Nick had addressed this by putting mlocked pages back on the lru for migration. Seemed like unnecessary work to me. And, as I recall, this lost the mlock count and it had to be reestablished over time.
Quoted 7 lines
Quoted 5 lines
These mlocked pages don't need to be on a non-reclaimable list, because we can find them again via the ptes when they become unlocked, and there is no point background scanning them, because they're always going to be locked while they're mlocked.
Agreed.
I also agree they don't need to be scanned. And, altho' having them on an LRU list has other uses, I suppose that having mlocked pages on the noreclaim list could be considered "clutter" if we did want to scan the noreclaim list for other types of non-reclaimable pages that might have become reclaimable.
Lee
Quoted 13 lines
The main reason I sent out these patches now is that I just wanted to get some comments from other upstream developers.
I have gotten distracted by other work so much that I spent most of my time forward porting the patch set, and not enough time working with the rest of the upstream community to get the code moving forward.
To be honest, I have only briefly looked at the non-reclaimable code. I would be more than happy to merge any improvements to that code.
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 10 lines · On Wed, 19 Dec 2007 11:04:26 -0500 Lee Schermerhorn <[email protected]>…
Quoted 8 lines · Rik van Riel
Quoted 3 lines · On Wed, 19 Dec 2007 11:56:48 +1100 Nick Piggin <[email protected]> wrote:
Hmm, I still don't know (or forgot) why you don't just use the old scheme of having an mlock count in the LRU bit, and removing the mlocked page from the LRU completely.
How do we detect those pages reliably in the lumpy reclaim code?
Quoted 7 lines
I wanted to try to treat nonreclaimable pages, whatever the reason, uniformly. Lumpy reclaim wasn't there when I started on this, but we've been able to handle them. I was more interested in page migration. The act of isolating the page from the LRU [under zone
lru_lock] arbitrates between racing tasks attempting to migrate the same page. That and we keep the isolated pages on a list using the LRU links. We can't migrate pages that we can't successfully isolate from the LRU list.
Good point.
Lets keep the nonreclaimable pages on a list, so we can keep the migration code (and other code) consistent.
We can deal with lazily moving pages back to the nonreclaim list if we find that, after one munlock, there are other mlocking users of that page.
Quoted 5 lines
I also agree they don't need to be scanned. And, altho' having them on an LRU list has other uses, I suppose that having mlocked pages on the noreclaim list could be considered "clutter" if we did want to scan the noreclaim list for other types of non-reclaimable pages that might have become reclaimable.
If we ever want to do that, we can always introduce separate lists for those pages.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 21 lines · Rik van Riel
On Wed, 19 Dec 2007 11:04:26 -0500
Quoted 10 lines · Lee Schermerhorn
Quoted 8 lines · Rik van Riel
On Wed, 19 Dec 2007 11:56:48 +1100
Quoted 3 lines · Nick Piggin
Hmm, I still don't know (or forgot) why you don't just use the old scheme of having an mlock count in the LRU bit, and removing the mlocked page from the LRU completely.
How do we detect those pages reliably in the lumpy reclaim code?
Quoted 7 lines
I wanted to try to treat nonreclaimable pages, whatever the reason, uniformly. Lumpy reclaim wasn't there when I started on this, but we've been able to handle them. I was more interested in page migration. The act of isolating the page from the LRU [under zone
lru_lock] arbitrates between racing tasks attempting to migrate the same page. That and we keep the isolated pages on a list using the LRU links. We can't migrate pages that we can't successfully isolate from the LRU list.
Quoted 1 line
Good point.
Ah: that's what it was. The migration code got harder with my mlock code (although I did have something that should have worked in theory, it involved a few steps).
I don't have a particular problem with putting mlock pages on the slow scan lists, although if you have huge mlocked data sets, you could effectively speed up slow scan list scanning by orders of magnitude by avoiding the mlocked pages.
I won't push it now, but I might see if I can rewrite it one day :)
BTW. if you have any workloads that are limited by page reclaim, especially unmapped file backed pagecache reclaim, then I have some stright-line-speedup patches which you might find interesting (I can send them if you'd like to test).
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 4 lines · On Fri, 21 Dec 2007 21:52:19 +1100 Nick Piggin <[email protected]> wrote:
BTW. if you have any workloads that are limited by page reclaim, especially unmapped file backed pagecache reclaim, then I have some stright-line-speedup patches which you might find interesting (I can send them if you'd like to test).
I am definately interested in those.
The current upstream VM seems to be fairly good in steady state, with the largest problems happening when the system switches states (eg. from reclaiming page cache to swapping), but any speedups in the steady state are good too.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 9 lines · Rik van Riel
On Fri, 21 Dec 2007 21:52:19 +1100
Quoted 4 lines · Nick Piggin
BTW. if you have any workloads that are limited by page reclaim, especially unmapped file backed pagecache reclaim, then I have some stright-line-speedup patches which you might find interesting (I can send them if you'd like to test).
I am definately interested in those.
Sorry it took a few days...
So I'm testing throughput for the full pagecache lifecycle, insertion to reclaim. Reading from a sparse file much bigger than memory.
On my 2 socket, 8 core Opteron setup:
Single dd from a single file:
vanilla: 687.01MB/s
patched: 1037.17MB/s (151%)
8 dds from a single file:
vanilla: 1458.04MB/s
patched: 5898.65MB/s (405%)
Not sure how well that translates to real world workloads, but it might help somewhere. Admittedly some of the patches are pretty complex...
Anyway, have a good christmas and new year :)
Thanks,
Nick
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 3 lines · On Sun, 23 Dec 2007 23:22:08 +1100 Nick Piggin <[email protected]> wrote:
Not sure how well that translates to real world workloads, but it might help somewhere. Admittedly some of the patches are pretty complex...
I like your patch series.
They are completely orthogonal to my patches though, so I won't tie them together by merging your series into mine :)
It looks like the majority of your patches could go into -mm right away.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
In reply to Rik van RielQuoted 12 lines · Rik van Riel
On Wed, 19 Dec 2007 11:56:48 +1100
Quoted 9 lines · Nick Piggin
Quoted 7 lines · Rik van Riel
Rework of a patch by Nick Piggin -- part 1 of 2.
This patch:
1) defines the [CONFIG_]NORECLAIM_MLOCK sub-option and the stub version of the mlock/noreclaim APIs when it's not configured. Depends on [CONFIG_]NORECLAIM.
Quoted 5 lines
Quoted 3 lines
Hmm, I still don't know (or forgot) why you don't just use the old scheme of having an mlock count in the LRU bit, and removing the mlocked page from the LRU completely.
How do we detect those pages reliably in the lumpy reclaim code?
They will have PG_mlocked set.
Quoted 10 lines
Quoted 4 lines
These mlocked pages don't need to be on a non-reclaimable list, because we can find them again via the ptes when they become unlocked, and there is no point background scanning them, because they're always going to be locked while they're mlocked.
Agreed.
The main reason I sent out these patches now is that I just wanted to get some comments from other upstream developers.
Quoted 8 lines
I have gotten distracted by other work so much that I spent most of my time forward porting the patch set, and not enough time working with the rest of the upstream community to get the code moving forward.
To be honest, I have only briefly looked at the non-reclaimable code. I would be more than happy to merge any improvements to that code.
I haven't had too much time to look at it either, although it does seem like a reasonable idea.
However the mlock code could be completely separate from the slow scan pages (and not be on those LRUs at all).
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
In reply to Nick PigginQuoted 4 lines · Nick Piggin
These mlocked pages don't need to be on a non-reclaimable list, because we can find them again via the ptes when they become unlocked, and there is no point background scanning them, because they're always going to be locked while they're mlocked.
But there is something to be said for having a consistent scheme. Here we already introduce address space flags for one kind of unreclaimability. Isnt it possible to come up with a way to categorize pages that works (mostly) the same way for all types of pages with reclaim issues?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 8 lines · On Wed, 19 Dec 2007 23:19:00 -0800 (PST) Christoph Lameter <[email protected]>…
Quoted 4 lines · Nick Piggin
These mlocked pages don't need to be on a non-reclaimable list, because we can find them again via the ptes when they become unlocked, and there is no point background scanning them, because they're always going to be locked while they're mlocked.
But there is something to be said for having a consistent scheme.
The code as called from .c files should indeed be consistent.
However, since we never need to scan the non-reclaimable list, we could use the inline functions in the .h files to have an mlock count instead of a .lru list head in the non-reclaimable pages.
At least, I think so. I'm going to have to think about the details a lot more. I have no idea yet if there will be any impact from batching the pages on pagevecs, vs. an atomic mlock count...
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 17/20] non-reclaimable mlocked pages
Quoted 19 lines · Rik van Riel
Quoted 8 lines · On Wed, 19 Dec 2007 23:19:00 -0800 (PST) Christoph Lameter <[email protected]>…
Quoted 4 lines · Nick Piggin
These mlocked pages don't need to be on a non-reclaimable list, because we can find them again via the ptes when they become unlocked, and there is no point background scanning them, because they're always going to be locked while they're mlocked.
But there is something to be said for having a consistent scheme.
The code as called from .c files should indeed be consistent.
However, since we never need to scan the non-reclaimable list, we could use the inline functions in the .h files to have an mlock count instead of a .lru list head in the non-reclaimable pages.
Quoted 4 lines
At least, I think so. I'm going to have to think about the details a lot more. I have no idea yet if there will be any impact from batching the pages on pagevecs, vs. an atomic mlock count...
Just remember that page migration can migrate mlocked pages today, and we'll want to continue to support this. Migration uses the lru locks to manage the pages selected for migration and uses isolation from lru list under zone lru_lock to arbitrate any racing migrations. Unless mlocked pages are kept on an lru-like list, we'll need to put them back during migration--possibly losing the mlock count or needing to save it somewhere over [possibly lazy] migration.
Note that having mlocked pages on the noreclaim lru list doesn't mean we have to scan them to reclaim them. It does however mean that we'd have to skip over them to scan other types of non-reclaimable pages. What other types? In my current implementation, SHM_LOCKed pages and ramdisk/fs pages aren't mlocked. Rather, they are culled to the noreclaim list in vmscan when we detect a page on the [in]active list that is in a nonreclaimable mapping. This required minimal changes to recognize and cull these nonreclaimable pages. Currently PG_mlocked is used only for pages mapped into a VM_LOCKED vma. Since the noreclaim list exists for the other types [and there could be more], it's little additional work to keep mlocked pages there as well. This makes them play nice with migration.
Lee
PATCH 18/20 mlock vma pages under mmap_sem held for read
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series [no change]
+ fix function return types [void -> int] to fix build when not configured.
New in V2.
We need to hold the mmap_sem for write to initiatate mlock()/munlock() because we may need to merge/split vmas. However, this can lead to very long lock hold times attempting to fault in a large memory region
to mlock it into memory. This can hold off other faults against the
mm [multithreaded tasks] and other scans of the mm, such as via /proc. To alleviate this, downgrade the mmap_sem to read mode during the population of the region for locking. This is especially the case if we need to reclaim memory to lock down the region. We [probably?] don't need to do this for unlocking as all of the pages should be resident--they're already mlocked.
Now, the caller's of the mlock functions [mlock_fixup() and mlock_vma_pages_range()] expect the mmap_sem to be returned in write mode. Changing all callers appears to be way too much effort at this point. So, restore write mode before returning. Note that this opens a window where the mmap list could change in a multithreaded process. So, at least for mlock_fixup(), where we could be called in a loop over multiple vmas, we check that a vma still exists at the start address and that vma still covers the page range [start,end). If not, we return an error, -EAGAIN, and let the caller deal with it.
Return -EAGAIN from mlock_vma_pages_range() function and mlock_fixup() if the vma at 'start' disappears or changes so that the page range [start,end) is no longer contained in the vma. Again, let the caller deal with it. Looks like only sys_remap_file_pages() [via mmap_region()] should actually care.
With this patch, I no longer see processes like ps(1) blocked for seconds or minutes at a time waiting for a large [multiple gigabyte] region to be locked down.
mm/mlock.c +56 -1
@@ -215,6 +215,37 @@ int __mlock_vma_pages_range(struct vm_ar return ret; } +/** +* mlock_vma_pages_range +* @vma - vm area to mlock into memory +* @start - start address in @vma of range to mlock, +* @end - end address in @vma of range +* +* Called with current->mm->mmap_sem held write locked. Downgrade to read +* for faulting in pages. This can take a looong time for large segments. +* +* We need to restore the mmap_sem to write locked because our callers' +* callers expect this. However, because the mmap could have changed +* [in a multi-threaded process], we need to recheck. +*/ +int mlock_vma_pages_range (struct vm_area_struct *vma, +unsigned long start,unsigned long end) +{ +struct mm_struct *mm = vma->vm_mm; + +downgrade_write (&mm->mmap_sem); +__mlock_vma_pages_range (vma, start, end,1 ); + +up_read (&mm->mmap_sem); +/* vma can change or disappear */ +down_write (&mm->mmap_sem); + vma =find_vma (mm, start); +/* non-NULL vma must contain @start, but need to check @end */ +if (!vma || end > vma->vm_end) +return -EAGAIN ; +return 0 ; +} +#else /* CONFIG_NORECLAIM_MLOCK */ /*
@@ -281,14 +312,38 @@ success: mm->locked_vm += nr_pages;/* -* vm_flags is protected by the mmap_sem held in write mode. +* vm_flags is protected by the mmap_sem held for write. * It's okay if try_to_unmap_one unmaps a page just after we * set VM_LOCKED, __mlock_vma_pages_range will bring it back. */ vma->vm_flags = newflags; +/* +* mmap_sem is currently held for write. If we're locking pages, +* downgrade the write lock to a read lock so that other faults, +* mmap scans, ... while we fault in all pages. +*/ +if (lock) +downgrade_write (&mm->mmap_sem); +__mlock_vma_pages_range (vma, start, end, lock); +if (lock) { +/* +* Need to reacquire mmap sem in write mode, as our callers +* expect this. We have no support for atomically upgrading +* a sem to write, so we need to check for changes while sem +* is unlocked. +*/ +up_read (&mm->mmap_sem); +/* vma can change or disappear */ +down_write (&mm->mmap_sem); + *prev =find_vma (mm, start); +/* non-NULL *prev must contain @start, but need to check @end */ +if (!(*prev) || end > (*prev)->vm_end) + ret = -EAGAIN ; + } + out:if (ret == -ENOMEM ) ret = -EAGAIN ;
mm/internal.h +8 -11
@@ -53,24 +53,21 @@ extern int __mlock_vma_pages_range(struc/* * mlock all pages in this vma range. For mmap()/mremap()/... */ -static inline void mlock_vma_pages_range (struct vm_area_struct *vma, -unsigned long start,unsigned long end) -{ -__mlock_vma_pages_range (vma, start, end,1 ); -} +extern int mlock_vma_pages_range (struct vm_area_struct *vma, +unsigned long start,unsigned long end);/* * munlock range of pages. For munmap() and exit(). * Always called to operate on a full vma that is being unmapped. */ -static inline void munlock_vma_pages_range (struct vm_area_struct *vma, +static inline int munlock_vma_pages_range (struct vm_area_struct *vma,unsigned long start,unsigned long end) {// TODO: verify my assumption. Should we just drop the start/end args? VM_BUG_ON (start != vma->vm_start || end != vma->vm_end); vma->vm_flags &= ~VM_LOCKED ;/* try_to_unlock() needs this */ -__mlock_vma_pages_range (vma, start, end,0 ); +return __mlock_vma_pages_range (vma, start, end,0 ); }extern void clear_page_mlock (struct page *page);
@@ -82,10 +79,10 @@ static inline int is_mlocked_vma(struct }static inline void clear_page_mlock (struct page *page) { }static inline void mlock_vma_page (struct page *page) { } -static inline void mlock_vma_pages_range (struct vm_area_struct *vma, -unsigned long start,unsigned long end) { } -static inline void munlock_vma_pages_range (struct vm_area_struct *vma, -unsigned long start,unsigned long end) { } +static inline int mlock_vma_pages_range (struct vm_area_struct *vma, +unsigned long start,unsigned long end) {return 0 ; } +static inline int munlock_vma_pages_range (struct vm_area_struct *vma, +unsigned long start,unsigned long end) {return 0 ; }#endif /* CONFIG_NORECLAIM_MLOCK */
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 19/20 handle mlocked pages during map/unmap and truncate
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series [no changes]
V1 -> V2:
+ modified mmap.c:mmap_region() to return error if mlock_vma_pages_range() does. This can only occur if the vma gets removed/changed while
we're switching mmap_sem lock modes. Most callers don't care, but
sys_remap_file_pages() appears to.
Rework of Nick Piggins's "mm: move mlocked pages off the LRU" patch -- part 2 0f 2.
Remove mlocked pages from the LRU using "NoReclaim infrastructure" during mmap()/mremap(). Try to move back to normal LRU lists on munmap() when last locked mapping removed. Removed PageMlocked() status when page truncated from file.
Originally Signed-off-by: Nick Piggin <[email protected]>
mm/mmap.c +37 -5
@@ -32,6 +32,8 @@#include <asm/tlb.h> #include <asm/mmu_context.h> +#include "internal.h" +#ifndef arch_mmap_check#define arch_mmap_check (addr, len, flags) (0)#endif
@@ -1211,9 +1213,13 @@ out:vm_stat_account (mm, vm_flags, file, len >>PAGE_SHIFT );if (vm_flags &VM_LOCKED ) { mm->locked_vm += len >>PAGE_SHIFT ; -make_pages_present (addr, addr + len); - } -if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK )) +/* +* makes pages present; downgrades, drops, requires mmap_sem +*/ + error =mlock_vma_pages_range (vma, addr, addr + len); +if (error) +return error;/* vma gone! */ + }else if ((flags &MAP_POPULATE ) && !(flags &MAP_NONBLOCK ))make_pages_present (addr, addr + len);return addr;
@@ -1892,6 +1898,19 @@ int do_munmap(struct mm_struct *mm, unsi vma = prev? prev->vm_next: mm->mmap;/* +* unlock any mlock()ed ranges before detaching vmas +*/ +if (mm->locked_vm) { +struct vm_area_struct *tmp = vma; +while (tmp && tmp->vm_start < end) { +if (tmp->vm_flags &VM_LOCKED ) +munlock_vma_pages_range (tmp, + tmp->vm_start, tmp->vm_end); + tmp = tmp->vm_next; + } + } + +/* * Remove the vma's, and unmap the actual pages */ detach_vmas_to_be_unmapped (mm, vma, prev, end);
@@ -2024,7 +2043,7 @@ out: mm->total_vm += len >>PAGE_SHIFT ;if (flags &VM_LOCKED ) { mm->locked_vm += len >>PAGE_SHIFT ; -make_pages_present (addr, addr + len); +mlock_vma_pages_range (vma, addr, addr + len); }return addr; }
@@ -2035,13 +2054,26 @@ EXPORT_SYMBOL(do_brk);void exit_mmap (struct mm_struct *mm) {struct mmu_gather *tlb; -struct vm_area_struct *vma = mm->mmap; +struct vm_area_struct *vma;unsigned long nr_accounted =0 ;unsigned long end;/* mm's last user has gone, and its about to be pulled down */ arch_exit_mmap (mm); +if (mm->locked_vm) { + vma = mm->mmap; +while (vma) { +if (vma->vm_flags &VM_LOCKED ) +munlock_vma_pages_range (vma, + vma->vm_start, vma->vm_end); + vma = vma->vm_next; + } + } + + vma = mm->mmap; + +lru_add_drain ();flush_cache_mm (mm); tlb =tlb_gather_mmu (mm,1 );
mm/mremap.c +5 -3
@@ -23,6 +23,8 @@#include <asm/cacheflush.h> #include <asm/tlbflush.h> +#include "internal.h" +static pmd_t *get_old_pmd (struct mm_struct *mm,unsigned long addr) {pgd_t *pgd;
@@ -232,8 +234,8 @@ static unsigned long move_vma(struct vm_if (vm_flags &VM_LOCKED ) { mm->locked_vm += new_len >>PAGE_SHIFT ;if (new_len > old_len) -make_pages_present (new_addr + old_len, - new_addr + new_len); +mlock_vma_pages_range (vma, new_addr + old_len, + new_addr + new_len); }return new_addr;
@@ -373,7 +375,7 @@ unsigned long do_mremap(unsigned long advm_stat_account (mm, vma->vm_flags, vma->vm_file, pages);if (vma->vm_flags &VM_LOCKED ) { mm->locked_vm += pages; -make_pages_present (addr + old_len, +mlock_vma_pages_range (vma, addr + old_len, addr + new_len); } ret = addr;
mm/vmscan.c +4 -0
@@ -534,6 +534,10 @@ static unsigned long shrink_page_list(st goto activate_locked;case SWAP_AGAIN : goto keep_locked; +case SWAP_MLOCK : +ClearPageActive (page); +SetPageNoreclaim (page); + goto keep_locked;/* to noreclaim list */ case SWAP_SUCCESS : ;/* try to free the page below */ }
mm/filemap.c +9 -1
@@ -2504,8 +2504,16 @@ generic_file_direct_IO(int rw, struct kiif (rw ==WRITE ) { write_len =iov_length (iov, nr_segs); end = (offset + write_len -1 ) >>PAGE_CACHE_SHIFT ; -if (mapping_mapped (mapping)) +if (mapping_mapped (mapping)) { +/* +* Calling unmap_mapping_range like this is wrong, +* because it can lead to mlocked pages being +* discarded (this is true even before the Noreclaim +* mlock work). direct-IO vs pagecache is a load of +* junk anyway, so who cares. +*/ unmap_mapping_range (mapping, offset, write_len,0 ); + } } retval =filemap_write_and_wait (mapping);
mm/truncate.c +4 -0
@@ -18,6 +18,7 @@#include <linux/task_io_accounting_ops.h> #include <linux/buffer_head.h> /* grr. try_to_release_page, do_invalidatepage */ +#include "internal.h" /**
@@ -104,6 +105,7 @@ truncate_complete_page(struct address_spdo_invalidatepage (page,0 );remove_from_page_cache (page); +clear_page_mlock (page);ClearPageUptodate (page);ClearPageMappedToDisk (page);page_cache_release (page);/* pagecache ref */
@@ -128,6 +130,7 @@ invalidate_complete_page(struct address_if (PagePrivate (page) && !try_to_release_page (page,0 ))return 0 ; +clear_page_mlock (page); ret =remove_mapping (mapping, page);return ret;
@@ -354,6 +357,7 @@ invalidate_complete_page2(struct addressif (PageDirty (page)) goto failed; +clear_page_mlock (page);BUG_ON (PagePrivate (page));__remove_from_page_cache (page);write_unlock_irq (&mapping->tree_lock);
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 20/20 account mlocked pages
In reply to Rik van RielV2 -> V3:
+ rebase to 23-mm1 atop RvR's split lru series
+ fix definitions of NR_MLOCK to fix build errors when not configured.
V1 -> V2:
+ new in V2 -- pulled in & reworked from Nick's previous series
From: Nick Piggin <[email protected]>
To: Linux Memory Management <[email protected]>
Cc: Nick Piggin <[email protected]>, Andrew Morton <[email protected]>
Subject: [patch 4/4] mm: account mlocked pages
Date: Mon, 12 Mar 2007 07:39:14 +0100 (CET)
Add NR_MLOCK zone page state, which provides a (conservative) count of mlocked pages (actually, the number of mlocked pages moved off the LRU).
Reworked by lts to fit in with the modified mlock page support in the Reclaim Scalability series. I don't know whether we'll want to keep these stats in the long run, but during testing of this series, I find them useful.
drivers/base/node.c +6 -0
@@ -55,6 +55,9 @@ static ssize_t node_read_meminfo(struct "Node %d Inactive(file): %8lu kB\n" #ifdef CONFIG_NORECLAIM "Node %d Noreclaim: %8lu kB\n" +#ifdef CONFIG_NORECLAIM_MLOCK + "Node %d Mlocked: %8lu kB\n" +#endif #endif#ifdef CONFIG_HIGHMEM "Node %d HighTotal: %8lu kB\n"
@@ -82,6 +85,9 @@ static ssize_t node_read_meminfo(struct nid, node_page_state(nid, NR_INACTIVE_FILE),#ifdef CONFIG_NORECLAIM nid, node_page_state(nid, NR_NORECLAIM), +#ifdef CONFIG_NORECLAIM_MLOCK + nid, K(node_page_state(nid, NR_MLOCK)), +#endif #endif #ifdef CONFIG_HIGHMEM nid, K(i.totalhigh),
fs/proc/proc_misc.c +6 -0
@@ -160,6 +160,9 @@ static int meminfo_read_proc(char *page, "Inactive(file): %8lu kB\n" #ifdef CONFIG_NORECLAIM "Noreclaim: %8lu kB\n" +#ifdef CONFIG_NORECLAIM_MLOCK + "Mlocked: %8lu kB\n" +#endif #endif#ifdef CONFIG_HIGHMEM "HighTotal: %8lu kB\n"
@@ -195,6 +198,9 @@ static int meminfo_read_proc(char *page, K(global_page_state(NR_INACTIVE_FILE)),#ifdef CONFIG_NORECLAIM K(global_page_state(NR_NORECLAIM)), +#ifdef CONFIG_NORECLAIM_MLOCK + K(global_page_state(NR_MLOCK)), +#endif #endif #ifdef CONFIG_HIGHMEM K(i.totalhigh),
include/linux/mmzone.h +5 -1
@@ -86,8 +86,12 @@ enum zone_stat_item { NR_ACTIVE_FILE, /* " " " " " */#ifdef CONFIG_NORECLAIM NR_NORECLAIM, /* " " " " " */ +#ifdef CONFIG_NORECLAIM_MLOCK + NR_MLOCK, /* mlock()ed pages found and moved off LRU */ +#endif #else -NR_NORECLAIM =NR_ACTIVE_FILE ,/* avoid compiler errors in dead code */ +NR_NORECLAIM =NR_ACTIVE_FILE ,/* avoid compiler errors in dead code */ +NR_MLOCK =NR_ACTIVE_FILE ,/* avoid compiler errors... */ #endifNR_ANON_PAGES ,/* Mapped anonymous pages */ NR_FILE_MAPPED, /* pagecache pages mapped into pagetables.
mm/mlock.c +27 -11
@@ -75,11 +75,11 @@ void clear_page_mlock(struct page *page) {BUG_ON (!PageLocked (page)); -if (likely (!PageMlocked (page))) -return ; -ClearPageMlocked (page); -if (!isolate_lru_page (page)) -putback_lru_page (page); +if (unlikely (TestClearPageMlocked (page))) { +dec_zone_page_state (page,NR_MLOCK ); +if (!isolate_lru_page (page)) +putback_lru_page (page); + } }/*
@@ -90,8 +90,11 @@ void mlock_vma_page(struct page *page) {BUG_ON (!PageLocked (page)); -if (!TestSetPageMlocked (page) && !isolate_lru_page (page)) +if (!TestSetPageMlocked (page)) { +inc_zone_page_state (page,NR_MLOCK ); +if (!isolate_lru_page (page))putback_lru_page (page); + } }/*
@@ -113,10 +116,22 @@ static void munlock_vma_page(struct page {BUG_ON (!PageLocked (page)); -if (TestClearPageMlocked (page) && !isolate_lru_page (page)) { -if (try_to_unlock (page) ==SWAP_MLOCK ) -SetPageMlocked (page);/* still VM_LOCKED */ -putback_lru_page (page); +if (TestClearPageMlocked (page)) { +dec_zone_page_state (page,NR_MLOCK ); +if (!isolate_lru_page (page)) { +if (try_to_unlock (page) ==SWAP_MLOCK ) { +SetPageMlocked (page);/* still VM_LOCKED */ +inc_zone_page_state (page,NR_MLOCK ); + } +putback_lru_page (page); + } +/* +* Else we lost the race. let try_to_unmap() deal with it. +* At least we get the page state and mlock stats right. +* However, page is still on the noreclaim list. We'll fix +* that up when the page is eventually freed or we scan the +* noreclaim list. +*/ } }
@@ -133,7 +148,8 @@ int is_mlocked_vma(struct vm_area_structif (likely (!(vma->vm_flags &VM_LOCKED )))return 0 ; -SetPageMlocked (page); +if (!TestSetPageMlocked (page)) +inc_zone_page_state (page,NR_MLOCK );return 1 ; }
mm/migrate.c +8 -1
@@ -371,8 +371,15 @@ static void migrate_page_copy(struct pagset_page_dirty (newpage); } -if (TestClearPageMlocked (page)) +if (TestClearPageMlocked (page)) { +unsigned long flags; + +local_irq_save (flags); +__dec_zone_page_state (page,NR_MLOCK );SetPageMlocked (newpage); +__inc_zone_page_state (newpage,NR_MLOCK ); +local_irq_restore (flags); + }#ifdef CONFIG_SWAP ClearPageSwapCache (page);
Signature · 7 lines
All Rights Reversed -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 5 lines · Rik van Riel
On large memory systems, the VM can spend way too much time scanning through pages that it cannot (or should not) evict from memory. Not only does it use up CPU time, but it also provokes lock contention and can leave large systems under memory presure in a catatonic state.
Hi, Rik,
I remember you mentioning that by large memory systems you mean systems with at-least 128GB, does this definition still hold?
Quoted 8 lines
This patch series improves VM scalability by:
1) making the locking a little more scalable
2) putting filesystem backed, swap backed and non-reclaimable pages onto their own LRUs, so the system only scans the pages that it can/should evict from memory
Quoted 8 lines
3) switching to SEQ replacement for the anonymous LRUs, so the number of pages that need to be scanned when the system starts swapping is bound to a reasonable number
The noreclaim patches come verbatim from Lee Schermerhorn and Nick Piggin. I have not taken a detailed look at them yet and all I have done is fix the rejects against the latest -mm kernel.
Is there a consolidate patch available, it makes it easier to test.
Quoted 4 lines
I am posting this series now because I would like to get more feedback, while I am studying and improving the noreclaim patches myself.
What kind of tests show the problem? I'll try and review and test the code.
Signature · 10 lines
Warm Regards, Balbir Singh Linux Technology Center IBM, ISTL -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · On Sun, 23 Dec 2007 01:57:32 +0530 Balbir Singh <[email protected]>…
Quoted 4 lines · Rik van Riel
On large memory systems, the VM can spend way too much time scanning through pages that it cannot (or should not) evict from memory. Not only does it use up CPU time, but it also provokes lock contention and can leave large systems under memory presure in a catatonic state.
I remember you mentioning that by large memory systems you mean systems with at-least 128GB, does this definition still hold?
It depends on the workload. Certain test cases can wedge the VM with as little as 16GB of RAM. Other workloads cause trouble at 32 or 64GB, with the system sometimes hanging for several minutes, all the CPUs in the pageout code and no actual swap IO.
On systems of 128GB and more, we have seen systems hang in the pageout code overnight, without deciding what to swap out.
Quoted 12 lines
Quoted 12 lines
This patch series improves VM scalability by:
1) making the locking a little more scalable
2) putting filesystem backed, swap backed and non-reclaimable pages onto their own LRUs, so the system only scans the pages that it can/should evict from memory
3) switching to SEQ replacement for the anonymous LRUs, so the number of pages that need to be scanned when the system starts swapping is bound to a reasonable number
Quoted 5 lines
Quoted 3 lines
The noreclaim patches come verbatim from Lee Schermerhorn and Nick Piggin. I have not taken a detailed look at them yet and all I have done is fix the rejects against the latest -mm kernel.
Is there a consolidate patch available, it makes it easier to test.
I will make a big patch available with the next version. I have to upgrade my patch set to newer noreclaim patches from Lee and add a few small cleanups elsewhere.
Quoted 5 lines
Quoted 3 lines
I am posting this series now because I would like to get more feedback, while I am studying and improving the noreclaim patches myself.
What kind of tests show the problem? I'll try and review and test the code.
The easiest test possible simply allocates a ton of memory and then touches it all. Enough memory that the system needs to go into swap.
Once memory is full, you will see the VM scan like mad, with a big CPU spike (clearing the referenced bits off all pages) before it starts swapping out anything. That big CPU spike should be gone or greatly reduced with my patches.
On really huge systems, that big CPU spike can be enough for one CPU to spend so much time in the VM that all the other CPUs join it, and the system goes under in a big lock contention fest.
Besides, even single threadedly clearing the referenced bits on 1TB worth of memory can't result in acceptable latencies :)
In the real world, users with large JVMs on their servers, which sometimes go a little into swap, can trigger this system. All of the CPUs end up scanning the active list, and all pages have the referenced bit set. Even if the system eventually recovers, it might as well have been dead.
Going into swap a little should only take a little bit of time.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 7 lines · Rik van Riel
Quoted 5 lines · On Sun, 23 Dec 2007 01:57:32 +0530 Balbir Singh <[email protected]>…
Quoted 4 lines · Rik van Riel
On large memory systems, the VM can spend way too much time scanning through pages that it cannot (or should not) evict from memory. Not only does it use up CPU time, but it also provokes lock contention and can leave large systems under memory presure in a catatonic state.
Quoted 8 lines
Quoted 2 lines
I remember you mentioning that by large memory systems you mean systems with at-least 128GB, does this definition still hold?
It depends on the workload. Certain test cases can wedge the VM with as little as 16GB of RAM. Other workloads cause trouble at 32 or 64GB, with the system sometimes hanging for several minutes, all the CPUs in the pageout code and no actual swap IO.
Interesting, I have not run into it so far. But I have smaller machines, typically 4-8GB.
Quoted 15 lines
On systems of 128GB and more, we have seen systems hang in the pageout code overnight, without deciding what to swap out.
Quoted 12 lines
Quoted 12 lines
This patch series improves VM scalability by:
1) making the locking a little more scalable
2) putting filesystem backed, swap backed and non-reclaimable pages onto their own LRUs, so the system only scans the pages that it can/should evict from memory
3) switching to SEQ replacement for the anonymous LRUs, so the number of pages that need to be scanned when the system starts swapping is bound to a reasonable number
Quoted 9 lines
Quoted 4 lines
Quoted 3 lines
The noreclaim patches come verbatim from Lee Schermerhorn and Nick Piggin. I have not taken a detailed look at them yet and all I have done is fix the rejects against the latest -mm kernel.
Is there a consolidate patch available, it makes it easier to test.
I will make a big patch available with the next version. I have to upgrade my patch set to newer noreclaim patches from Lee and add a few small cleanups elsewhere.
That would be nice. I'll try and help out by testing the patches and running them
Quoted 21 lines
Quoted 4 lines
Quoted 3 lines
I am posting this series now because I would like to get more feedback, while I am studying and improving the noreclaim patches myself.
What kind of tests show the problem? I'll try and review and test the code.
The easiest test possible simply allocates a ton of memory and then touches it all. Enough memory that the system needs to go into swap.
Once memory is full, you will see the VM scan like mad, with a big CPU spike (clearing the referenced bits off all pages) before it starts swapping out anything. That big CPU spike should be gone or greatly reduced with my patches.
On really huge systems, that big CPU spike can be enough for one CPU to spend so much time in the VM that all the other CPUs join it, and the system goes under in a big lock contention fest.
Besides, even single threadedly clearing the referenced bits on 1TB worth of memory can't result in acceptable latencies :)
Quoted 8 lines
In the real world, users with large JVMs on their servers, which sometimes go a little into swap, can trigger this system. All of the CPUs end up scanning the active list, and all pages have the referenced bit set. Even if the system eventually recovers, it might as well have been dead.
Going into swap a little should only take a little bit of time.
Very fascinating, so we need to scale better with larger memory. I suspect part of the answer will lie with using large/huge pages.
Signature · 10 lines
Warm Regards, Balbir Singh Linux Technology Center IBM, ISTL -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 8 lines · On Mon, 24 Dec 2007 04:29:36 +0530 Balbir Singh <[email protected]>…
Quoted 6 lines · Rik van Riel
In the real world, users with large JVMs on their servers, which sometimes go a little into swap, can trigger this system. All of the CPUs end up scanning the active list, and all pages have the referenced bit set. Even if the system eventually recovers, it might as well have been dead.
Quoted 4 lines
Quoted 1 line
Going into swap a little should only take a little bit of time.
Very fascinating, so we need to scale better with larger memory. I suspect part of the answer will lie with using large/huge pages.
Linus vetoed going to a larger soft page size, with good reason.
Just look at how much the 64kB page size on PPC64 sucks for most workloads - it works for PPC64 because people buy PPC64 monster systems for the kinds of monster workloads that work well with a large page size, but it definately isn't general purpose.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Quoted 15 lines · Rik van Riel
Quoted 8 lines · On Mon, 24 Dec 2007 04:29:36 +0530 Balbir Singh <[email protected]>…
Quoted 6 lines · Rik van Riel
In the real world, users with large JVMs on their servers, which sometimes go a little into swap, can trigger this system. All of the CPUs end up scanning the active list, and all pages have the referenced bit set. Even if the system eventually recovers, it might as well have been dead.
Quoted 4 lines
Quoted 1 line
Going into swap a little should only take a little bit of time.
Very fascinating, so we need to scale better with larger memory. I suspect part of the answer will lie with using large/huge pages.
Quoted 6 lines
Linus vetoed going to a larger soft page size, with good reason.
Just look at how much the 64kB page size on PPC64 sucks for most workloads - it works for PPC64 because people buy PPC64 monster systems for the kinds of monster workloads that work well with a large page size, but it definately isn't general purpose.
Indeed, machines already exist with >> 1TB of RAM, so even going to 1MB pages leaves these machines in trouble. Going to big pages a few years ago would have pushed the problem back a few years, but now we need real fixes.
Signature · 7 lines
Mathematics is the supreme nostalgia of our time. -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>