From mboxrd@z Thu Jan 1 00:00:00 1970 From: Avi Kivity Subject: Re: [patch 10/10] KVM: MMU: speed up mmu_unsync_walk Date: Fri, 19 Sep 2008 18:26:56 -0700 Message-ID: <48D45160.6030208@redhat.com> References: <20080918212749.800177179@localhost.localdomain> <20080918213337.235766366@localhost.localdomain> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: Avi Kivity , kvm@vger.kernel.org, "David S. Ahern" To: Marcelo Tosatti Return-path: Received: from mx2.redhat.com ([66.187.237.31]:36159 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751408AbYITB0x (ORCPT ); Fri, 19 Sep 2008 21:26:53 -0400 In-Reply-To: <20080918213337.235766366@localhost.localdomain> Sender: kvm-owner@vger.kernel.org List-ID: Marcelo Tosatti wrote: > Cache the unsynced children information in a per-page bitmap. > > static void nonpaging_prefetch_page(struct kvm_vcpu *vcpu, > struct kvm_mmu_page *sp) > { > @@ -946,33 +978,57 @@ static void nonpaging_invlpg(struct kvm_ > static int mmu_unsync_walk(struct kvm_mmu_page *parent, mmu_unsync_fn fn, > void *priv) > { > - int i, ret; > - struct kvm_mmu_page *sp = parent; > + int ret, level, i; > + u64 ent; > + struct kvm_mmu_page *sp, *child; > + struct walk { > + struct kvm_mmu_page *sp; > + int pos; > + } walk[PT64_ROOT_LEVEL]; > > - while (parent->unsync_children) { > - for (i = 0; i < PT64_ENT_PER_PAGE; ++i) { > - u64 ent = sp->spt[i]; > + WARN_ON(parent->role.level == PT_PAGE_TABLE_LEVEL); > + > + if (!parent->unsync_children) > + return 0; > + > + memset(&walk, 0, sizeof(walk)); > + level = parent->role.level; > + walk[level-1].sp = parent; > + > + do { > + sp = walk[level-1].sp; > + i = find_next_bit(sp->unsync_child_bitmap, 512, walk[level-1].pos); > + if (i < 512) { > + walk[level-1].pos = i+1; > + ent = sp->spt[i]; > > if (is_shadow_present_pte(ent)) { > - struct kvm_mmu_page *child; > child = page_header(ent & PT64_BASE_ADDR_MASK); > > if (child->unsync_children) { > - sp = child; > - break; > + --level; > + walk[level-1].sp = child; > + walk[level-1].pos = 0; > + continue; > } > if (child->unsync) { > ret = fn(child, priv); > + __clear_bit(i, sp->unsync_child_bitmap); > if (ret) > return ret; > } > } > + __clear_bit(i, sp->unsync_child_bitmap); > + } else { > + ++level; > + if (find_first_bit(sp->unsync_child_bitmap, 512) == 512) { > + sp->unsync_children = 0; > + if (level-1 < PT64_ROOT_LEVEL) > + walk[level-1].pos = 0; > + } > } > - if (i == PT64_ENT_PER_PAGE) { > - sp->unsync_children = 0; > - sp = parent; > - } > - } > + } while (level <= parent->role.level); > + > return 0; > } > > > --- kvm.orig/include/asm-x86/kvm_host.h > +++ kvm/include/asm-x86/kvm_host.h > @@ -201,6 +201,7 @@ struct kvm_mmu_page { > u64 *parent_pte; /* !multimapped */ > struct hlist_head parent_ptes; /* multimapped, kvm_pte_chain */ > }; > + DECLARE_BITMAP(unsync_child_bitmap, 512); > }; > Later, we can throw this bitmap out to a separate object. Also, it may make sense to replace it with an array of u16s. -- I have a truly marvellous patch that fixes the bug which this signature is too narrow to contain.