Re: [PATCH v8] perf: Sharing PMU counters across compatible events

Song Liu
2019-12-12T15:18:21Z

> On Dec 12, 2019, at 5:42 AM, Peter Zijlstra <peterz@infradead.org> wrote:
>
> On Fri, Dec 06, 2019 at 04:24:47PM -0800, Song Liu wrote:
>> +/* Remove dup_master for the event */
>> +static void perf_event_remove_dup(struct perf_event *event,
>> + struct perf_event_context *ctx)
>> +
>> +{
>> + struct perf_event *tmp, *new_master;
>> + int count;
>> +
>> + /* no sharing */
>> + if (!event->dup_master)
>> + return;
>> +
>> + WARN_ON_ONCE(event->state != PERF_EVENT_STATE_INACTIVE &&
>> + event->state != PERF_EVENT_STATE_OFF);
>> +
>> + /* this event is not the master */
>> + if (event->dup_master != event) {
>> + event->dup_master = NULL;
>> + return;
>> + }
>> +
>> + /* this event is the master */
>> + perf_event_exit_dup_master(event);
>> +
>> + count = 0;
>> + new_master = NULL;
>> + list_for_each_entry(tmp, &ctx->event_list, event_entry) {
>> + WARN_ON_ONCE(tmp->state > PERF_EVENT_STATE_INACTIVE);
>> + if (tmp->dup_master == event) {
>> + count++;
>> + if (!new_master)
>> + new_master = tmp;
>> + }
>> + }
>> +
>> + if (!count)
>> + return;
>> +
>> + if (count == 1) {
>> + /* no more sharing */
>> + new_master->dup_master = NULL;
>> + return;
>> + }
>> +
>> + perf_event_init_dup_master(new_master);
>> +
>> + /* switch to new_master */
>> + list_for_each_entry(tmp, &ctx->event_list, event_entry)
>> + if (tmp->dup_master == event)
>> + tmp->dup_master = new_master;
>> +}
>
> I'm thinking you can do that in a single iteration:
>
> list_for_each_entry(tmp, &ctx->event_list, event_entry) {
> if (tmp->dup_master != event)
> continue;
>
> if (!new_master)
> new_master = tmp;
>
> tmp->dup_master = new_master;
> count++;
> }
>
> if (count == 1)
> new_master->dup_master = NULL;
> else
> perf_event_init_dup_master(new_master);
>
> Hmm?

This should work. Let me fix in v9.

Thanks,
Song