From patchwork Mon Apr 18 18:38:14 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takuya Yoshikawa X-Patchwork-Id: 716171 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p3IIcSfq029853 for ; Mon, 18 Apr 2011 18:38:28 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754800Ab1DRSiZ (ORCPT ); Mon, 18 Apr 2011 14:38:25 -0400 Received: from mail-pz0-f46.google.com ([209.85.210.46]:44230 "EHLO mail-pz0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752458Ab1DRSiY (ORCPT ); Mon, 18 Apr 2011 14:38:24 -0400 Received: by pzk9 with SMTP id 9so2197610pzk.19 for ; Mon, 18 Apr 2011 11:38:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:date:from:to:cc:subject:message-id:in-reply-to :references:x-mailer:mime-version:content-type :content-transfer-encoding; bh=0F0+LcOp7gZi1a+/Oj7FtmakqGUqgolydD6a/VBcP+I=; b=BNiJp4w3r/syFg4dvCp7A2RXMXQxJx9or2odXYRdAv42f5i3qLP+4RKevAMEkkVc9k nVa3cIs0rVhFWRLAo6QZwvoN6s+AdTMhpQkVWQaUqFt9X91k9LgAQ1I8SGV/Q1ZUTJyk CwF4HGEiaDnDwtgDZ5+xiqRia3LEuYeP9uZGA= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=date:from:to:cc:subject:message-id:in-reply-to:references:x-mailer :mime-version:content-type:content-transfer-encoding; b=uoswu6a/Vma+SPepp5rHI0+fHavNXTyTSZmC9Nbv6PK/BrG54RmDQIW1iTlpNH375S 1hsdRjqGBM3R3+Aoj5iliDvefaRkMuSK4E5Vl6TTIWj8ZQbdS7FrTABgFjD4X2aUSJkg laK9SD5vjBQWxOVC0Hmqe+jYl01pYiLZpAdQQ= Received: by 10.68.56.194 with SMTP id c2mr4721199pbq.29.1303151904422; Mon, 18 Apr 2011 11:38:24 -0700 (PDT) Received: from amd (s198099.dynamic.ppp.asahi-net.or.jp [220.157.198.99]) by mx.google.com with ESMTPS id v5sm2452241pbl.77.2011.04.18.11.38.20 (version=SSLv3 cipher=OTHER); Mon, 18 Apr 2011 11:38:22 -0700 (PDT) Date: Tue, 19 Apr 2011 03:38:14 +0900 From: Takuya Yoshikawa To: avi@redhat.com, mtosatti@redhat.com Cc: kvm@vger.kernel.org, yoshikawa.takuya@oss.ntt.co.jp Subject: [RFC PATCH 3/3] KVM: MMU: Optimize guest page table walk Message-Id: <20110419033814.3cc7ab5e.takuya.yoshikawa@gmail.com> In-Reply-To: <20110419033220.e527bcae.takuya.yoshikawa@gmail.com> References: <20110419033220.e527bcae.takuya.yoshikawa@gmail.com> X-Mailer: Sylpheed 3.1.0beta2 (GTK+ 2.22.0; x86_64-pc-linux-gnu) Mime-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 18 Apr 2011 18:38:28 +0000 (UTC) From: Takuya Yoshikawa We optimize multi level guest page table walk as follows: 1. We cache the memslot which, probably, includes the next guest page tables to avoid searching for it many times. 2. We use get_user() instead of copy_from_user(). Note that this is kind of a restricted way of Xiao's more generic work: "KVM: optimize memslots searching and cache GPN to GFN." With this patch applied, paging64_walk_addr_generic() has improved as the following tracing results show. Before: 3.169 us | paging64_walk_addr_generic(); 1.880 us | paging64_walk_addr_generic(); 1.243 us | paging64_walk_addr_generic(); 1.517 us | paging64_walk_addr_generic(); 3.009 us | paging64_walk_addr_generic(); 1.814 us | paging64_walk_addr_generic(); 1.340 us | paging64_walk_addr_generic(); 1.659 us | paging64_walk_addr_generic(); 1.748 us | paging64_walk_addr_generic(); 1.488 us | paging64_walk_addr_generic(); After: 1.714 us | paging64_walk_addr_generic(); 0.806 us | paging64_walk_addr_generic(); 0.664 us | paging64_walk_addr_generic(); 0.619 us | paging64_walk_addr_generic(); 0.645 us | paging64_walk_addr_generic(); 0.605 us | paging64_walk_addr_generic(); 1.388 us | paging64_walk_addr_generic(); 0.753 us | paging64_walk_addr_generic(); 0.594 us | paging64_walk_addr_generic(); 0.833 us | paging64_walk_addr_generic(); Signed-off-by: Takuya Yoshikawa --- arch/x86/kvm/paging_tmpl.h | 37 ++++++++++++++++++++++++++++++++----- 1 files changed, 32 insertions(+), 5 deletions(-) diff --git a/arch/x86/kvm/paging_tmpl.h b/arch/x86/kvm/paging_tmpl.h index 109939a..614aa3f 100644 --- a/arch/x86/kvm/paging_tmpl.h +++ b/arch/x86/kvm/paging_tmpl.h @@ -109,12 +109,37 @@ static unsigned FNAME(gpte_access)(struct kvm_vcpu *vcpu, pt_element_t gpte) return access; } +/* + * Read the guest PTE refered to by table_gfn and offset and put it into ptep. + * + * *slot_hint, if not NULL, should point to a memslot which probably includes + * the guest PTE. The actual memslot will be put back into this so that + * callers can cache it. + */ static int FNAME(read_guest_pte)(struct kvm_vcpu *vcpu, struct kvm_mmu *mmu, - gfn_t table_gfn, int offset, pt_element_t *ptep) + gfn_t table_gfn, int offset, pt_element_t *ptep, + struct kvm_memory_slot **slot_hint) { - return kvm_read_guest_page_mmu(vcpu, mmu, table_gfn, ptep, - offset, sizeof(*ptep), - PFERR_USER_MASK | PFERR_WRITE_MASK); + unsigned long addr; + pt_element_t __user *ptep_user; + gfn_t real_gfn; + + real_gfn = mmu->translate_gpa(vcpu, gfn_to_gpa(table_gfn), + PFERR_USER_MASK | PFERR_WRITE_MASK); + if (real_gfn == UNMAPPED_GVA) + return -EFAULT; + + real_gfn = gpa_to_gfn(real_gfn); + + if (!(*slot_hint) || !gfn_in_memslot(*slot_hint, real_gfn)) + *slot_hint = gfn_to_memslot(vcpu->kvm, real_gfn); + + addr = gfn_to_hva_memslot(*slot_hint, real_gfn); + if (kvm_is_error_hva(addr)) + return -EFAULT; + + ptep_user = (pt_element_t __user *)((void *)addr + offset); + return get_user(*ptep, ptep_user); } /* @@ -130,6 +155,7 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, gpa_t pte_gpa; bool eperm, present, rsvd_fault; int offset, write_fault, user_fault, fetch_fault; + struct kvm_memory_slot *slot_cache = NULL; write_fault = access & PFERR_WRITE_MASK; user_fault = access & PFERR_USER_MASK; @@ -168,7 +194,8 @@ walk: walker->table_gfn[walker->level - 1] = table_gfn; walker->pte_gpa[walker->level - 1] = pte_gpa; - if (FNAME(read_guest_pte)(vcpu, mmu, table_gfn, offset, &pte)) { + if (FNAME(read_guest_pte)(vcpu, mmu, table_gfn, + offset, &pte, &slot_cache)) { present = false; break; }