All of lore.kernel.org
 help / color / mirror / Atom feed
From: Jan Beulich <jbeulich@suse.com>
To: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: "Roger Pau Monné" <roger.pau@citrix.com>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	"Julien Grall" <julien@xen.org>,
	"Volodymyr Babchuk" <Volodymyr_Babchuk@epam.com>,
	"Bertrand Marquis" <bertrand.marquis@arm.com>,
	"Michal Orzel" <michal.orzel@amd.com>,
	"Oleksii Kurochko" <oleksii.kurochko@gmail.com>,
	Xen-devel <xen-devel@lists.xenproject.org>
Subject: Re: [PATCH v2 4/4] x86/vmx: Rewrite vmx_sync_pir_to_irr() to be more efficient
Date: Wed, 28 Aug 2024 11:19:52 +0200	[thread overview]
Message-ID: <d022a5b1-c0ca-4399-b972-b01d834a95ec@suse.com> (raw)
In-Reply-To: <20240827135746.1908070-5-andrew.cooper3@citrix.com>

On 27.08.2024 15:57, Andrew Cooper wrote:
> There are two issues.  First, pi_test_and_clear_on() pulls the cache-line to
> the CPU and dirties it even if there's nothing outstanding, but the final
> for_each_set_bit() is O(256) when O(8) would do,

Nit: That's bitmap_for_each() now, I think. And again ...

> and would avoid multiple
> atomic updates to the same IRR word.
> 
> Rewrite it from scratch, explaining what's going on at each step.
> 
> Bloat-o-meter reports 177 -> 145 (net -32), but the better aspect is the
> removal calls to __find_{first,next}_bit() hidden behind for_each_set_bit().

... here, and no underscore prefixes on the two find functions.

