|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 2/2] xen: spread page scrubbing across all idle CPU
On 10/06/14 13:18, Bob Liu wrote:
> Because of page scrubbing, it's very slow to destroy a domain with large
> memory.
> It takes around 10 minutes when destroy a guest of nearly 1 TB of memory.
>
> Besides the CPU running 'xl destory', this patch try to accelerate the
> scrubbing
destroy
> time by using all idle CPUs to do the scrubbing work in parallel.
>
> Compared with other approaches, this way has a minimum effect to the whole
> system. The disadvantage is if all CPUs are not idle, the scrubbing time can't
> be reduced.
>
> On a 60 CPUs system, the 'xl destroy' time of a 30G guest reduced from 15s to
> 8s.
>
> Signed-off-by: Bob Liu <bob.liu@xxxxxxxxxx>
> ---
> xen/arch/x86/domain.c | 1 +
> xen/common/domain.c | 4 +++
> xen/common/page_alloc.c | 73
> +++++++++++++++++++++++++++++++++++++++++++++--
> xen/include/xen/mm.h | 2 ++
> 4 files changed, 78 insertions(+), 2 deletions(-)
>
> diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
> index 6fddd4c..ffa9b91 100644
> --- a/xen/arch/x86/domain.c
> +++ b/xen/arch/x86/domain.c
> @@ -116,6 +116,7 @@ static void idle_loop(void)
> {
> if ( cpu_is_offline(smp_processor_id()) )
> play_dead();
> + scrub_free_pages(0);
> (*pm_idle)();
> do_tasklet();
> do_softirq();
> diff --git a/xen/common/domain.c b/xen/common/domain.c
> index 4291e29..7a8c6bf 100644
> --- a/xen/common/domain.c
> +++ b/xen/common/domain.c
> @@ -593,6 +593,10 @@ int domain_kill(struct domain *d)
> BUG_ON(rc != -EAGAIN);
> break;
> }
> +
> + tasklet_init(&global_scrub_tasklet, scrub_free_pages, 1);
> + tasklet_schedule_on_cpu(&global_scrub_tasklet, smp_processor_id());
> +
Doesn't this result in re-init()ing the global scrub tasklet if
domain_kill() is called on two domains at the same time?
> for_each_vcpu ( d, v )
> unmap_vcpu_info(v);
> d->is_dying = DOMDYING_dead;
> diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
> index 56826b4..d51926d 100644
> --- a/xen/common/page_alloc.c
> +++ b/xen/common/page_alloc.c
> @@ -79,6 +79,14 @@ PAGE_LIST_HEAD(page_offlined_list);
> /* Broken page list, protected by heap_lock. */
> PAGE_LIST_HEAD(page_broken_list);
>
> +/* Global scrub page list, protected by scrub_lock */
> +PAGE_LIST_HEAD(global_scrub_list);
> +DEFINE_SPINLOCK(scrub_lock);
> +struct tasklet global_scrub_tasklet;
> +
> +DEFINE_PER_CPU(struct page_list_head, scrub_list);
> +DEFINE_PER_CPU(struct page_list_head, scrubbed_list);
> +
> /*************************
> * BOOT-TIME ALLOCATOR
> */
> @@ -1569,9 +1577,13 @@ void free_domheap_pages(struct page_info *pg, unsigned
> int order)
> * domain has died we assume responsibility for erasure.
> */
> if ( unlikely(d->is_dying) )
> + {
> + spin_lock(&scrub_lock);
> for ( i = 0; i < (1 << order); i++ )
> - scrub_one_page(&pg[i]);
> -
> + page_list_add_tail(&pg[i], &global_scrub_list);
> + spin_unlock(&scrub_lock);
> + goto out;
> + }
> free_heap_pages(pg, order);
> }
> else if ( unlikely(d == dom_cow) )
> @@ -1588,6 +1600,7 @@ void free_domheap_pages(struct page_info *pg, unsigned
> int order)
> drop_dom_ref = 0;
> }
>
> +out:
> if ( drop_dom_ref )
> put_domain(d);
> }
> @@ -1680,6 +1693,62 @@ void scrub_one_page(struct page_info *pg)
> unmap_domain_page(p);
> }
>
> +#define SCRUB_BATCH 1024
> +void scrub_free_pages(unsigned long is_tasklet)
> +{
> + struct page_info *pg;
> + unsigned int i, cpu, empty = 0;
bool_t empty.
cpu can be initialised when declared.
> +
> + cpu = smp_processor_id();
> + do
> + {
> + if ( page_list_empty(&this_cpu(scrub_list)) )
Repeatedly using this_cpu() is bad, due to the hidden RELOC_HIDE.
Instead, use something like this:
struct *page_list_head this_scrub_list = &this_cpu(scrub_list)
> + {
> + /* Delist a batch of pages from global scrub list */
> + spin_lock(&scrub_lock);
> + for( i = 0; i < SCRUB_BATCH; i++ )
> + {
> + pg = page_list_remove_head(&global_scrub_list);
> + if ( !pg )
> + {
> + empty = 1;
> + break;
> + }
> + page_list_add_tail(pg, &this_cpu(scrub_list));
> + }
> + spin_unlock(&scrub_lock);
> + }
> +
> + /* Scrub percpu list */
> + while ( !page_list_empty(&this_cpu(scrub_list)) )
> + {
> + pg = page_list_remove_head(&this_cpu(scrub_list));
> + ASSERT(pg);
> + scrub_one_page(pg);
> + page_list_add_tail(pg, &this_cpu(scrubbed_list));
> + }
> +
> + /* Free percpu scrubbed list */
> + if ( !page_list_empty(&this_cpu(scrubbed_list)) )
> + {
> + spin_lock(&heap_lock);
> + while ( !page_list_empty(&this_cpu(scrubbed_list)) )
> + {
> + pg = page_list_remove_head(&this_cpu(scrubbed_list));
> + __free_heap_pages(pg, 0);
> + }
> + spin_unlock(&heap_lock);
> + }
> +
> + /* Global list is empty */
> + if (empty)
Spaces inside brackets.
~Andrew
> + return;
> + } while ( !softirq_pending(cpu) );
> +
> + if( is_tasklet )
> + tasklet_schedule_on_cpu(&global_scrub_tasklet, cpu);
> +}
> +
> static void dump_heap(unsigned char key)
> {
> s_time_t now = NOW();
> diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
> index b183189..29821c4 100644
> --- a/xen/include/xen/mm.h
> +++ b/xen/include/xen/mm.h
> @@ -78,6 +78,8 @@ int query_page_offline(unsigned long mfn, uint32_t *status);
> unsigned long total_free_pages(void);
>
> void scrub_heap_pages(void);
> +void scrub_free_pages(unsigned long is_tasklet);
> +extern struct tasklet global_scrub_tasklet;
>
> int assign_pages(
> struct domain *d,
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |