[Lguest] [PATCH 1/1][V2] Least Recently Used pgdirs
Rusty Russell
rusty at rustcorp.com.au
Mon Aug 20 14:36:38 EST 2007
On Sun, 2007-08-19 at 13:08 -0500, Jason Yeh wrote:
> hi all,
>
> This is the update to the previous patch I send under the same title.
> The main difference between the two versions are:
> 1. flush_user_mapping() no longer always flush the current
> pgdir. It takes an a struct pgdir * parameter and flush the
> pgdir.
>
> 2. The Least Recently Used list is updated only when the pgdir
> is about to be used.
>
> 3. Formatting changes.
>
> I also measured the time it takes to compile a kernel with "-j 4" flag
> under the Guest. I am not sure if it is the best way to measure
> the impact of the patch. If you have better idea, please let me know.
> The average of five runs with the patch is:
> real 9m26.849s
> user 7m13.130s
> sys 2m11.330s
>
> without the patch, the number looks like:
> real 9m46.572s
> user 7m33.140s
> sys 2m11.260s
>
> Suggestions/comments are welcomed.
+51 lines (+1% lines) for 3% improvement? Sold!
Except you seem to have increased the number of pgdirs to 5, so
benchmark results don't really count:
+ if (lg->num_pgdirs > PGDIR_MAX) {
This should be ==.
Also, I think you mis-understood my recommendation. I was saying that
find_pgdir_from_list should probably move the pgdir to the front, not
alloc_newpgdir().
Also build doesn't need to be -j4, that's overkill for a UP box.
Your patch was still line-wrapped. Perhaps you need to use an
attachment?
Other minor things:
1) I prefer "MAX_PGDIRS" to PGDIR_MAX (the latter suggests pgdir is a
counter or something).
> + /* pgdir LRU
> + * Newest pgdir is added to the head of the list.
> + * pgdir_list is the tail of the list */
> + struct list_head pgdir_list;
> + struct pgdir *pgdir_cur;
> + unsigned int num_pgdirs;
Comment needs more meat, I think. How about:
/* We keep up to MAX_PGDIRS page tables for each guest: latest-used is
* moved to the head and we discard from the tail (ie. LRU). */
> -static unsigned int find_pgdir(struct lguest *lg, unsigned long pgtable)
> +static struct pgdir * find_pgdir_from_list(struct lguest *lg, unsigned
> long pgtable)
No space between the "struct pgdir *" and the "find_pgdir". Not sure it
needs to be renamed, either?
> +/* Helper to allocate new pgdir */
> +struct pgdir * alloc_newpgdir(void)
static? Also, alloc_newpgdir is redundant: alloc_pgdir?
> -static unsigned int new_pgdir(struct lguest *lg,
> +static struct pgdir * new_pgdir(struct lguest *lg,
"static struct pgdir *new_pgdir()".
> * top-level pgdir). This happens on almost every context switch. */
> void guest_new_pagetable(struct lguest *lg, unsigned long pgtable)
> {
> - int newpgdir, repin = 0;
> + int repin = 0;
> + struct pgdir * newpgdir;
No space after the '*'.
> * its first page table is. We set some things up here: */
> int init_guest_pagetable(struct lguest *lg, unsigned long pgtable)
> {
> + struct pgdir * newpgdir;
> +
> /* In flush_user_mappings() we loop from 0 to
> * "vaddr_to_pgd_index(lg->page_offset)". This assumes it won't hit
> * the Switcher mappings, so check that now. */
> if (vaddr_to_pgd_index(lg->page_offset) >= SWITCHER_PGD_INDEX)
> return -EINVAL;
> - /* We start on the first shadow page table, and give it a blank PGD
> - * page. */
> - lg->pgdidx = 0;
> - lg->pgdirs[lg->pgdidx].cr3 = pgtable;
> - lg->pgdirs[lg->pgdidx].pgdir = (spgd_t*)get_zeroed_page(GFP_KERNEL);
> - if (!lg->pgdirs[lg->pgdidx].pgdir)
> +
> + INIT_LIST_HEAD(&lg->pgdir_list);
> +
> + newpgdir = alloc_newpgdir();
> + if (!newpgdir)
> return -ENOMEM;
> +
> + lg->pgdir_cur = newpgdir;
> + newpgdir->cr3 = pgtable;
> + list_add(&newpgdir->list, &lg->pgdir_list);
> + lg->num_pgdirs = 1;
> +
Hmm, perhaps rename alloc_newpgdir() to "add_pgdir()" and have it do the
"list_add(&newpgdir->list, &lg->pgdir_list);", "lg->num_pgdirs++" and
cr3 assignments? Then this code becomes:
lg->pgdir_cur = add_pgdir(lg, pgtable);
if (!lg->pgdir_cur)
return -ENOMEM;
And new_pgdir becomes:
/* Have we reached the maximum number of pgdirs we can hold? */
if (lg->num_pgdirs == PGDIR_MAX) {
/* Grab the tail for recycling and move it to the front. */
newpgdir = list_entry(lg->pgdir_list.prev, struct pgdir, list);
list_move(&newpgdir->list, &lg->pgdir_list);
/* Release all the non-kernel mappings. */
flush_user_mappings(lg, newpgdir);
/* Record which Guest toplevel this shadows. */
lg->cr3 = cr3;
} else {
/* Now we try to allocate a fresh one. */
newpgdir = alloc_newpgdir(lg, cr3);
if (!newpgdir)
kill_guest(lg, "failed to get fresh pgdir");
/* This is a blank page, so there are no kernel
* mappings: caller must map the stack! */
*blank_pgdir = 1;
}
return newpgdir;
}
Cheers!
Rusty.
More information about the Lguest
mailing list