Received: by 10.223.176.5 with SMTP id f5csp1226114wra; Fri, 9 Feb 2018 15:08:19 -0800 (PST) X-Google-Smtp-Source: AH8x224UpNUtYGmyx+NDl9aqVKORyylxBGf5X3X/9qzHuE61/u/q+tcg0DA4wOiUJE09jbw+6Uc4 X-Received: by 10.99.164.25 with SMTP id c25mr3637001pgf.308.1518217699843; Fri, 09 Feb 2018 15:08:19 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1518217699; cv=none; d=google.com; s=arc-20160816; b=Qp8Rj0TLvWS4lqDjeHTdv2YQcJNQt8nnqdtwELkSuhfxtqnr5pY6IbOaHJF9rTc+kP WrVzm+idccuwIqLQgM1xRdWTIO1CnsychBbSENPesD+pjoPjYQtcVo9rewbd1TYbLC+m kqipPNKEptkjv2uUJl2HuFiRD9Dnec2GPRShljol70zZNP6KS+KcSOiuA2big7oloKJ6 mucQTBuS8ldr4zcnTVAizGVG64Zj3tj9gEGdFNjCxtZcOYPHIjYK1R3nZk0aAvmfYb0z oHyFWC1X03DyZtYw572obnaGvUpKaN9mWXRdva0j9tnc2XUU4WVtb/kZvlh0QdaglFuU 3Alg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:date:subject:cc:to:from :dmarc-filter:dkim-signature:dkim-signature :arc-authentication-results; bh=T0m4hvsafyrLAD6K7uHmAb6wmfPSR3cc0xB/afZg04U=; b=PhuDWHwfcFp3OpJ4Rzn/N7mFIHpaIgh/Vn+reTKlQFqhWbrHAoHGgfCZ+00gX0Uryb Pmn/smtUUmG8vHXmQlQzIGRVqhEP9/NJVqZMUsmQ6W0fI0aLUItfk7zSHI/C4AIqJI1M GPWx2E84Zsq9zGiXt1p8qRcb6T4FMPQDv6bmVAYvm8yFdOI0ISE22qeQJKZr/+johChB g0pUPctXxl0a+6oq2pDZQJO8TGp/gQSDlePKAVjiwDNHYPex/re9rRUftxaAnFYxyYCu QWGBsmvsbEE9ZAIiAB8TuDdrB3URFedQqUEqR67uv6/qnik+HdEsm4x6XbSaYWC8ZivI tE2Q== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@codeaurora.org header.s=default header.b=Z+iKi4lL; dkim=pass header.i=@codeaurora.org header.s=default header.b=N10dbMxK; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l14si20599pgc.506.2018.02.09.15.07.59; Fri, 09 Feb 2018 15:08:19 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@codeaurora.org header.s=default header.b=Z+iKi4lL; dkim=pass header.i=@codeaurora.org header.s=default header.b=N10dbMxK; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753142AbeBIXHU (ORCPT + 99 others); Fri, 9 Feb 2018 18:07:20 -0500 Received: from smtp.codeaurora.org ([198.145.29.96]:40048 "EHLO smtp.codeaurora.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752521AbeBIXHT (ORCPT ); Fri, 9 Feb 2018 18:07:19 -0500 Received: by smtp.codeaurora.org (Postfix, from userid 1000) id 7B7326022B; Fri, 9 Feb 2018 23:07:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1518217638; bh=L56GtVhMNhcoj3WfACa4nWn+ljPXQa8+Gz3MbqlzFvQ=; h=From:To:Cc:Subject:Date:From; b=Z+iKi4lLVFaNYwx70JQj9a59GHdqgozfcWr7MqVBrLwIdaY8jiMo8B7dtr0aRg6Zi lEk0SeoGjp6CxMm4qwJslSxkf6WeD9mENP8PA2SZJu8GB5kbikF5JRnxdLCYHbfqq7 fFkMb7OX0RtT5GicWaXpGspwVcSyT3cQcQ+vbjqg= X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on pdx-caf-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.8 required=2.0 tests=ALL_TRUSTED,BAYES_00, DKIM_SIGNED,T_DKIM_INVALID autolearn=no autolearn_force=no version=3.4.0 Received: from rananta-linux.qualcomm.com (i-global254.qualcomm.com [199.106.103.254]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA256 (128/128 bits)) (No client certificate requested) (Authenticated sender: rananta@smtp.codeaurora.org) by smtp.codeaurora.org (Postfix) with ESMTPSA id 1038F6022B; Fri, 9 Feb 2018 23:07:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=codeaurora.org; s=default; t=1518217637; bh=L56GtVhMNhcoj3WfACa4nWn+ljPXQa8+Gz3MbqlzFvQ=; h=From:To:Cc:Subject:Date:From; b=N10dbMxKfERezsTRttxWBNvMdLfs0MGKkEqn2Gx8EX+hI/gcQ8XlEAsM+NumteIef K6pyrBJ2GNQu5vdiL7/9z9dYkaNUpOtdxdrIDVj4vuW4/O2LXRveHmlXipKlLHu/Bd ldj51u1BBc/rGtayYOd4Apb44CtAjTCyGSdHFOKU= DMARC-Filter: OpenDMARC Filter v1.3.2 smtp.codeaurora.org 1038F6022B Authentication-Results: pdx-caf-mail.web.codeaurora.org; dmarc=none (p=none dis=none) header.from=codeaurora.org Authentication-Results: pdx-caf-mail.web.codeaurora.org; spf=none smtp.mailfrom=rananta@codeaurora.org From: Raghavendra Rao Ananta To: peterz@infradead.org, mingo@redhat.com, acme@kernel.org, alexander.shishkin@linux.intel.com, jolsa@redhat.com, namhyung@kernel.org Cc: linux-kernel@vger.kernel.org, psodagud@codeaurora.org, tsoni@codeaurora.org, rananta@codeaurora.org Subject: [PATCH] perf: Add support for creating offline events Date: Fri, 9 Feb 2018 15:07:00 -0800 Message-Id: <1518217620-28458-1-git-send-email-rananta@codeaurora.org> X-Mailer: git-send-email 1.9.1 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Perf framework doesn't allow creation of hardware events if the requested CPU is offline. However, creation of an event is achievable if the event is attached to the PMU as soon as the CPU is online again. So, introducing a feature that could allow to create events even when the CPU is offline and return a success to the caller. If, during the time of event creation, the CPU is found offline, the event is moved to a new state (PERF_EVENT_STATE_DORMANT). As and when the CPU is know to be woken up (through hotplug notifiers), all the dormant events would be attached to the PMU (by perf_install_in_context()). If during the life time of the event, the CPU hasn't come online, the dormant event would just be freed. Signed-off-by: Raghavendra Rao Ananta --- include/linux/perf_event.h | 7 +++ kernel/events/core.c | 109 ++++++++++++++++++++++++++++++++------------- 2 files changed, 84 insertions(+), 32 deletions(-) diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 7546822..bc07f16 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -489,6 +489,7 @@ struct perf_addr_filters_head { * enum perf_event_state - the states of a event */ enum perf_event_state { + PERF_EVENT_STATE_DORMANT = -5, PERF_EVENT_STATE_DEAD = -4, PERF_EVENT_STATE_EXIT = -3, PERF_EVENT_STATE_ERROR = -2, @@ -687,6 +688,12 @@ struct perf_event { #endif struct list_head sb_list; + + /* Entry into the list that holds the events whose CPUs + * are offline. These events will be removed from the + * list and installed once the CPU wakes up. + */ + struct list_head dormant_entry; #endif /* CONFIG_PERF_EVENTS */ }; diff --git a/kernel/events/core.c b/kernel/events/core.c index f0549e7..66dbccb 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -2329,6 +2329,19 @@ static int __perf_install_in_context(void *info) return ret; } +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE +static LIST_HEAD(dormant_event_list); +static DEFINE_SPINLOCK(dormant_event_list_lock); + +static void perf_prepare_install_in_context(struct perf_event *event) +{ + spin_lock(&dormant_event_list_lock); + event->state = PERF_EVENT_STATE_DORMANT; + list_add_tail(&event->dormant_entry, &dormant_event_list); + spin_unlock(&dormant_event_list_lock); +} +#endif + /* * Attach a performance event to a context. * @@ -2353,6 +2366,15 @@ static int __perf_install_in_context(void *info) smp_store_release(&event->ctx, ctx); if (!task) { +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE + struct perf_cpu_context *cpuctx = + container_of(ctx, struct perf_cpu_context, ctx); + + if (!cpuctx->online) { + perf_prepare_install_in_context(event); + return; + } +#endif cpu_function_call(cpu, __perf_install_in_context, event); return; } @@ -2421,6 +2443,43 @@ static int __perf_install_in_context(void *info) raw_spin_unlock_irq(&ctx->lock); } +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE +static void perf_deferred_install_in_context(int cpu) +{ + struct perf_event *event, *tmp; + struct perf_event_context *ctx; + + /* This function is called twice while coming online. Once for + * CPUHP_PERF_PREPARE and the other for CPUHP_AP_PERF_ONLINE. + * Only during the CPUHP_AP_PERF_ONLINE state, we can confirm + * that CPU PMU is ready and can be installed to. + */ + if (!cpu_online(cpu)) + return; + + spin_lock(&dormant_event_list_lock); + list_for_each_entry_safe(event, tmp, &dormant_event_list, + dormant_entry) { + if (cpu != event->cpu) + continue; + + list_del(&event->dormant_entry); + event->state = PERF_EVENT_STATE_INACTIVE; + spin_unlock(&dormant_event_list_lock); + + ctx = event->ctx; + perf_event__state_init(event); + + mutex_lock(&ctx->mutex); + perf_install_in_context(ctx, event, cpu); + mutex_unlock(&ctx->mutex); + + spin_lock(&dormant_event_list_lock); + } + spin_unlock(&dormant_event_list_lock); +} +#endif + /* * Cross CPU call to enable a performance event */ @@ -4202,6 +4261,13 @@ int perf_event_release_kernel(struct perf_event *event) struct perf_event *child, *tmp; LIST_HEAD(free_list); +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE + spin_lock(&dormant_event_list_lock); + if (event->state == PERF_EVENT_STATE_DORMANT) + list_del(&event->dormant_entry); + spin_unlock(&dormant_event_list_lock); +#endif + /* * If we got here through err_file: fput(event_file); we will not have * attached to a context yet. @@ -4513,6 +4579,15 @@ static bool is_event_hup(struct perf_event *event) struct perf_event_context *ctx; int ret; +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE + spin_lock(&dormant_event_list_lock); + if (event->state == PERF_EVENT_STATE_DORMANT) { + spin_unlock(&dormant_event_list_lock); + return 0; + } + spin_unlock(&dormant_event_list_lock); +#endif + ctx = perf_event_ctx_lock(event); ret = __perf_read(event, buf, count); perf_event_ctx_unlock(event, ctx); @@ -10161,23 +10236,6 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id) goto err_locked; } - if (!task) { - /* - * Check if the @cpu we're creating an event for is online. - * - * We use the perf_cpu_context::ctx::mutex to serialize against - * the hotplug notifiers. See perf_event_{init,exit}_cpu(). - */ - struct perf_cpu_context *cpuctx = - container_of(ctx, struct perf_cpu_context, ctx); - - if (!cpuctx->online) { - err = -ENODEV; - goto err_locked; - } - } - - /* * Must be under the same ctx::mutex as perf_install_in_context(), * because we need to serialize with concurrent event creation. @@ -10354,21 +10412,6 @@ struct perf_event * goto err_unlock; } - if (!task) { - /* - * Check if the @cpu we're creating an event for is online. - * - * We use the perf_cpu_context::ctx::mutex to serialize against - * the hotplug notifiers. See perf_event_{init,exit}_cpu(). - */ - struct perf_cpu_context *cpuctx = - container_of(ctx, struct perf_cpu_context, ctx); - if (!cpuctx->online) { - err = -ENODEV; - goto err_unlock; - } - } - if (!exclusive_event_installable(event, ctx)) { err = -EBUSY; goto err_unlock; @@ -11141,6 +11184,8 @@ int perf_event_init_cpu(unsigned int cpu) } mutex_unlock(&pmus_lock); + perf_deferred_install_in_context(cpu); + return 0; } -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project