From: Sean Christopherson <seanjc@google.com>
To: Aaron Lewis <aaronlewis@google.com>
Cc: kvm@vger.kernel.org, pbonzini@redhat.com, jmattson@google.com
Subject: Re: [PATCH v5 4/7] kvm: x86/pmu: Introduce masked events to the pmu event filter
Date: Mon, 10 Oct 2022 15:42:28 +0000 [thread overview]
Message-ID: <Y0Q9ZFGQf1On/Cus@google.com> (raw)
In-Reply-To: <20220920174603.302510-5-aaronlewis@google.com>
On Tue, Sep 20, 2022, Aaron Lewis wrote:
> static void convert_to_filter_events(struct kvm_pmu_event_filter *filter)
> @@ -645,7 +719,34 @@ static void convert_to_filter_events(struct kvm_pmu_event_filter *filter)
> for (i = 0; i < filter->nevents; i++) {
> u64 e = filter->events[i];
>
> - filter->events[i] = encode_filter_entry(e);
> + filter->events[i] = encode_filter_entry(e, filter->flags);
> + }
> +}
> +
> +/*
> + * Sort will order the list by exclude, then event select. This function will
> + * then index the sublists of event selects such that when a search is done on
> + * the list, the head of the event select sublist is returned. This simplifies
> + * the logic in filter_contains_match() when walking the list.
I'm not so sure that this is simpler overall though. If inclusive vs. exclusive
are separate lists, then avoiding "index" would mean there's no need to convert
entries. And IIUC, the only thing this saves in filter_contains_match() is
having to walk backwards, e.g. it's
for (i = index; i < filter->nevents; i++) {
if (!<eventsel event match>)
break;
if (is_filter_match(...))
return true;
}
return false;
versus
for (i = index; i < filter->nevents; i++) {
if (filter_event_cmp(eventsel, filter->events[i]))
break;
if (is_filter_match(eventsel, filter->events[i]))
return true;
}
for (i = index - 1; i > 0; i--) {
if (filter_event_cmp(eventsel, filter->events[i]))
break;
if (is_filter_match(eventsel, filter->events[i]))
return true;
}
return false;
It's definitely _more_ code in filter_contains_match(), and the duplicate code is
unfortunate, but I wouldn't necessarily say it's simpler. There's a fair bit of
complexity in understanding the indexing scheme, it's just hidden.
And I believe if the indexing is dropped, then the same filter_event_cmp() helper
can be used for sort() and bsearch(), and for bounding the walks.
And here's also no need to "encode" entries or use a second struct overly.
We might need separate logic for the existing non-masked mechanism, but again
that's only more code, IMO it's not more complex. E.g. I believe that the legacy
case can be handled with a dedicated:
if (!(filter->flags & KVM_PMU_EVENT_FLAG_MASKED_EVENTS))
return find_filter_index(..., cmp_u64) > 0;
Oh, and as a bonus of splitting include vs. exclude, the legacy case effectively
optimizes exclude since the length of the exclude array will be '0'.
If we do keep the indexing, I think we should rename "index" to "head", e.g. like
"head pages", to make it more obvious that the helper returns the head of a list.
> + */
> +static void index_filter_events(struct kvm_pmu_event_filter *filter)
> +{
> + struct kvm_pmu_filter_entry *prev, *curr;
> + int i, index = 0;
> +
> + if (filter->nevents)
> + prev = (struct kvm_pmu_filter_entry *)(filter->events);
> +
> + for (i = 0; i < filter->nevents; i++) {
> + curr = (struct kvm_pmu_filter_entry *)(&filter->events[i]);
> +
> + if (curr->event_select != prev->event_select ||
> + curr->exclude != prev->exclude) {
> + index = 0;
> + prev = curr;
> + }
> +
> + curr->event_index = index++;
> }
> }
> + * When filter events are converted into this format then sorted, the
> + * resulting list naturally ends up in two sublists. One for the 'include
> + * list' and one for the 'exclude list'. These sublists are further broken
> + * down into sublists ordered by their event select. After that, the
> + * event select sublists are indexed such that a search for: exclude = n,
> + * event_select = n, and event_index = 0 will return the head of an event
> + * select sublist that can be walked to see if a match exists.
> + */
> struct kvm_pmu_filter_entry {
> union {
> u64 raw;
> struct {
> + u64 mask:8;
> + u64 match:8;
> + u64 event_index:12;
This is broken. There are 2^12 possible event_select values, but event_index is
the index into the full list of events, i.e. is bounded only by nevents, and so
this needs to be stored as a 32-bit value. E.g. if userspace creates a filter
with 2^32-2 entries for eventsel==0, then the index for eventsel==1 will be
2^32-1 even though there are only two event_select values in the entire list.
> u64 event_select:12;
> - u64 unit_mask:8;
> - u64 rsvd:44;
> + u64 exclude:1;
> + u64 rsvd:23;
> };
> };
> };
next prev parent reply other threads:[~2022-10-10 15:42 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-09-20 17:45 [PATCH v5 0/7] Introduce and test masked events Aaron Lewis
2022-09-20 17:45 ` [PATCH v5 1/7] kvm: x86/pmu: Correct the mask used in a pmu event filter lookup Aaron Lewis
2022-10-07 23:25 ` Sean Christopherson
2022-10-15 15:43 ` Aaron Lewis
2022-10-17 18:20 ` Sean Christopherson
2022-10-21 1:33 ` Aaron Lewis
2022-09-20 17:45 ` [PATCH v5 2/7] kvm: x86/pmu: Remove invalid raw events from the pmu event filter Aaron Lewis
2022-10-07 23:48 ` Sean Christopherson
2022-09-20 17:45 ` [PATCH v5 3/7] kvm: x86/pmu: prepare the pmu event filter for masked events Aaron Lewis
2022-10-08 0:08 ` Sean Christopherson
2022-09-20 17:46 ` [PATCH v5 4/7] kvm: x86/pmu: Introduce masked events to the pmu event filter Aaron Lewis
2022-10-08 0:37 ` Sean Christopherson
2022-10-10 15:42 ` Sean Christopherson [this message]
2022-10-15 15:43 ` Aaron Lewis
2022-10-17 17:47 ` Sean Christopherson
2022-10-19 1:06 ` Aaron Lewis
2022-10-21 1:33 ` Aaron Lewis
2022-10-21 17:50 ` Sean Christopherson
2022-09-20 17:46 ` [PATCH v5 5/7] selftests: kvm/x86: Add flags when creating a " Aaron Lewis
2022-09-20 17:46 ` [PATCH v5 6/7] selftests: kvm/x86: Add testing for KVM_SET_PMU_EVENT_FILTER Aaron Lewis
2022-09-20 17:56 ` Jim Mattson
2022-09-20 17:46 ` [PATCH v5 7/7] selftests: kvm/x86: Test masked events Aaron Lewis
2022-09-20 17:59 ` Jim Mattson
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=Y0Q9ZFGQf1On/Cus@google.com \
--to=seanjc@google.com \
--cc=aaronlewis@google.com \
--cc=jmattson@google.com \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).