[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH] Global virq for low memory situations



>>> On 23.02.12 at 20:59, Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx> wrote:
> @@ -300,6 +301,87 @@ static unsigned long init_node_heap(int 
>      return needed;
>  }
>  
> +/* Default to 64 MiB */
> +#define DEFAULT_LOW_MEM_VIRQ_MIB    64
> +#define MAX_LOW_MEM_VIRQ_MIB        1024
> +
> +static unsigned long long __read_mostly opt_low_mem_virq = 
> +                                        (DEFAULT_LOW_MEM_VIRQ_MIB << 20);
> +size_param("low_mem_virq_limit", opt_low_mem_virq);
> +
> +/* Thresholds to control hysteresis. In pages */
> +/* When memory grows above this threshold, reset hysteresis.
> + * -1 initially to not reset until at least one virq issued. */
> +static unsigned long low_mem_virq_high      = -1UL;
> +/* Threshold at which we issue virq */
> +static unsigned long low_mem_virq_th        = 0;
> +/* Original threshold after all checks completed */
> +static unsigned long low_mem_virq_orig      = 0;
> +/* Order for current threshold */
> +static unsigned int  low_mem_virq_th_order  = 0;
> +
> +/* Perform bootstrapping checks and set bounds */
> +static void setup_low_mem_virq(void)

__init

> +{
> +    unsigned int order;
> +    unsigned long long threshold;
> +
> +    /* Dom0 has already been allocated by now. So check we won't 
> +     * be complaining immediately with whatever's left of the heap. */
> +    threshold = min(opt_low_mem_virq, (unsigned long long)
> +                          (total_avail_pages << PAGE_SHIFT));

The cast needs to be on total_avail_pages, not the result of the
shift. Also, unsigned long long is the wrong type (paddr_t was
invented for this very purpose).

Further, the initial threshold should clearly be *below* the currently
available amount (e.g. at half of it).

> +
> +    /* Then, cap to some predefined maximum */
> +    threshold = min(threshold, (unsigned long long)
> +                          (MAX_LOW_MEM_VIRQ_MIB << 20));

Same here wrt the cast.

> +
> +    /* Threshold bytes -> pages */
> +    low_mem_virq_th = threshold >> PAGE_SHIFT;
> +
> +    /* Next, round the threshold down to the next order */
> +    order = get_order_from_pages(low_mem_virq_th);
> +    if ( (1 << order) > low_mem_virq_th ) 
> +        order--;
> +
> +    /* Set bounds, ready to go */
> +    low_mem_virq_th = low_mem_virq_orig = 1 << order;

1UL << ...

> +    low_mem_virq_th_order = order;
> +
> +    printk("Current low memory virq threshold set at 0x%lx pages.\n",

"Initial ..."

> +            low_mem_virq_th);
> +}
> +
> +static void check_low_mem_virq(void)
> +{
> +    if ( total_avail_pages <= low_mem_virq_th )
> +    {
> +        send_global_virq(VIRQ_ENOMEM);
> +
> +        /* Update thresholds. Next warning will be when we drop below
> +         * next order. However, we wait until we grow beyond one
> +         * order above us to complain again at the current order */
> +        low_mem_virq_high   = 1 << (low_mem_virq_th_order + 1);

1UL << ...

> +        if ( low_mem_virq_th_order > 0 )
> +            low_mem_virq_th_order--;
> +        low_mem_virq_th     = 1 << low_mem_virq_th_order;

Same here.

> +        return;
> +    }
> +
> +    if ( total_avail_pages >= low_mem_virq_high )
> +    {
> +        /* Reset hysteresis. Bring threshold up one order.
> +         * If we are back where originally set, set high
> +         * threshold to -1 to avoid further growth of 
> +         * virq threshold. */
> +        low_mem_virq_th_order++;
> +        low_mem_virq_th = 1 << low_mem_virq_th_order;

And here.

> +        if ( low_mem_virq_th == low_mem_virq_orig )
> +            low_mem_virq_high = -1UL;
> +        else
> +            low_mem_virq_high = 1 << (low_mem_virq_th_order + 2);

And here.

> +    }
> +}
> +
>  /* Allocate 2^@order contiguous pages. */
>  static struct page_info *alloc_heap_pages(
>      unsigned int zone_lo, unsigned int zone_hi,
> @@ -420,6 +502,8 @@ static struct page_info *alloc_heap_page
>      total_avail_pages -= request;
>      ASSERT(total_avail_pages >= 0);
>  
> +    check_low_mem_virq();
> +
>      if ( d != NULL )
>          d->last_alloc_node = node;
>  
> @@ -1022,6 +1106,10 @@ void __init scrub_heap_pages(void)
>      }
>  
>      printk("done.\n");
> +
> +    /* Now that the heap is initialized, run checks and set bounds
> +     * for the low mem virq algorithm. */
> +    setup_low_mem_virq();
>  }
>  
>  
> diff -r dd69d9b1aee9 -r da02cb8485de xen/include/public/xen.h
> --- a/xen/include/public/xen.h
> +++ b/xen/include/public/xen.h
> @@ -157,6 +157,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
>  #define VIRQ_PCPU_STATE 9  /* G. (DOM0) PCPU state changed                   
> */
>  #define VIRQ_MEM_EVENT  10 /* G. (DOM0) A memory event has occured           
> */
>  #define VIRQ_XC_RESERVED 11 /* G. Reserved for XenClient                     
> */
> +#define VIRQ_ENOMEM     12 /* G. (DOM0) Dangerously low on heap memory       
> */

Either the default threshold ought to be *much* lower (say 64k), or
the "dangerously" here is completely misleading.

>  
>  /* Architecture-specific VIRQ definitions. */
>  #define VIRQ_ARCH_0    16

Given that this new vIRQ ought to be handled in user space, do you
have an implementation ready to contribute as well?

Jan

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.