diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2008-08-12 18:52:53 -0400 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2008-08-12 03:52:53 -0400 |
commit | 71a3f4edc11b9dd7af28d003acbbd33496003da1 (patch) | |
tree | b727812682ca9f30169496a30a1e51620f53c7c9 /drivers/lguest/page_tables.c | |
parent | 912985dce45ef18fcdd9f5439fef054e0e22302a (diff) |
lguest: use get_user_pages_fast() instead of get_user_pages()
Using a simple page table thrashing program I measure a slight
improvement. The program creates five processes. Each touches 1000
pages then schedules the next process. We repeat this 1000 times. As
lguest only caches 4 cr3 values, this rebuilds a lot of shadow page
tables requiring virt->phys mappings.
Before: 5.93 seconds
After: 5.40 seconds
(Counts of slow vs fastpath in this usage are 6092 and 2852462 respectively.)
And more importantly for lguest, the code is simpler.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Diffstat (limited to 'drivers/lguest/page_tables.c')
-rw-r--r-- | drivers/lguest/page_tables.c | 25 |
1 files changed, 9 insertions, 16 deletions
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index d93500f24fbb..81d0c6053447 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c | |||
@@ -108,9 +108,8 @@ static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr) | |||
108 | } | 108 | } |
109 | /*:*/ | 109 | /*:*/ |
110 | 110 | ||
111 | /*M:014 get_pfn is slow; it takes the mmap sem and calls get_user_pages. We | 111 | /*M:014 get_pfn is slow: we could probably try to grab batches of pages here as |
112 | * could probably try to grab batches of pages here as an optimization | 112 | * an optimization (ie. pre-faulting). :*/ |
113 | * (ie. pre-faulting). :*/ | ||
114 | 113 | ||
115 | /*H:350 This routine takes a page number given by the Guest and converts it to | 114 | /*H:350 This routine takes a page number given by the Guest and converts it to |
116 | * an actual, physical page number. It can fail for several reasons: the | 115 | * an actual, physical page number. It can fail for several reasons: the |
@@ -123,19 +122,13 @@ static unsigned long gpte_addr(pgd_t gpgd, unsigned long vaddr) | |||
123 | static unsigned long get_pfn(unsigned long virtpfn, int write) | 122 | static unsigned long get_pfn(unsigned long virtpfn, int write) |
124 | { | 123 | { |
125 | struct page *page; | 124 | struct page *page; |
126 | /* This value indicates failure. */ | ||
127 | unsigned long ret = -1UL; | ||
128 | 125 | ||
129 | /* get_user_pages() is a complex interface: it gets the "struct | 126 | /* gup me one page at this address please! */ |
130 | * vm_area_struct" and "struct page" assocated with a range of pages. | 127 | if (get_user_pages_fast(virtpfn << PAGE_SHIFT, 1, write, &page) == 1) |
131 | * It also needs the task's mmap_sem held, and is not very quick. | 128 | return page_to_pfn(page); |
132 | * It returns the number of pages it got. */ | 129 | |
133 | down_read(¤t->mm->mmap_sem); | 130 | /* This value indicates failure. */ |
134 | if (get_user_pages(current, current->mm, virtpfn << PAGE_SHIFT, | 131 | return -1UL; |
135 | 1, write, 1, &page, NULL) == 1) | ||
136 | ret = page_to_pfn(page); | ||
137 | up_read(¤t->mm->mmap_sem); | ||
138 | return ret; | ||
139 | } | 132 | } |
140 | 133 | ||
141 | /*H:340 Converting a Guest page table entry to a shadow (ie. real) page table | 134 | /*H:340 Converting a Guest page table entry to a shadow (ie. real) page table |
@@ -174,7 +167,7 @@ static pte_t gpte_to_spte(struct lg_cpu *cpu, pte_t gpte, int write) | |||
174 | /*H:460 And to complete the chain, release_pte() looks like this: */ | 167 | /*H:460 And to complete the chain, release_pte() looks like this: */ |
175 | static void release_pte(pte_t pte) | 168 | static void release_pte(pte_t pte) |
176 | { | 169 | { |
177 | /* Remember that get_user_pages() took a reference to the page, in | 170 | /* Remember that get_user_pages_fast() took a reference to the page, in |
178 | * get_pfn()? We have to put it back now. */ | 171 | * get_pfn()? We have to put it back now. */ |
179 | if (pte_flags(pte) & _PAGE_PRESENT) | 172 | if (pte_flags(pte) & _PAGE_PRESENT) |
180 | put_page(pfn_to_page(pte_pfn(pte))); | 173 | put_page(pfn_to_page(pte_pfn(pte))); |