> --- a/xen/arch/x86/hvm/vmx/vmx.c
> +++ b/xen/arch/x86/hvm/vmx/vmx.c
> @@ -2317,18 +2317,72 @@ static void cf_check vmx_deliver_posted_intr(struct vcpu *v, u8 vector)
>  
>  static void cf_check vmx_sync_pir_to_irr(struct vcpu *v)
>  {
> -    struct vlapic *vlapic = vcpu_vlapic(v);
> -    unsigned int group, i;
> -    DECLARE_BITMAP(pending_intr, X86_NR_VECTORS);
> +    struct pi_desc *desc = &v->arch.hvm.vmx.pi_desc;
> +    union {
> +        uint64_t _64[X86_NR_VECTORS / (sizeof(uint64_t) * 8)];

Using unsigned long here would imo be better, as that's what matches
struct pi_desc's DECLARE_BITMAP().

> +        uint32_t _32[X86_NR_VECTORS / (sizeof(uint32_t) * 8)];
> +    } vec;
> +    uint32_t *irr;
> +    bool on;
>  
> -    if ( !pi_test_and_clear_on(&v->arch.hvm.vmx.pi_desc) )
> +    /*
> +     * The PIR is a contended cacheline which bounces between the CPU(s) and
> +     * IOMMU(s).  An IOMMU updates the entire PIR atomically, but we can't
> +     * express the same on the CPU side, so care has to be taken.
> +     *
> +     * First, do a plain read of ON.  If the PIR hasn't been modified, this
> +     * will keep the cacheline Shared and not pull it Excusive on the current
> +     * CPU.
> +     */
> +    if ( !pi_test_on(desc) )
>          return;
>  
> -    for ( group = 0; group < ARRAY_SIZE(pending_intr); group++ )
> -        pending_intr[group] = pi_get_pir(&v->arch.hvm.vmx.pi_desc, group);
> +    /*
> +     * Second, if the plain read said that ON was set, we must clear it with
> +     * an atomic action.  This will bring the cachline to Exclusive on the

Nit (from my spell checker): cacheline.

> +     * current CPU.
> +     *
> +     * This should always succeed because noone else should be playing with
> +     * the PIR behind our back, but assert so just in case.
> +     */
> +    on = pi_test_and_clear_on(desc);
> +    ASSERT(on);
> +
> +    /*
> +     * The cacheline is now Exclusive on the current CPU, and because ON was

"is" is pretty ambitious. We can only hope it (still) is.

> +     * set, some other entity (an IOMMU, or Xen on another CPU) has indicated
> +     * that at PIR needs re-scanning.

Stray "at"?

> +     *
> +     * Note: Entities which can't update the entire cacheline atomically
> +     *       (i.e. Xen on another CPU) are required to update PIR first, then
> +     *       set ON.  Therefore, there is a corner case where we may have
> +     *       found and processed the PIR updates "last time around" and only
> +     *       found ON this time around.  This is fine; the logic still
> +     *       operates correctly.
> +     *
> +     * Atomically read and clear the entire pending bitmap as fast as we, to

Missing "can" before the comma?

> +     * reduce the window where another entity may steal the cacheline back
> +     * from us.  This is a performance concern, not a correctness concern.  If
> +     * the another entity does steal the cacheline back, we'll just wait to

"the other"?

> +     * get it back again.
> +     */
> +    for ( unsigned int i = 0; i < ARRAY_SIZE(vec._64); ++i )
> +        vec._64[i] = xchg(&desc->pir[i], 0);
> +
> +    /*
> +     * Finally, merge the pending vectors into IRR.  The IRR register is
> +     * scattered in memory, so we have to do this 32 bits at a time.
> +     */
> +    irr = (uint32_t *)&vcpu_vlapic(v)->regs->data[APIC_IRR];
> +    for ( unsigned int i = 0; i < ARRAY_SIZE(vec._32); ++i )
> +    {
> +        if ( !vec._32[i] )
> +            continue;
>  
> -    bitmap_for_each ( i, pending_intr, X86_NR_VECTORS )
> -        vlapic_set_vector(i, &vlapic->regs->data[APIC_IRR]);
> +        asm ( "lock or %[val], %[irr]"
> +              : [irr] "+m" (irr[i * 0x10])

This wants to be irr * 4 only, to account for sizeof(*irr) == 4.

Jan


  parent reply	other threads:[~2024-08-28  9:20 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-27 13:57 [PATCH 0/4] xen/bitops: More for_each_bit() conversions Andrew Cooper
2024-08-27 13:57 ` [PATCH 1/4] xen/evtchn: Use bitmap_for_each() in evtchn_check_pollers() Andrew Cooper
2024-08-27 15:57   ` Jan Beulich
2024-08-27 13:57 ` [PATCH 2/4] x86/hvm: Use for_each_set_bit() in hvm_emulate_writeback() Andrew Cooper
2024-08-27 16:07   ` Jan Beulich
2024-08-28 14:44     ` Andrew Cooper
2024-08-28 14:56       ` Jan Beulich
2024-08-28 18:56         ` Andrew Cooper
2024-08-29  6:13           ` Jan Beulich
2024-08-27 13:57 ` [PATCH 3/4] x86/hvm: Rework hpet_write() for improved code generation Andrew Cooper
2024-08-28  8:13   ` Jan Beulich
2024-08-28 17:50     ` Andrew Cooper
2024-08-29  6:25       ` Jan Beulich
2024-08-27 13:57 ` [PATCH v2 4/4] x86/vmx: Rewrite vmx_sync_pir_to_irr() to be more efficient Andrew Cooper
2024-08-27 16:25   ` Andrew Cooper
2024-08-28  9:19   ` Jan Beulich [this message]
2024-08-28 18:08     ` Andrew Cooper
2024-08-28 19:36       ` Andrew Cooper
2024-08-29  6:35       ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d022a5b1-c0ca-4399-b972-b01d834a95ec@suse.com \
    --to=jbeulich@suse.com \
    --cc=Volodymyr_Babchuk@epam.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=bertrand.marquis@arm.com \
    --cc=julien@xen.org \
    --cc=michal.orzel@amd.com \
    --cc=oleksii.kurochko@gmail.com \
    --cc=roger.pau@citrix.com \
    --cc=sstabellini@kernel.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.