All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Zyngier <maz@kernel.org>
To: Oliver Upton <oliver.upton@linux.dev>
Cc: kvmarm@lists.linux.dev, kvm@vger.kernel.org,
	James Morse <james.morse@arm.com>,
	Suzuki K Poulose <suzuki.poulose@arm.com>,
	Zenghui Yu <yuzenghui@huawei.com>,
	Raghavendra Rao Ananta <rananta@google.com>,
	Jing Zhang <jingzhangos@google.com>
Subject: Re: [PATCH 12/15] KVM: arm64: vgic-its: Pick cache victim based on usage count
Date: Thu, 25 Jan 2024 10:55:19 +0000	[thread overview]
Message-ID: <861qa58yy0.wl-maz@kernel.org> (raw)
In-Reply-To: <20240124204909.105952-13-oliver.upton@linux.dev>

On Wed, 24 Jan 2024 20:49:06 +0000,
Oliver Upton <oliver.upton@linux.dev> wrote:
> 
> To date the translation cache LRU policy relies on the ordering of the
> linked-list to pick the victim, as entries are moved to the head of the
> list on every cache hit. These sort of transformations are incompatible
> with an rculist, necessitating a different strategy for recording usage
> in-place.
> 
> Count the number of cache hits since the last translation cache miss for
> every entry. The preferences for selecting a victim are as follows:
> 
>  - Invalid entries over valid entries
> 
>  - Valid entry with the lowest usage count
> 
>  - In the case of a tie, pick the entry closest to the tail (oldest)
> 
> Signed-off-by: Oliver Upton <oliver.upton@linux.dev>
> ---
>  arch/arm64/kvm/vgic/vgic-its.c | 42 ++++++++++++++++++++++++++--------
>  1 file changed, 32 insertions(+), 10 deletions(-)
> 
> diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
> index aec82d9a1b3c..ed0c6c333a6c 100644
> --- a/arch/arm64/kvm/vgic/vgic-its.c
> +++ b/arch/arm64/kvm/vgic/vgic-its.c
> @@ -154,6 +154,7 @@ struct vgic_translation_cache_entry {
>  	u32			devid;
>  	u32			eventid;
>  	struct vgic_irq		*irq;
> +	atomic64_t		usage_count;
>  };
>  
>  /**
> @@ -577,13 +578,7 @@ static struct vgic_irq *__vgic_its_check_cache(struct vgic_dist *dist,
>  		    cte->eventid != eventid)
>  			continue;
>  
> -		/*
> -		 * Move this entry to the head, as it is the most
> -		 * recently used.
> -		 */
> -		if (!list_is_first(&cte->entry, &dist->lpi_translation_cache))
> -			list_move(&cte->entry, &dist->lpi_translation_cache);
> -
> +		atomic64_inc(&cte->usage_count);
>  		return cte->irq;
>  	}
>  
> @@ -616,6 +611,30 @@ static unsigned int vgic_its_max_cache_size(struct kvm *kvm)
>  	return atomic_read(&kvm->online_vcpus) * LPI_DEFAULT_PCPU_CACHE_SIZE;
>  }
>  
> +static struct vgic_translation_cache_entry *vgic_its_cache_victim(struct vgic_dist *dist)
> +{
> +	struct vgic_translation_cache_entry *cte, *victim = NULL;
> +	u64 min, tmp;
> +
> +	/*
> +	 * Find the least used cache entry since the last cache miss, preferring
> +	 * older entries in the case of a tie. Note that usage accounting is
> +	 * deliberately non-atomic, so this is all best-effort.
> +	 */
> +	list_for_each_entry(cte, &dist->lpi_translation_cache, entry) {
> +		if (!cte->irq)
> +			return cte;
> +
> +		tmp = atomic64_xchg_relaxed(&cte->usage_count, 0);
> +		if (!victim || tmp <= min) {

min is not initialised until after the first round. Not great. How
comes the compiler doesn't spot this?

> +			victim = cte;
> +			min = tmp;
> +		}
> +	}

So this resets all the counters on each search for a new insertion?
Seems expensive, specially on large VMs (512 * 16 = up to 8K SWP
instructions in a tight loop, and I'm not even mentioning the fun
without LSE). I can at least think of a box that will throw its
interconnect out of the pram it tickled that way.

I'd rather the new cache entry inherits the max of the current set,
making it a lot cheaper. We can always detect the overflow and do a
full invalidation in that case (worse case -- better options exist).

> +
> +	return victim;
> +}
> +
>  static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its,
>  				       u32 devid, u32 eventid,
>  				       struct vgic_irq *irq)
> @@ -645,9 +664,12 @@ static void vgic_its_cache_translation(struct kvm *kvm, struct vgic_its *its,
>  		goto out;
>  
>  	if (dist->lpi_cache_count >= vgic_its_max_cache_size(kvm)) {
> -		/* Always reuse the last entry (LRU policy) */
> -		victim = list_last_entry(&dist->lpi_translation_cache,
> -				      typeof(*cte), entry);
> +		victim = vgic_its_cache_victim(dist);
> +		if (WARN_ON_ONCE(!victim)) {
> +			victim = new;
> +			goto out;
> +		}

I don't understand how this could happen. It sort of explains the
oddity I was mentioning earlier, but I don't think we need this
complexity.

Thanks,

	M.

-- 
Without deviation from the norm, progress is not possible.

  parent reply	other threads:[~2024-01-25 10:55 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-24 20:48 [PATCH 00/15] KVM: arm64: Improvements to GICv3 LPI injection Oliver Upton
2024-01-24 20:48 ` [PATCH 01/15] KVM: arm64: vgic: Store LPIs in an xarray Oliver Upton
2024-02-05  6:05   ` Dan Carpenter
2024-01-24 20:48 ` [PATCH 02/15] KVM: arm64: vgic: Use xarray to find LPI in vgic_get_lpi() Oliver Upton
2024-01-24 20:48 ` [PATCH 03/15] KVM: arm64: vgic-v3: Iterate the xarray to find pending LPIs Oliver Upton
2024-01-24 20:48 ` [PATCH 04/15] KVM: arm64: vgic-its: Walk the LPI xarray in vgic_copy_lpi_list() Oliver Upton
2024-01-25  9:15   ` Marc Zyngier
2024-01-25  9:24     ` Oliver Upton
2024-01-24 20:48 ` [PATCH 05/15] KVM: arm64: vgic: Get rid of the LPI linked-list Oliver Upton
2024-01-25  9:28   ` Marc Zyngier
2024-01-24 20:49 ` [PATCH 06/15] KVM: arm64: vgic: Use atomics to count LPIs Oliver Upton
2024-01-24 20:49 ` [PATCH 07/15] KVM: arm64: vgic: Free LPI vgic_irq structs in an RCU-safe manner Oliver Upton
2024-01-24 20:49 ` [PATCH 08/15] KVM: arm64: vgic: Rely on RCU protection in vgic_get_lpi() Oliver Upton
2024-01-24 20:49 ` [PATCH 09/15] KVM: arm64: vgic: Ensure the irq refcount is nonzero when taking a ref Oliver Upton
2024-01-25 10:08   ` Marc Zyngier
2024-01-24 20:49 ` [PATCH 10/15] KVM: arm64: vgic: Don't acquire the lpi_list_lock in vgic_put_irq() Oliver Upton
2024-01-24 20:49 ` [PATCH 11/15] KVM: arm64: vgic-its: Lazily allocate LPI translation cache Oliver Upton
2024-01-25 10:19   ` Marc Zyngier
2024-01-25 15:13     ` Oliver Upton
2024-01-24 20:49 ` [PATCH 12/15] KVM: arm64: vgic-its: Pick cache victim based on usage count Oliver Upton
2024-01-25  9:22   ` Oliver Upton
2024-01-25 10:55   ` Marc Zyngier [this message]
2024-01-25 15:34     ` Oliver Upton
2024-01-25 18:07       ` Marc Zyngier
2024-01-24 20:49 ` [PATCH 13/15] KVM: arm64: vgic-its: Protect cached vgic_irq pointers with RCU Oliver Upton
2024-01-29  1:03   ` kernel test robot
2024-01-24 20:49 ` [PATCH 14/15] KVM: arm64: vgic-its: Treat the LPI translation cache as an rculist Oliver Upton
2024-01-24 20:49 ` [PATCH 15/15] KVM: arm64: vgic-its: Rely on RCU to protect translation cache reads Oliver Upton
2024-01-25 11:02 ` [PATCH 00/15] KVM: arm64: Improvements to GICv3 LPI injection Marc Zyngier
2024-01-25 15:47   ` Oliver Upton

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=861qa58yy0.wl-maz@kernel.org \
    --to=maz@kernel.org \
    --cc=james.morse@arm.com \
    --cc=jingzhangos@google.com \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=oliver.upton@linux.dev \
    --cc=rananta@google.com \
    --cc=suzuki.poulose@arm.com \
    --cc=yuzenghui@huawei.com \
    /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.