diff mbox

[v2,10/10] x86/SVM: Add AMD AVIC key handler

Message ID 1483163161-2402-11-git-send-email-suravee.suthikulpanit@amd.com (mailing list archive)
State New, archived
Headers show

Commit Message

Suravee Suthikulpanit Dec. 31, 2016, 5:46 a.m. UTC
Adding new key-handler "j" for dumping AVIC-related information.
Here is an example of per-domain statistics being dumped.

  *********** SVM AVIC Statistics **************
  >>> Domain 1 <<<
      VCPU 0
      * incomp_ipi = 3110
      * noaccel    = 236475
      * post_intr  = 116176
      * doorbell   = 715
      VCPU 1
      * incomp_ipi = 2565
      * noaccel    = 233061
      * post_intr  = 115765
      * doorbell   = 771
  **************************************

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Jan Beulich <JBeulich@suse.com>
Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
---
 xen/arch/x86/hvm/svm/avic.c        | 48 ++++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/svm/svm.c         |  1 +
 xen/include/asm-x86/hvm/svm/vmcb.h |  6 +++++
 3 files changed, 55 insertions(+)

Comments

Boris Ostrovsky Jan. 3, 2017, 4:01 p.m. UTC | #1
>  
> +static void avic_dump(unsigned char ch)
> +{
> +    struct domain *d;
> +    struct vcpu *v;
> +
> +    printk("*********** SVM AVIC Statistics **************\n");
> +
> +    rcu_read_lock(&domlist_read_lock);
> +
> +    for_each_domain ( d )
> +    {
> +        if ( !is_hvm_domain(d) )

|| !svm_avic_vcpu_enabled(d->v[0]) (or something along these lines)?


> +            continue;
> +        printk(">>> Domain %d <<<\n", d->domain_id);
> +        for_each_vcpu ( d, v )
> +        {
> +            printk("\tVCPU %d\n", v->vcpu_id);
> +            printk("\t* incomp_ipi = %u\n",
> +                   v->arch.hvm_svm.cnt_avic_incomp_ipi);
> +            printk("\t* noaccel    = %u\n",
> +                   v->arch.hvm_svm.cnt_avic_noaccel);
> +            printk("\t* post_intr  = %u\n",
> +                   v->arch.hvm_svm.cnt_avic_post_intr);
> +            printk("\t* doorbell   = %u\n",
> +                   v->arch.hvm_svm.cnt_avic_doorbell);
> +        }
> +    }
> +
> +    rcu_read_unlock(&domlist_read_lock);
> +
> +    printk("**************************************\n");
> +
> +}
> +
> +void __init setup_avic_dump(void)
> +{

if ( !svm_avic ) return; ?


-boris


> +    register_keyhandler('j', avic_dump, "dump SVM AVIC", 1);
> +}
> +
Andrew Cooper Jan. 3, 2017, 4:04 p.m. UTC | #2
On 03/01/17 16:01, Boris Ostrovsky wrote:
>>  
>> +static void avic_dump(unsigned char ch)
>> +{
>> +    struct domain *d;
>> +    struct vcpu *v;
>> +
>> +    printk("*********** SVM AVIC Statistics **************\n");
>> +
>> +    rcu_read_lock(&domlist_read_lock);
>> +
>> +    for_each_domain ( d )
>> +    {
>> +        if ( !is_hvm_domain(d) )
> || !svm_avic_vcpu_enabled(d->v[0]) (or something along these lines)?

It isn't safe to deference the vcpu array like this, which in turn
highlights that the avic predicate should be per-domain, not per-cpu. 
Under no circumstances should we have AVIC on some vcpus but not others
of the same domain.

~Andrew
Suravee Suthikulpanit Jan. 5, 2017, 8 a.m. UTC | #3
Hi Boris/Andrew,

On 1/3/17 23:04, Andrew Cooper wrote:
> On 03/01/17 16:01, Boris Ostrovsky wrote:
>>>
>>> +static void avic_dump(unsigned char ch)
>>> +{
>>> +    struct domain *d;
>>> +    struct vcpu *v;
>>> +
>>> +    printk("*********** SVM AVIC Statistics **************\n");
>>> +
>>> +    rcu_read_lock(&domlist_read_lock);
>>> +
>>> +    for_each_domain ( d )
>>> +    {
>>> +        if ( !is_hvm_domain(d) )
>> || !svm_avic_vcpu_enabled(d->v[0]) (or something along these lines)?
>
> It isn't safe to deference the vcpu array like this, which in turn
> highlights that the avic predicate should be per-domain, not per-cpu.
> Under no circumstances should we have AVIC on some vcpus but not others
> of the same domain.
>
> ~Andrew
>

Let me add something like:

     static inline bool svm_is_avic_domain(struct domain *d)
     {
         return ( d->arch.hvm_domain.svm.avic_physical_id_table != 0 );
     }

This should allow us to check whether the svm_avic_dom_init() is enabled 
successfully.

Thanks,
Suravee
Jan Beulich Jan. 5, 2017, 4:07 p.m. UTC | #4
>>> On 31.12.16 at 06:46, <suravee.suthikulpanit@amd.com> wrote:
> +void __init setup_avic_dump(void)
> +{
> +    register_keyhandler('j', avic_dump, "dump SVM AVIC", 1);
> +}

For one the description should include the word "stats". And then
I'm rather uncertain this is work burning one of the few remaining
available keys. Could this be made a domctl instead?

Jan
Suravee Suthikulpanit Jan. 10, 2017, 11:14 a.m. UTC | #5
Jan,

On 01/05/2017 11:07 PM, Jan Beulich wrote:
>>>> On 31.12.16 at 06:46, <suravee.suthikulpanit@amd.com> wrote:
>> +void __init setup_avic_dump(void)
>> +{
>> +    register_keyhandler('j', avic_dump, "dump SVM AVIC", 1);
>> +}
>
> For one the description should include the word "stats". And then
> I'm rather uncertain this is work burning one of the few remaining
> available keys. Could this be made a domctl instead?
>
> Jan
>

Not sure how you are thinking about using domctl to output statistics. 
Are there examples? Could you please describe?

Thanks,
Suravee
Jan Beulich Jan. 10, 2017, 12:55 p.m. UTC | #6
>>> On 10.01.17 at 12:14, <Suravee.Suthikulpanit@amd.com> wrote:
> On 01/05/2017 11:07 PM, Jan Beulich wrote:
>>>>> On 31.12.16 at 06:46, <suravee.suthikulpanit@amd.com> wrote:
>>> +void __init setup_avic_dump(void)
>>> +{
>>> +    register_keyhandler('j', avic_dump, "dump SVM AVIC", 1);
>>> +}
>>
>> For one the description should include the word "stats". And then
>> I'm rather uncertain this is work burning one of the few remaining
>> available keys. Could this be made a domctl instead?
> 
> Not sure how you are thinking about using domctl to output statistics. 
> Are there examples? Could you please describe?

Provide a domctl to obtain the values, and a new xl command to
wrap that domctl.

Jan
diff mbox

Patch

diff --git a/xen/arch/x86/hvm/svm/avic.c b/xen/arch/x86/hvm/svm/avic.c
index faa5e45..1aea724 100644
--- a/xen/arch/x86/hvm/svm/avic.c
+++ b/xen/arch/x86/hvm/svm/avic.c
@@ -27,6 +27,7 @@ 
 #include <asm/hvm/support.h>
 #include <asm/hvm/svm/avic.h>
 #include <asm/hvm/vlapic.h>
+#include <xen/keyhandler.h>
 #include <asm/p2m.h>
 #include <asm/page.h>
 
@@ -320,6 +321,8 @@  void svm_avic_vmexit_do_incomp_ipi(struct cpu_user_regs *regs)
     u32 id = vmcb->exitinfo2 >> 32;
     u32 index = vmcb->exitinfo2 && 0xFF;
 
+    curr->arch.hvm_svm.cnt_avic_incomp_ipi++;
+
     switch ( id )
     {
     case AVIC_INCMP_IPI_ERR_INVALID_INT_TYPE:
@@ -580,6 +583,8 @@  void svm_avic_vmexit_do_noaccel(struct cpu_user_regs *regs)
     u32 offset = vmcb->exitinfo1 & 0xFF0;
     u32 rw = (vmcb->exitinfo1 >> 32) & 0x1;
 
+    curr->arch.hvm_svm.cnt_avic_noaccel++;
+
     switch ( offset )
     {
     case APIC_ID:
@@ -654,16 +659,59 @@  void svm_avic_deliver_posted_intr(struct vcpu *v, u8 vec)
     if ( vlapic_test_and_set_vector(vec, &vlapic->regs->data[APIC_IRR]) )
         return;
 
+    v->arch.hvm_svm.cnt_avic_post_intr++;
     /*
      * If vcpu is running on another cpu, hit the doorbell to signal
      * it to process interrupt. Otherwise, kick it.
      */
     if ( v->is_running && (v != current) )
+    {
         wrmsrl(AVIC_DOORBELL, cpu_data[v->processor].apicid);
+        v->arch.hvm_svm.cnt_avic_doorbell++;
+    }
     else
         vcpu_kick(v);
 }
 
+static void avic_dump(unsigned char ch)
+{
+    struct domain *d;
+    struct vcpu *v;
+
+    printk("*********** SVM AVIC Statistics **************\n");
+
+    rcu_read_lock(&domlist_read_lock);
+
+    for_each_domain ( d )
+    {
+        if ( !is_hvm_domain(d) )
+            continue;
+        printk(">>> Domain %d <<<\n", d->domain_id);
+        for_each_vcpu ( d, v )
+        {
+            printk("\tVCPU %d\n", v->vcpu_id);
+            printk("\t* incomp_ipi = %u\n",
+                   v->arch.hvm_svm.cnt_avic_incomp_ipi);
+            printk("\t* noaccel    = %u\n",
+                   v->arch.hvm_svm.cnt_avic_noaccel);
+            printk("\t* post_intr  = %u\n",
+                   v->arch.hvm_svm.cnt_avic_post_intr);
+            printk("\t* doorbell   = %u\n",
+                   v->arch.hvm_svm.cnt_avic_doorbell);
+        }
+    }
+
+    rcu_read_unlock(&domlist_read_lock);
+
+    printk("**************************************\n");
+
+}
+
+void __init setup_avic_dump(void)
+{
+    register_keyhandler('j', avic_dump, "dump SVM AVIC", 1);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/xen/arch/x86/hvm/svm/svm.c b/xen/arch/x86/hvm/svm/svm.c
index 7c0cda0..b8861d8 100644
--- a/xen/arch/x86/hvm/svm/svm.c
+++ b/xen/arch/x86/hvm/svm/svm.c
@@ -1456,6 +1456,7 @@  const struct hvm_function_table * __init start_svm(void)
     }
 
     setup_vmcb_dump();
+    setup_avic_dump();
 
     svm_feature_flags = (current_cpu_data.extended_cpuid_level >= 0x8000000A ?
                          cpuid_edx(0x8000000A) : 0);
diff --git a/xen/include/asm-x86/hvm/svm/vmcb.h b/xen/include/asm-x86/hvm/svm/vmcb.h
index 9abf077..e2b810e 100644
--- a/xen/include/asm-x86/hvm/svm/vmcb.h
+++ b/xen/include/asm-x86/hvm/svm/vmcb.h
@@ -552,6 +552,12 @@  struct arch_svm_struct {
 
     struct avic_phy_apic_id_ent *avic_last_phy_id;
     u32 avic_last_ldr;
+
+    /* AVIC Statistics */
+    u32 cnt_avic_incomp_ipi;
+    u32 cnt_avic_noaccel;
+    u32 cnt_avic_post_intr;
+    u32 cnt_avic_doorbell;
 };
 
 struct vmcb_struct *alloc_vmcb(void);