* [PATCH V2 0/1] perf: Add CPU hotplug support for events
@ 2019-05-31 13:39 Mukesh Ojha
2019-05-31 13:39 ` [PATCH V2 1/1] perf: event preserve and create across cpu hotplug Mukesh Ojha
0 siblings, 1 reply; 13+ messages in thread
From: Mukesh Ojha @ 2019-05-31 13:39 UTC (permalink / raw)
To: linux-kernel; +Cc: Mukesh Ojha
The embedded world, specifically Android mobile SoCs, rely on CPU
hotplugs to manage power and thermal constraints. These hotplugs
can happen at a very rapid pace. Adjacently, they also relies on
many perf event counters for its management. Therefore, there is
a need to preserve these events across hotplugs.
In such a scenario, a perf client (kernel or user-space) can create
events even when the CPU is offline. If the CPU comes online during
the lifetime of the event, the registered event can start counting
spontaneously. As an extension to this, the events' count can also
be preserved across CPU hotplugs. This takes the burden off of the
clients to monitor the state of the CPU.
The tests were conducted on arm64 device.
/* CPU-1 is offline: Event created when CPU1 is offline */
/ # cat /sys/devices/system/cpu/cpu1/online
1
/ # echo 0 > /sys/devices/system/cpu/cpu1/online
Test used for testing
#!/bin/sh
chmod +x *
# Count the cycles events on cpu-1 for every 200 ms
./perf stat -e cycles -I 200 -C 1 &
# Make the CPU-1 offline and online continuously
while true; do
sleep 2
echo 0 > /sys/devices/system/cpu/cpu1/online
sleep 2
echo 1 > /sys/devices/system/cpu/cpu1/online
done
Results:
/ # ./test.sh
# time counts unit events
0.200145885 <not counted> cycles
0.410115208 <not counted> cycles
0.619922551 <not counted> cycles
0.829904635 <not counted> cycles
1.039751614 <not counted> cycles
1.249547603 <not counted> cycles
1.459228280 <not counted> cycles
1.665606561 <not counted> cycles
1.874981926 <not counted> cycles
2.084297811 <not counted> cycles
2.293471249 <not counted> cycles
2.503231561 <not counted> cycles
2.712993332 <not counted> cycles
2.922744478 <not counted> cycles
3.132502186 <not counted> cycles
3.342255050 <not counted> cycles
3.552010102 <not counted> cycles
3.761760363 <not counted> cycles
/* CPU-1 made online: Event started counting */
3.971459269 1925429 cycles
4.181325206 19391145 cycles
4.391074164 113894 cycles
4.599130519 3150152 cycles
4.805564737 487122 cycles
5.015164581 247533 cycles
5.224764529 103622 cycles
# time counts unit events
5.434360831 238179 cycles
5.645293799 238895 cycles
5.854909320 367543 cycles
6.064487966 2383428 cycles
/* CPU-1 made offline: counting stopped
6.274289476 <not counted> cycles
6.483493903 <not counted> cycles
6.693202705 <not counted> cycles
6.902956195 <not counted> cycles
7.112714268 <not counted> cycles
7.322465570 <not counted> cycles
7.532222340 <not counted> cycles
7.741975830 <not counted> cycles
7.951686246 <not counted> cycles
/* CPU-1 made online: Event started counting
8.161469892 22040750 cycles
8.371219528 114977 cycles
8.580979111 259952 cycles
8.790757132 444661 cycles
9.000559215 248512 cycles
9.210385256 246590 cycles
9.420187704 243819 cycles
9.630052287 7102438 cycles
9.839848225 337454 cycles
10.049645048 644072 cycles
10.259476246 1855410 cycles
Mukesh Ojha (1):
perf: event preserve and create across cpu hotplug
include/linux/perf_event.h | 1 +
kernel/events/core.c | 122 +++++++++++++++++++++++++++++----------------
2 files changed, 79 insertions(+), 44 deletions(-)
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center,
Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V2 1/1] perf: event preserve and create across cpu hotplug
2019-05-31 13:39 [PATCH V2 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
@ 2019-05-31 13:39 ` Mukesh Ojha
2019-06-03 17:53 ` Jiri Olsa
2019-06-12 10:57 ` [PATCH V3] " Mukesh Ojha
0 siblings, 2 replies; 13+ messages in thread
From: Mukesh Ojha @ 2019-05-31 13:39 UTC (permalink / raw)
To: linux-kernel
Cc: Mukesh Ojha, Raghavendra Rao Ananta, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Alexander Shishkin, Jiri Olsa,
Alexei Starovoitov
Perf framework doesn't allow preserving CPU events across
CPU hotplugs. The events are scheduled out as and when the
CPU walks offline. Moreover, the framework also doesn't
allow the clients to create events on an offline CPU. As
a result, the clients have to keep on monitoring the CPU
state until it comes back online.
Therefore, introducing the perf framework to support creation
and preserving of (CPU) events for offline CPUs. Through
this, the CPU's online state would be transparent to the
client and it not have to worry about monitoring the CPU's
state. Success would be returned to the client even while
creating the event on an offline CPU. If during the lifetime
of the event the CPU walks offline, the event would be
preserved and would continue to count as soon as (and if) the
CPU comes back online.
Co-authored-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
---
Change in V2:
As per long back discussion happened at
https://lkml.org/lkml/2018/2/15/1324
Peter.Z. has suggested to do thing in different way and shared
patch as well. This patch fixes the issue seen while trying
to achieve the purpose.
Fixed issue on top of Peter's patch:
===================================
1. Added a NULL check on task to avoid crash in __perf_install_in_context.
2. while trying to add event to context when cpu is offline.
Inside add_event_to_ctx() to make consistent state machine while hotplug.
-event->state += PERF_EVENT_STATE_HOTPLUG_OFFSET;
+event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
3. In event_function_call(), added a label 'remove_event_from_ctx' to
delete events from context list while cpu is offline.
include/linux/perf_event.h | 1 +
kernel/events/core.c | 119 ++++++++++++++++++++++++++++-----------------
2 files changed, 76 insertions(+), 44 deletions(-)
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index e47ef76..31a3a5d 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -510,6 +510,7 @@ enum perf_event_state {
PERF_EVENT_STATE_OFF = -1,
PERF_EVENT_STATE_INACTIVE = 0,
PERF_EVENT_STATE_ACTIVE = 1,
+ PERF_EVENT_STATE_HOTPLUG_OFFSET = -32,
};
struct file;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 72d06e30..fbfffca 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -264,17 +264,18 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
lockdep_assert_held(&ctx->mutex);
}
- if (!task) {
- cpu_function_call(event->cpu, event_function, &efs);
- return;
- }
-
if (task == TASK_TOMBSTONE)
return;
again:
- if (!task_function_call(task, event_function, &efs))
- return;
+ if (task) {
+ if (!task_function_call(task, event_function, &efs))
+ return;
+ } else {
+ if (!cpu_function_call(event->cpu, event_function, &efs))
+ return;
+ }
+
raw_spin_lock_irq(&ctx->lock);
/*
@@ -286,10 +287,16 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
raw_spin_unlock_irq(&ctx->lock);
return;
}
+
+ if (!task)
+ goto remove_event_from_ctx;
+
if (ctx->is_active) {
raw_spin_unlock_irq(&ctx->lock);
goto again;
}
+
+remove_event_from_ctx:
func(event, NULL, ctx, data);
raw_spin_unlock_irq(&ctx->lock);
}
@@ -2309,7 +2316,7 @@ static void perf_set_shadow_time(struct perf_event *event,
struct perf_event *event, *partial_group = NULL;
struct pmu *pmu = ctx->pmu;
- if (group_event->state == PERF_EVENT_STATE_OFF)
+ if (group_event->state <= PERF_EVENT_STATE_OFF)
return 0;
pmu->start_txn(pmu, PERF_PMU_TXN_ADD);
@@ -2388,6 +2395,14 @@ static int group_can_go_on(struct perf_event *event,
static void add_event_to_ctx(struct perf_event *event,
struct perf_event_context *ctx)
{
+ if (!ctx->task) {
+ struct perf_cpu_context *cpuctx =
+ container_of(ctx, struct perf_cpu_context, ctx);
+
+ if (!cpuctx->online)
+ event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
+ }
+
list_add_event(event, ctx);
perf_group_attach(event);
}
@@ -2565,11 +2580,6 @@ static int __perf_install_in_context(void *info)
*/
smp_store_release(&event->ctx, ctx);
- if (!task) {
- cpu_function_call(cpu, __perf_install_in_context, event);
- return;
- }
-
/*
* Should not happen, we validate the ctx is still alive before calling.
*/
@@ -2608,8 +2618,14 @@ static int __perf_install_in_context(void *info)
*/
smp_mb();
again:
- if (!task_function_call(task, __perf_install_in_context, event))
- return;
+
+ if (task) {
+ if (!task_function_call(task, __perf_install_in_context, event))
+ return;
+ } else {
+ if (!cpu_function_call(cpu, __perf_install_in_context, event))
+ return;
+ }
raw_spin_lock_irq(&ctx->lock);
task = ctx->task;
@@ -2626,7 +2642,7 @@ static int __perf_install_in_context(void *info)
* If the task is not running, ctx->lock will avoid it becoming so,
* thus we can safely install the event.
*/
- if (task_curr(task)) {
+ if (task && task_curr(task)) {
raw_spin_unlock_irq(&ctx->lock);
goto again;
}
@@ -10967,16 +10983,7 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
}
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) {
+ if (!cpu_possible(cpu)) {
err = -ENODEV;
goto err_locked;
}
@@ -11158,15 +11165,7 @@ struct perf_event *
}
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) {
+ if (!cpu_possible(cpu)) {
err = -ENODEV;
goto err_unlock;
}
@@ -11894,17 +11893,48 @@ void perf_swevent_init_cpu(unsigned int cpu)
}
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static void __perf_event_init_cpu_context(void *__info)
+{
+ struct perf_cpu_context *cpuctx = __info;
+ struct perf_event_context *ctx = &cpuctx->ctx;
+ struct perf_event_context *task_ctx = cpuctx->task_ctx;
+ struct perf_event *event;
+
+ perf_ctx_lock(cpuctx, task_ctx);
+ ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+ if (task_ctx)
+ ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
+ perf_event_set_state(event, event->state - PERF_EVENT_STATE_HOTPLUG_OFFSET);
+
+ perf_event_sched_in(cpuctx, task_ctx, current);
+ perf_ctx_unlock(cpuctx, task_ctx);
+}
+
+static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx)
+{
+ smp_call_function_single(cpu, __perf_event_init_cpu_context, cpuctx, 1);
+}
+
static void __perf_event_exit_context(void *__info)
{
- struct perf_event_context *ctx = __info;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = __info;
+ struct perf_event_context *ctx = &cpuctx->ctx;
+ struct perf_event_context *task_ctx = cpuctx->task_ctx;
struct perf_event *event;
- raw_spin_lock(&ctx->lock);
- ctx_sched_out(ctx, cpuctx, EVENT_TIME);
- list_for_each_entry(event, &ctx->event_list, event_entry)
- __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
- raw_spin_unlock(&ctx->lock);
+ perf_ctx_lock(cpuctx, task_ctx);
+ ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+ if (task_ctx)
+ ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
+ perf_event_set_state(event,
+ event->state + PERF_EVENT_STATE_HOTPLUG_OFFSET);
+
+ perf_event_sched_in(cpuctx, task_ctx, current);
+ perf_ctx_unlock(cpuctx, task_ctx);
}
static void perf_event_exit_cpu_context(int cpu)
@@ -11919,7 +11949,7 @@ static void perf_event_exit_cpu_context(int cpu)
ctx = &cpuctx->ctx;
mutex_lock(&ctx->mutex);
- smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
+ smp_call_function_single(cpu, __perf_event_exit_context, cpuctx, 1);
cpuctx->online = 0;
mutex_unlock(&ctx->mutex);
}
@@ -11927,7 +11957,7 @@ static void perf_event_exit_cpu_context(int cpu)
mutex_unlock(&pmus_lock);
}
#else
-
+static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx) { }
static void perf_event_exit_cpu_context(int cpu) { }
#endif
@@ -11948,6 +11978,7 @@ int perf_event_init_cpu(unsigned int cpu)
mutex_lock(&ctx->mutex);
cpuctx->online = 1;
+ _perf_event_init_cpu_context(cpu, cpuctx);
mutex_unlock(&ctx->mutex);
}
mutex_unlock(&pmus_lock);
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center,
Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH V2 1/1] perf: event preserve and create across cpu hotplug
2019-05-31 13:39 ` [PATCH V2 1/1] perf: event preserve and create across cpu hotplug Mukesh Ojha
@ 2019-06-03 17:53 ` Jiri Olsa
2019-06-04 14:09 ` Mukesh Ojha
2019-06-12 10:57 ` [PATCH V3] " Mukesh Ojha
1 sibling, 1 reply; 13+ messages in thread
From: Jiri Olsa @ 2019-06-03 17:53 UTC (permalink / raw)
To: Mukesh Ojha
Cc: linux-kernel, Raghavendra Rao Ananta, Peter Zijlstra,
Ingo Molnar, Arnaldo Carvalho de Melo, Alexander Shishkin,
Alexei Starovoitov
On Fri, May 31, 2019 at 07:09:16PM +0530, Mukesh Ojha wrote:
> Perf framework doesn't allow preserving CPU events across
> CPU hotplugs. The events are scheduled out as and when the
> CPU walks offline. Moreover, the framework also doesn't
> allow the clients to create events on an offline CPU. As
> a result, the clients have to keep on monitoring the CPU
> state until it comes back online.
>
> Therefore, introducing the perf framework to support creation
> and preserving of (CPU) events for offline CPUs. Through
> this, the CPU's online state would be transparent to the
> client and it not have to worry about monitoring the CPU's
> state. Success would be returned to the client even while
> creating the event on an offline CPU. If during the lifetime
> of the event the CPU walks offline, the event would be
> preserved and would continue to count as soon as (and if) the
> CPU comes back online.
>
> Co-authored-by: Peter Zijlstra <peterz@infradead.org>
> Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
> Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Cc: Jiri Olsa <jolsa@redhat.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> ---
> Change in V2:
>
> As per long back discussion happened at
> https://lkml.org/lkml/2018/2/15/1324
>
> Peter.Z. has suggested to do thing in different way and shared
> patch as well. This patch fixes the issue seen while trying
> to achieve the purpose.
>
> Fixed issue on top of Peter's patch:
> ===================================
> 1. Added a NULL check on task to avoid crash in __perf_install_in_context.
>
> 2. while trying to add event to context when cpu is offline.
> Inside add_event_to_ctx() to make consistent state machine while hotplug.
>
> -event->state += PERF_EVENT_STATE_HOTPLUG_OFFSET;
> +event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
>
> 3. In event_function_call(), added a label 'remove_event_from_ctx' to
> delete events from context list while cpu is offline.
>
>
> include/linux/perf_event.h | 1 +
> kernel/events/core.c | 119 ++++++++++++++++++++++++++++-----------------
> 2 files changed, 76 insertions(+), 44 deletions(-)
>
hi,
I got crash on running "perf stat -a" and switching off
one cpu in another terminal via:
"echo 0 > /sys/devices/system/cpu/cpu2/online"
jirka
---
ibm-x3650m4-01 login: [ 554.951780] smpboot: CPU 2 is now offline
[ 554.958301] BUG: kernel NULL pointer dereference, address: 0000000000000168
[ 554.966070] #PF: supervisor read access in kernel mode
[ 554.971802] #PF: error_code(0x0000) - not-present page
[ 554.977532] PGD 0 P4D 0
[ 554.980356] Oops: 0000 [#1] SMP PTI
[ 554.984256] CPU: 9 PID: 4782 Comm: bash Tainted: G W 5.2.0-rc1+ #3
[ 554.992605] Hardware name: IBM System x3650 M4 : -[7915E2G]-/00Y7683, BIOS -[VVE124AUS-1.30]- 11/21/2012
[ 555.003190] RIP: 0010:__perf_remove_from_context+0xcd/0x130
[ 555.009407] Code: 8b 3d 97 51 5f 60 e8 b2 4d ee ff 48 8b 95 b8 00 00 00 48 01 c2 48 2b 95 c0 00 00 00 48 89 85 c0 00 00 00 48 89 95 b8 00 00 00 <49> 8b 9c 24 68 01 00 00 48 85 db 0f 84 43 ff ff ff 65 8b 3d 5b 51
[ 555.030361] RSP: 0018:ffffaea78542fcb8 EFLAGS: 00010002
[ 555.036190] RAX: 0000008136178cad RBX: ffffa0c0f78b0008 RCX: 000000000000001f
[ 555.044151] RDX: 00000080bf70f331 RSI: 0000000040000219 RDI: fffc405d97b9b8a9
[ 555.052112] RBP: ffffa0c0f78b0000 R08: 0000000000000002 R09: 0000000000029500
[ 555.060074] R10: 00078047268106e0 R11: 0000000000000001 R12: 0000000000000000
[ 555.068037] R13: ffffa0bf86a5c000 R14: 0000000000000001 R15: 0000000000000001
[ 555.076000] FS: 00007f0ace1c9740(0000) GS:ffffa0c2f78c0000(0000) knlGS:0000000000000000
[ 555.085029] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 555.091438] CR2: 0000000000000168 CR3: 000000046c908001 CR4: 00000000000606e0
[ 555.099401] Call Trace:
[ 555.102133] ? perf_event_read_event+0x110/0x110
[ 555.107286] ? list_del_event+0x140/0x140
[ 555.111757] event_function_call+0x113/0x130
[ 555.116521] ? list_del_event+0x140/0x140
[ 555.120994] ? perf_event_read_event+0x110/0x110
[ 555.126144] perf_remove_from_context+0x20/0x70
[ 555.131200] perf_event_release_kernel+0x79/0x330
[ 555.136451] hardlockup_detector_perf_cleanup+0x33/0x8d
[ 555.142282] lockup_detector_cleanup+0x16/0x30
[ 555.147241] _cpu_down+0xf3/0x1c0
[ 555.150941] do_cpu_down+0x2c/0x50
[ 555.154737] device_offline+0x81/0xb0
[ 555.158822] online_store+0x4a/0x90
[ 555.162714] kernfs_fop_write+0x116/0x190
[ 555.167188] vfs_write+0xa5/0x1a0
[ 555.170885] ksys_write+0x59/0xd0
[ 555.174583] do_syscall_64+0x55/0x1c0
[ 555.178670] entry_SYSCALL_64_after_hwframe+0x44/0xa9
[ 555.184306] RIP: 0033:0x7f0acd8b1c58
[ 555.188301] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 c5 5a 2d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
[ 555.209261] RSP: 002b:00007ffe3883af68 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[ 555.217709] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f0acd8b1c58
[ 555.225669] RDX: 0000000000000002 RSI: 000055ce3c955780 RDI: 0000000000000001
[ 555.233632] RBP: 000055ce3c955780 R08: 000000000000000a R09: 00007f0acd9433c0
[ 555.241594] R10: 000000000000000a R11: 0000000000000246 R12: 00007f0acdb83780
[ 555.249557] R13: 0000000000000002 R14: 00007f0acdb7e740 R15: 0000000000000002
[ 555.257521] Modules linked in: xt_MASQUERADE nf_nat xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ipt_REJECT nf_reject_ipv4 nft_counter nft_compat tun bridge stp llc nf_tables nfnetlink sunrpc intel_rapl sb_edac x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm ipmi_ssif irqbypass crct10dif_pclmul crc32_pclmul ipmi_si ghash_clmulni_intel cdc_ether usbnet intel_cstate mii intel_uncore ipmi_devintf iTCO_wdt iTCO_vendor_support ipmi_msghandler sg wmi intel_rapl_perf ioatdma i2c_i801 pcspkr lpc_ich xfs libcrc32c sr_mod cdrom sd_mod mgag200 drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm ahci libahci igb crc32c_intel dca drm libata i2c_algo_bit megaraid_sas dm_mirror dm_region_hash dm_log dm_mod
[ 555.329511] CR2: 0000000000000168
[ 555.333218] ---[ end trace f871a38c5e6d1393 ]---
[ 555.338371] RIP: 0010:__perf_remove_from_context+0xcd/0x130
[ 555.344588] Code: 8b 3d 97 51 5f 60 e8 b2 4d ee ff 48 8b 95 b8 00 00 00 48 01 c2 48 2b 95 c0 00 00 00 48 89 85 c0 00 00 00 48 89 95 b8 00 00 00 <49> 8b 9c 24 68 01 00 00 48 85 db 0f 84 43 ff ff ff 65 8b 3d 5b 51
[ 555.365543] RSP: 0018:ffffaea78542fcb8 EFLAGS: 00010002
[ 555.371372] RAX: 0000008136178cad RBX: ffffa0c0f78b0008 RCX: 000000000000001f
[ 555.379334] RDX: 00000080bf70f331 RSI: 0000000040000219 RDI: fffc405d97b9b8a9
[ 555.387294] RBP: ffffa0c0f78b0000 R08: 0000000000000002 R09: 0000000000029500
[ 555.395264] R10: 00078047268106e0 R11: 0000000000000001 R12: 0000000000000000
[ 555.403228] R13: ffffa0bf86a5c000 R14: 0000000000000001 R15: 0000000000000001
[ 555.411189] FS: 00007f0ace1c9740(0000) GS:ffffa0c2f78c0000(0000) knlGS:0000000000000000
[ 555.420219] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 555.426630] CR2: 0000000000000168 CR3: 000000046c908001 CR4: 00000000000606e0
[ 555.434593] Kernel panic - not syncing: Fatal exception
[ 555.471650] Kernel Offset: 0x1e800000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
[ 555.483688] ---[ end Kernel panic - not syncing: Fatal exception ]---
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V2 1/1] perf: event preserve and create across cpu hotplug
2019-06-03 17:53 ` Jiri Olsa
@ 2019-06-04 14:09 ` Mukesh Ojha
0 siblings, 0 replies; 13+ messages in thread
From: Mukesh Ojha @ 2019-06-04 14:09 UTC (permalink / raw)
To: Jiri Olsa
Cc: linux-kernel, Raghavendra Rao Ananta, Peter Zijlstra,
Ingo Molnar, Arnaldo Carvalho de Melo, Alexander Shishkin,
Alexei Starovoitov
On 6/3/2019 11:23 PM, Jiri Olsa wrote:
> On Fri, May 31, 2019 at 07:09:16PM +0530, Mukesh Ojha wrote:
>> Perf framework doesn't allow preserving CPU events across
>> CPU hotplugs. The events are scheduled out as and when the
>> CPU walks offline. Moreover, the framework also doesn't
>> allow the clients to create events on an offline CPU. As
>> a result, the clients have to keep on monitoring the CPU
>> state until it comes back online.
>>
>> Therefore, introducing the perf framework to support creation
>> and preserving of (CPU) events for offline CPUs. Through
>> this, the CPU's online state would be transparent to the
>> client and it not have to worry about monitoring the CPU's
>> state. Success would be returned to the client even while
>> creating the event on an offline CPU. If during the lifetime
>> of the event the CPU walks offline, the event would be
>> preserved and would continue to count as soon as (and if) the
>> CPU comes back online.
>>
>> Co-authored-by: Peter Zijlstra <peterz@infradead.org>
>> Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
>> Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
>> Cc: Peter Zijlstra <peterz@infradead.org>
>> Cc: Ingo Molnar <mingo@redhat.com>
>> Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
>> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
>> Cc: Jiri Olsa <jolsa@redhat.com>
>> Cc: Alexei Starovoitov <ast@kernel.org>
>> ---
>> Change in V2:
>>
>> As per long back discussion happened at
>> https://lkml.org/lkml/2018/2/15/1324
>>
>> Peter.Z. has suggested to do thing in different way and shared
>> patch as well. This patch fixes the issue seen while trying
>> to achieve the purpose.
>>
>> Fixed issue on top of Peter's patch:
>> ===================================
>> 1. Added a NULL check on task to avoid crash in __perf_install_in_context.
>>
>> 2. while trying to add event to context when cpu is offline.
>> Inside add_event_to_ctx() to make consistent state machine while hotplug.
>>
>> -event->state += PERF_EVENT_STATE_HOTPLUG_OFFSET;
>> +event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
>>
>> 3. In event_function_call(), added a label 'remove_event_from_ctx' to
>> delete events from context list while cpu is offline.
>>
>>
>> include/linux/perf_event.h | 1 +
>> kernel/events/core.c | 119 ++++++++++++++++++++++++++++-----------------
>> 2 files changed, 76 insertions(+), 44 deletions(-)
>>
> hi,
> I got crash on running "perf stat -a" and switching off
> one cpu in another terminal via:
> "echo 0 > /sys/devices/system/cpu/cpu2/online"
Thanks Jiri for the testing it.
>
> jirka
>
>
> ---
> ibm-x3650m4-01 login: [ 554.951780] smpboot: CPU 2 is now offline
> [ 554.958301] BUG: kernel NULL pointer dereference, address: 0000000000000168
> [ 554.966070] #PF: supervisor read access in kernel mode
> [ 554.971802] #PF: error_code(0x0000) - not-present page
> [ 554.977532] PGD 0 P4D 0
> [ 554.980356] Oops: 0000 [#1] SMP PTI
> [ 554.984256] CPU: 9 PID: 4782 Comm: bash Tainted: G W 5.2.0-rc1+ #3
> [ 554.992605] Hardware name: IBM System x3650 M4 : -[7915E2G]-/00Y7683, BIOS -[VVE124AUS-1.30]- 11/21/2012
> [ 555.003190] RIP: 0010:__perf_remove_from_context+0xcd/0x130
> [ 555.009407] Code: 8b 3d 97 51 5f 60 e8 b2 4d ee ff 48 8b 95 b8 00 00 00 48 01 c2 48 2b 95 c0 00 00 00 48 89 85 c0 00 00 00 48 89 95 b8 00 00 00 <49> 8b 9c 24 68 01 00 00 48 85 db 0f 84 43 ff ff ff 65 8b 3d 5b 51
> [ 555.030361] RSP: 0018:ffffaea78542fcb8 EFLAGS: 00010002
> [ 555.036190] RAX: 0000008136178cad RBX: ffffa0c0f78b0008 RCX: 000000000000001f
> [ 555.044151] RDX: 00000080bf70f331 RSI: 0000000040000219 RDI: fffc405d97b9b8a9
> [ 555.052112] RBP: ffffa0c0f78b0000 R08: 0000000000000002 R09: 0000000000029500
> [ 555.060074] R10: 00078047268106e0 R11: 0000000000000001 R12: 0000000000000000
> [ 555.068037] R13: ffffa0bf86a5c000 R14: 0000000000000001 R15: 0000000000000001
> [ 555.076000] FS: 00007f0ace1c9740(0000) GS:ffffa0c2f78c0000(0000) knlGS:0000000000000000
> [ 555.085029] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 555.091438] CR2: 0000000000000168 CR3: 000000046c908001 CR4: 00000000000606e0
> [ 555.099401] Call Trace:
> [ 555.102133] ? perf_event_read_event+0x110/0x110
> [ 555.107286] ? list_del_event+0x140/0x140
> [ 555.111757] event_function_call+0x113/0x130
> [ 555.116521] ? list_del_event+0x140/0x140
> [ 555.120994] ? perf_event_read_event+0x110/0x110
> [ 555.126144] perf_remove_from_context+0x20/0x70
> [ 555.131200] perf_event_release_kernel+0x79/0x330
> [ 555.136451] hardlockup_detector_perf_cleanup+0x33/0x8d
Looks like the support for arm64 is missing for
hardlockup_detector_perf_cleanup()
(HAVE_HARDLOCKUP_DETECTOR_PERF/HAVE_PERF_EVENTS_NMI),
i.e why it has passed for me.
Wondering what could have caused this,
lockup_detector_offline_cpu
watchdog_disable
watchdog_nmi_disable
perf_event_disable(event);
Above path might have disabled the event, perf_remove_from_context this
might try to remove event from the context list.
My change only effects when event is destroyed while the offline cpu .
will look more into it .
Thanks,
Mukesh
> [ 555.142282] lockup_detector_cleanup+0x16/0x30
> [ 555.147241] _cpu_down+0xf3/0x1c0
> [ 555.150941] do_cpu_down+0x2c/0x50
> [ 555.154737] device_offline+0x81/0xb0
> [ 555.158822] online_store+0x4a/0x90
> [ 555.162714] kernfs_fop_write+0x116/0x190
> [ 555.167188] vfs_write+0xa5/0x1a0
> [ 555.170885] ksys_write+0x59/0xd0
> [ 555.174583] do_syscall_64+0x55/0x1c0
> [ 555.178670] entry_SYSCALL_64_after_hwframe+0x44/0xa9
> [ 555.184306] RIP: 0033:0x7f0acd8b1c58
> [ 555.188301] Code: 89 02 48 c7 c0 ff ff ff ff eb b3 0f 1f 80 00 00 00 00 f3 0f 1e fa 48 8d 05 c5 5a 2d 00 8b 00 85 c0 75 17 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 58 c3 0f 1f 80 00 00 00 00 41 54 49 89 d4 55
> [ 555.209261] RSP: 002b:00007ffe3883af68 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
> [ 555.217709] RAX: ffffffffffffffda RBX: 0000000000000002 RCX: 00007f0acd8b1c58
> [ 555.225669] RDX: 0000000000000002 RSI: 000055ce3c955780 RDI: 0000000000000001
> [ 555.233632] RBP: 000055ce3c955780 R08: 000000000000000a R09: 00007f0acd9433c0
> [ 555.241594] R10: 000000000000000a R11: 0000000000000246 R12: 00007f0acdb83780
> [ 555.249557] R13: 0000000000000002 R14: 00007f0acdb7e740 R15: 0000000000000002
> [ 555.257521] Modules linked in: xt_MASQUERADE nf_nat xt_conntrack nf_conntrack nf_defrag_ipv6 nf_defrag_ipv4 ipt_REJECT nf_reject_ipv4 nft_counter nft_compat tun bridge stp llc nf_tables nfnetlink sunrpc intel_rapl sb_edac x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm ipmi_ssif irqbypass crct10dif_pclmul crc32_pclmul ipmi_si ghash_clmulni_intel cdc_ether usbnet intel_cstate mii intel_uncore ipmi_devintf iTCO_wdt iTCO_vendor_support ipmi_msghandler sg wmi intel_rapl_perf ioatdma i2c_i801 pcspkr lpc_ich xfs libcrc32c sr_mod cdrom sd_mod mgag200 drm_kms_helper syscopyarea sysfillrect sysimgblt fb_sys_fops ttm ahci libahci igb crc32c_intel dca drm libata i2c_algo_bit megaraid_sas dm_mirror dm_region_hash dm_log dm_mod
> [ 555.329511] CR2: 0000000000000168
> [ 555.333218] ---[ end trace f871a38c5e6d1393 ]---
> [ 555.338371] RIP: 0010:__perf_remove_from_context+0xcd/0x130
> [ 555.344588] Code: 8b 3d 97 51 5f 60 e8 b2 4d ee ff 48 8b 95 b8 00 00 00 48 01 c2 48 2b 95 c0 00 00 00 48 89 85 c0 00 00 00 48 89 95 b8 00 00 00 <49> 8b 9c 24 68 01 00 00 48 85 db 0f 84 43 ff ff ff 65 8b 3d 5b 51
> [ 555.365543] RSP: 0018:ffffaea78542fcb8 EFLAGS: 00010002
> [ 555.371372] RAX: 0000008136178cad RBX: ffffa0c0f78b0008 RCX: 000000000000001f
> [ 555.379334] RDX: 00000080bf70f331 RSI: 0000000040000219 RDI: fffc405d97b9b8a9
> [ 555.387294] RBP: ffffa0c0f78b0000 R08: 0000000000000002 R09: 0000000000029500
> [ 555.395264] R10: 00078047268106e0 R11: 0000000000000001 R12: 0000000000000000
> [ 555.403228] R13: ffffa0bf86a5c000 R14: 0000000000000001 R15: 0000000000000001
> [ 555.411189] FS: 00007f0ace1c9740(0000) GS:ffffa0c2f78c0000(0000) knlGS:0000000000000000
> [ 555.420219] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 555.426630] CR2: 0000000000000168 CR3: 000000046c908001 CR4: 00000000000606e0
> [ 555.434593] Kernel panic - not syncing: Fatal exception
> [ 555.471650] Kernel Offset: 0x1e800000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)
> [ 555.483688] ---[ end Kernel panic - not syncing: Fatal exception ]---
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH V3] perf: event preserve and create across cpu hotplug
2019-05-31 13:39 ` [PATCH V2 1/1] perf: event preserve and create across cpu hotplug Mukesh Ojha
2019-06-03 17:53 ` Jiri Olsa
@ 2019-06-12 10:57 ` Mukesh Ojha
2019-06-18 8:54 ` [PATCH V4] " Mukesh Ojha
1 sibling, 1 reply; 13+ messages in thread
From: Mukesh Ojha @ 2019-06-12 10:57 UTC (permalink / raw)
To: linux-kernel
Cc: Mukesh Ojha, Raghavendra Rao Ananta, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Alexander Shishkin, Jiri Olsa,
Alexei Starovoitov
Perf framework doesn't allow preserving CPU events across
CPU hotplugs. The events are scheduled out as and when the
CPU walks offline. Moreover, the framework also doesn't
allow the clients to create events on an offline CPU. As
a result, the clients have to keep on monitoring the CPU
state until it comes back online.
Therefore, introducing the perf framework to support creation
and preserving of (CPU) events for offline CPUs. Through
this, the CPU's online state would be transparent to the
client and it not have to worry about monitoring the CPU's
state. Success would be returned to the client even while
creating the event on an offline CPU. If during the lifetime
of the event the CPU walks offline, the event would be
preserved and would continue to count as soon as (and if) the
CPU comes back online.
Co-authored-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
---
Change in V3:
- Jiri has tried perf stat -a and removed one of the cpu from the other
terminal. This resulted in a crash. Crash was because in
event_function_call(), we were passing NULL as cpuctx in
func(event, NULL, ctx, data).Fixed it in this patch.
Change in V2:
As per long back discussion happened at
https://lkml.org/lkml/2018/2/15/1324
Peter.Z. has suggested to do thing in different way and shared
patch as well. This patch fixes the issue seen while trying
to achieve the purpose.
Fixed issue on top of Peter's patch:
===================================
1. Added a NULL check on task to avoid crash in __perf_install_in_context.
2. while trying to add event to context when cpu is offline.
Inside add_event_to_ctx() to make consistent state machine while hotplug.
-event->state += PERF_EVENT_STATE_HOTPLUG_OFFSET;
+event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
3. In event_function_call(), added a label 'remove_event_from_ctx' to
delete events from context list while cpu is offline.
include/linux/perf_event.h | 1 +
kernel/events/core.c | 122 ++++++++++++++++++++++++++++-----------------
2 files changed, 78 insertions(+), 45 deletions(-)
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 3dc01cf..52b14b2 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -511,6 +511,7 @@ enum perf_event_state {
PERF_EVENT_STATE_OFF = -1,
PERF_EVENT_STATE_INACTIVE = 0,
PERF_EVENT_STATE_ACTIVE = 1,
+ PERF_EVENT_STATE_HOTPLUG_OFFSET = -32,
};
struct file;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 118ad1a..7f0bd11 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -248,6 +248,7 @@ static int event_function(void *info)
static void event_function_call(struct perf_event *event, event_f func, void *data)
{
struct perf_event_context *ctx = event->ctx;
+ struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
struct task_struct *task = READ_ONCE(ctx->task); /* verified in event_function */
struct event_function_struct efs = {
.event = event,
@@ -264,17 +265,18 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
lockdep_assert_held(&ctx->mutex);
}
- if (!task) {
- cpu_function_call(event->cpu, event_function, &efs);
- return;
- }
-
if (task == TASK_TOMBSTONE)
return;
again:
- if (!task_function_call(task, event_function, &efs))
- return;
+ if (task) {
+ if (!task_function_call(task, event_function, &efs))
+ return;
+ } else {
+ if (!cpu_function_call(event->cpu, event_function, &efs))
+ return;
+ }
+
raw_spin_lock_irq(&ctx->lock);
/*
@@ -286,11 +288,17 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
raw_spin_unlock_irq(&ctx->lock);
return;
}
+
+ if (!task)
+ goto remove_event_from_ctx;
+
if (ctx->is_active) {
raw_spin_unlock_irq(&ctx->lock);
goto again;
}
- func(event, NULL, ctx, data);
+
+remove_event_from_ctx:
+ func(event, cpuctx, ctx, data);
raw_spin_unlock_irq(&ctx->lock);
}
@@ -2310,7 +2318,7 @@ static void perf_set_shadow_time(struct perf_event *event,
struct perf_event *event, *partial_group = NULL;
struct pmu *pmu = ctx->pmu;
- if (group_event->state == PERF_EVENT_STATE_OFF)
+ if (group_event->state <= PERF_EVENT_STATE_OFF)
return 0;
pmu->start_txn(pmu, PERF_PMU_TXN_ADD);
@@ -2389,6 +2397,14 @@ static int group_can_go_on(struct perf_event *event,
static void add_event_to_ctx(struct perf_event *event,
struct perf_event_context *ctx)
{
+ if (!ctx->task) {
+ struct perf_cpu_context *cpuctx =
+ container_of(ctx, struct perf_cpu_context, ctx);
+
+ if (!cpuctx->online)
+ event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
+ }
+
list_add_event(event, ctx);
perf_group_attach(event);
}
@@ -2576,11 +2592,6 @@ static int __perf_install_in_context(void *info)
*/
smp_store_release(&event->ctx, ctx);
- if (!task) {
- cpu_function_call(cpu, __perf_install_in_context, event);
- return;
- }
-
/*
* Should not happen, we validate the ctx is still alive before calling.
*/
@@ -2619,8 +2630,14 @@ static int __perf_install_in_context(void *info)
*/
smp_mb();
again:
- if (!task_function_call(task, __perf_install_in_context, event))
- return;
+
+ if (task) {
+ if (!task_function_call(task, __perf_install_in_context, event))
+ return;
+ } else {
+ if (!cpu_function_call(cpu, __perf_install_in_context, event))
+ return;
+ }
raw_spin_lock_irq(&ctx->lock);
task = ctx->task;
@@ -2637,7 +2654,7 @@ static int __perf_install_in_context(void *info)
* If the task is not running, ctx->lock will avoid it becoming so,
* thus we can safely install the event.
*/
- if (task_curr(task)) {
+ if (task && task_curr(task)) {
raw_spin_unlock_irq(&ctx->lock);
goto again;
}
@@ -11022,16 +11039,7 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
}
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) {
+ if (!cpu_possible(cpu)) {
err = -ENODEV;
goto err_locked;
}
@@ -11213,15 +11221,7 @@ struct perf_event *
}
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) {
+ if (!cpu_possible(cpu)) {
err = -ENODEV;
goto err_unlock;
}
@@ -11949,17 +11949,48 @@ static void perf_swevent_init_cpu(unsigned int cpu)
}
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static void __perf_event_init_cpu_context(void *__info)
+{
+ struct perf_cpu_context *cpuctx = __info;
+ struct perf_event_context *ctx = &cpuctx->ctx;
+ struct perf_event_context *task_ctx = cpuctx->task_ctx;
+ struct perf_event *event;
+
+ perf_ctx_lock(cpuctx, task_ctx);
+ ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+ if (task_ctx)
+ ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
+ perf_event_set_state(event, event->state - PERF_EVENT_STATE_HOTPLUG_OFFSET);
+
+ perf_event_sched_in(cpuctx, task_ctx, current);
+ perf_ctx_unlock(cpuctx, task_ctx);
+}
+
+static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx)
+{
+ smp_call_function_single(cpu, __perf_event_init_cpu_context, cpuctx, 1);
+}
+
static void __perf_event_exit_context(void *__info)
{
- struct perf_event_context *ctx = __info;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = __info;
+ struct perf_event_context *ctx = &cpuctx->ctx;
+ struct perf_event_context *task_ctx = cpuctx->task_ctx;
struct perf_event *event;
- raw_spin_lock(&ctx->lock);
- ctx_sched_out(ctx, cpuctx, EVENT_TIME);
- list_for_each_entry(event, &ctx->event_list, event_entry)
- __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
- raw_spin_unlock(&ctx->lock);
+ perf_ctx_lock(cpuctx, task_ctx);
+ ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+ if (task_ctx)
+ ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
+ perf_event_set_state(event,
+ event->state + PERF_EVENT_STATE_HOTPLUG_OFFSET);
+
+ perf_event_sched_in(cpuctx, task_ctx, current);
+ perf_ctx_unlock(cpuctx, task_ctx);
}
static void perf_event_exit_cpu_context(int cpu)
@@ -11974,7 +12005,7 @@ static void perf_event_exit_cpu_context(int cpu)
ctx = &cpuctx->ctx;
mutex_lock(&ctx->mutex);
- smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
+ smp_call_function_single(cpu, __perf_event_exit_context, cpuctx, 1);
cpuctx->online = 0;
mutex_unlock(&ctx->mutex);
}
@@ -11982,7 +12013,7 @@ static void perf_event_exit_cpu_context(int cpu)
mutex_unlock(&pmus_lock);
}
#else
-
+static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx) { }
static void perf_event_exit_cpu_context(int cpu) { }
#endif
@@ -12003,6 +12034,7 @@ int perf_event_init_cpu(unsigned int cpu)
mutex_lock(&ctx->mutex);
cpuctx->online = 1;
+ _perf_event_init_cpu_context(cpu, cpuctx);
mutex_unlock(&ctx->mutex);
}
mutex_unlock(&pmus_lock);
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center,
Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH V4] perf: event preserve and create across cpu hotplug
2019-06-12 10:57 ` [PATCH V3] " Mukesh Ojha
@ 2019-06-18 8:54 ` Mukesh Ojha
2019-06-18 12:23 ` Peter Zijlstra
2019-06-18 13:46 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
0 siblings, 2 replies; 13+ messages in thread
From: Mukesh Ojha @ 2019-06-18 8:54 UTC (permalink / raw)
To: linux-kernel
Cc: Mukesh Ojha, Raghavendra Rao Ananta, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Alexander Shishkin, Jiri Olsa,
Alexei Starovoitov
Perf framework doesn't allow preserving CPU events across
CPU hotplugs. The events are scheduled out as and when the
CPU walks offline. Moreover, the framework also doesn't
allow the clients to create events on an offline CPU. As
a result, the clients have to keep on monitoring the CPU
state until it comes back online.
Therefore, introducing the perf framework to support creation
and preserving of (CPU) events for offline CPUs. Through
this, the CPU's online state would be transparent to the
client and it not have to worry about monitoring the CPU's
state. Success would be returned to the client even while
creating the event on an offline CPU. If during the lifetime
of the event the CPU walks offline, the event would be
preserved and would continue to count as soon as (and if) the
CPU comes back online.
Co-authored-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
---
Change in V4:
=============
- Released, __get_cpu_context would not be correct way to get the
cpu context of the cpu which is offline, instead use
container_of to get the cpuctx from ctx.
- Changed the goto label name inside event_function_call from
'remove_event_from_context' to 'out'.
Change in V3:
=============
- Jiri has tried perf stat -a and removed one of the cpu from the other
terminal. This resulted in a crash. Crash was because in
event_function_call(), we were passing NULL as cpuctx in
func(event, NULL, ctx, data).Fixed it in this patch.
Change in V2:
=============
As per long back discussion happened at
https://lkml.org/lkml/2018/2/15/1324
Peter.Z. has suggested to do thing in different way and shared
patch as well. This patch fixes the issue seen while trying
to achieve the purpose.
Fixed issue on top of Peter's patch:
===================================
1. Added a NULL check on task to avoid crash in __perf_install_in_context.
2. while trying to add event to context when cpu is offline.
Inside add_event_to_ctx() to make consistent state machine while hotplug.
-event->state += PERF_EVENT_STATE_HOTPLUG_OFFSET;
+event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
3. In event_function_call(), added a label 'remove_event_from_ctx' to
delete events from context list while cpu is offline.
include/linux/perf_event.h | 1 +
kernel/events/core.c | 123 ++++++++++++++++++++++++++++-----------------
2 files changed, 79 insertions(+), 45 deletions(-)
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 3dc01cf..52b14b2 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -511,6 +511,7 @@ enum perf_event_state {
PERF_EVENT_STATE_OFF = -1,
PERF_EVENT_STATE_INACTIVE = 0,
PERF_EVENT_STATE_ACTIVE = 1,
+ PERF_EVENT_STATE_HOTPLUG_OFFSET = -32,
};
struct file;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 118ad1a..82b5106 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -248,6 +248,8 @@ static int event_function(void *info)
static void event_function_call(struct perf_event *event, event_f func, void *data)
{
struct perf_event_context *ctx = event->ctx;
+ struct perf_cpu_context *cpuctx =
+ container_of(ctx, struct perf_cpu_context, ctx);
struct task_struct *task = READ_ONCE(ctx->task); /* verified in event_function */
struct event_function_struct efs = {
.event = event,
@@ -264,17 +266,18 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
lockdep_assert_held(&ctx->mutex);
}
- if (!task) {
- cpu_function_call(event->cpu, event_function, &efs);
- return;
- }
-
if (task == TASK_TOMBSTONE)
return;
again:
- if (!task_function_call(task, event_function, &efs))
- return;
+ if (task) {
+ if (!task_function_call(task, event_function, &efs))
+ return;
+ } else {
+ if (!cpu_function_call(event->cpu, event_function, &efs))
+ return;
+ }
+
raw_spin_lock_irq(&ctx->lock);
/*
@@ -286,11 +289,17 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
raw_spin_unlock_irq(&ctx->lock);
return;
}
+
+ if (!task)
+ goto out;
+
if (ctx->is_active) {
raw_spin_unlock_irq(&ctx->lock);
goto again;
}
- func(event, NULL, ctx, data);
+
+out:
+ func(event, cpuctx, ctx, data);
raw_spin_unlock_irq(&ctx->lock);
}
@@ -2310,7 +2319,7 @@ static void perf_set_shadow_time(struct perf_event *event,
struct perf_event *event, *partial_group = NULL;
struct pmu *pmu = ctx->pmu;
- if (group_event->state == PERF_EVENT_STATE_OFF)
+ if (group_event->state <= PERF_EVENT_STATE_OFF)
return 0;
pmu->start_txn(pmu, PERF_PMU_TXN_ADD);
@@ -2389,6 +2398,14 @@ static int group_can_go_on(struct perf_event *event,
static void add_event_to_ctx(struct perf_event *event,
struct perf_event_context *ctx)
{
+ if (!ctx->task) {
+ struct perf_cpu_context *cpuctx =
+ container_of(ctx, struct perf_cpu_context, ctx);
+
+ if (!cpuctx->online)
+ event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
+ }
+
list_add_event(event, ctx);
perf_group_attach(event);
}
@@ -2576,11 +2593,6 @@ static int __perf_install_in_context(void *info)
*/
smp_store_release(&event->ctx, ctx);
- if (!task) {
- cpu_function_call(cpu, __perf_install_in_context, event);
- return;
- }
-
/*
* Should not happen, we validate the ctx is still alive before calling.
*/
@@ -2619,8 +2631,14 @@ static int __perf_install_in_context(void *info)
*/
smp_mb();
again:
- if (!task_function_call(task, __perf_install_in_context, event))
- return;
+
+ if (task) {
+ if (!task_function_call(task, __perf_install_in_context, event))
+ return;
+ } else {
+ if (!cpu_function_call(cpu, __perf_install_in_context, event))
+ return;
+ }
raw_spin_lock_irq(&ctx->lock);
task = ctx->task;
@@ -2637,7 +2655,7 @@ static int __perf_install_in_context(void *info)
* If the task is not running, ctx->lock will avoid it becoming so,
* thus we can safely install the event.
*/
- if (task_curr(task)) {
+ if (task && task_curr(task)) {
raw_spin_unlock_irq(&ctx->lock);
goto again;
}
@@ -11022,16 +11040,7 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
}
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) {
+ if (!cpu_possible(cpu)) {
err = -ENODEV;
goto err_locked;
}
@@ -11213,15 +11222,7 @@ struct perf_event *
}
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) {
+ if (!cpu_possible(cpu)) {
err = -ENODEV;
goto err_unlock;
}
@@ -11949,17 +11950,48 @@ static void perf_swevent_init_cpu(unsigned int cpu)
}
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static void __perf_event_init_cpu_context(void *__info)
+{
+ struct perf_cpu_context *cpuctx = __info;
+ struct perf_event_context *ctx = &cpuctx->ctx;
+ struct perf_event_context *task_ctx = cpuctx->task_ctx;
+ struct perf_event *event;
+
+ perf_ctx_lock(cpuctx, task_ctx);
+ ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+ if (task_ctx)
+ ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
+ perf_event_set_state(event, event->state - PERF_EVENT_STATE_HOTPLUG_OFFSET);
+
+ perf_event_sched_in(cpuctx, task_ctx, current);
+ perf_ctx_unlock(cpuctx, task_ctx);
+}
+
+static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx)
+{
+ smp_call_function_single(cpu, __perf_event_init_cpu_context, cpuctx, 1);
+}
+
static void __perf_event_exit_context(void *__info)
{
- struct perf_event_context *ctx = __info;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = __info;
+ struct perf_event_context *ctx = &cpuctx->ctx;
+ struct perf_event_context *task_ctx = cpuctx->task_ctx;
struct perf_event *event;
- raw_spin_lock(&ctx->lock);
- ctx_sched_out(ctx, cpuctx, EVENT_TIME);
- list_for_each_entry(event, &ctx->event_list, event_entry)
- __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
- raw_spin_unlock(&ctx->lock);
+ perf_ctx_lock(cpuctx, task_ctx);
+ ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+ if (task_ctx)
+ ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
+ perf_event_set_state(event,
+ event->state + PERF_EVENT_STATE_HOTPLUG_OFFSET);
+
+ perf_event_sched_in(cpuctx, task_ctx, current);
+ perf_ctx_unlock(cpuctx, task_ctx);
}
static void perf_event_exit_cpu_context(int cpu)
@@ -11974,7 +12006,7 @@ static void perf_event_exit_cpu_context(int cpu)
ctx = &cpuctx->ctx;
mutex_lock(&ctx->mutex);
- smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
+ smp_call_function_single(cpu, __perf_event_exit_context, cpuctx, 1);
cpuctx->online = 0;
mutex_unlock(&ctx->mutex);
}
@@ -11982,7 +12014,7 @@ static void perf_event_exit_cpu_context(int cpu)
mutex_unlock(&pmus_lock);
}
#else
-
+static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx) { }
static void perf_event_exit_cpu_context(int cpu) { }
#endif
@@ -12003,6 +12035,7 @@ int perf_event_init_cpu(unsigned int cpu)
mutex_lock(&ctx->mutex);
cpuctx->online = 1;
+ _perf_event_init_cpu_context(cpu, cpuctx);
mutex_unlock(&ctx->mutex);
}
mutex_unlock(&pmus_lock);
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center,
Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH V4] perf: event preserve and create across cpu hotplug
2019-06-18 8:54 ` [PATCH V4] " Mukesh Ojha
@ 2019-06-18 12:23 ` Peter Zijlstra
2019-06-18 13:40 ` Mukesh Ojha
2019-06-18 13:46 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
1 sibling, 1 reply; 13+ messages in thread
From: Peter Zijlstra @ 2019-06-18 12:23 UTC (permalink / raw)
To: Mukesh Ojha
Cc: linux-kernel, Raghavendra Rao Ananta, Ingo Molnar,
Arnaldo Carvalho de Melo, Alexander Shishkin, Jiri Olsa,
Alexei Starovoitov
On Tue, Jun 18, 2019 at 02:24:51PM +0530, Mukesh Ojha wrote:
> Perf framework doesn't allow preserving CPU events across
> CPU hotplugs. The events are scheduled out as and when the
> CPU walks offline. Moreover, the framework also doesn't
> allow the clients to create events on an offline CPU. As
> a result, the clients have to keep on monitoring the CPU
> state until it comes back online.
>
> Therefore,
That's not a therefore. There's a distinct lack of rationale here. Why
do you want this?
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH V4] perf: event preserve and create across cpu hotplug
2019-06-18 12:23 ` Peter Zijlstra
@ 2019-06-18 13:40 ` Mukesh Ojha
0 siblings, 0 replies; 13+ messages in thread
From: Mukesh Ojha @ 2019-06-18 13:40 UTC (permalink / raw)
To: Peter Zijlstra
Cc: linux-kernel, Raghavendra Rao Ananta, Ingo Molnar,
Arnaldo Carvalho de Melo, Alexander Shishkin, Jiri Olsa,
Alexei Starovoitov
On 6/18/2019 5:53 PM, Peter Zijlstra wrote:
> On Tue, Jun 18, 2019 at 02:24:51PM +0530, Mukesh Ojha wrote:
>> Perf framework doesn't allow preserving CPU events across
>> CPU hotplugs. The events are scheduled out as and when the
>> CPU walks offline. Moreover, the framework also doesn't
>> allow the clients to create events on an offline CPU. As
>> a result, the clients have to keep on monitoring the CPU
>> state until it comes back online.
>>
>> Therefore,
> That's not a therefore. There's a distinct lack of rationale here. Why
> do you want this?
Thanks Peter for coming back on this.
Missed to send the coverletter,
https://lkml.org/lkml/2019/5/31/438
Will resend this with coverletter.
Btw, This patch
is based on suggestion given by you on this
https://lkml.org/lkml/2018/2/16/763
Thanks.
Mukesh
Thanks.
Mukesh
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events
2019-06-18 8:54 ` [PATCH V4] " Mukesh Ojha
2019-06-18 12:23 ` Peter Zijlstra
@ 2019-06-18 13:46 ` Mukesh Ojha
2019-06-18 13:46 ` [PATCH RESEND V4 1/1] perf: event preserve and create across cpu hotplug Mukesh Ojha
2019-06-24 9:01 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
1 sibling, 2 replies; 13+ messages in thread
From: Mukesh Ojha @ 2019-06-18 13:46 UTC (permalink / raw)
To: linux-kernel; +Cc: Mukesh Ojha
The embedded world, specifically Android mobile SoCs, rely on CPU
hotplugs to manage power and thermal constraints. These hotplugs
can happen at a very rapid pace. Adjacently, they also relies on
many perf event counters for its management. Therefore, there is
a need to preserve these events across hotplugs.
In such a scenario, a perf client (kernel or user-space) can create
events even when the CPU is offline. If the CPU comes online during
the lifetime of the event, the registered event can start counting
spontaneously. As an extension to this, the events' count can also
be preserved across CPU hotplugs. This takes the burden off of the
clients to monitor the state of the CPU.
The tests were conducted on arm64 device.
/* CPU-1 is offline: Event created when CPU1 is offline */
/ # cat /sys/devices/system/cpu/cpu1/online
1
/ # echo 0 > /sys/devices/system/cpu/cpu1/online
Test used for testing
#!/bin/sh
chmod +x *
# Count the cycles events on cpu-1 for every 200 ms
./perf stat -e cycles -I 200 -C 1 &
# Make the CPU-1 offline and online continuously
while true; do
sleep 2
echo 0 > /sys/devices/system/cpu/cpu1/online
sleep 2
echo 1 > /sys/devices/system/cpu/cpu1/online
done
Results:
/ # ./test.sh
# time counts unit events
0.200145885 <not counted> cycles
0.410115208 <not counted> cycles
0.619922551 <not counted> cycles
0.829904635 <not counted> cycles
1.039751614 <not counted> cycles
1.249547603 <not counted> cycles
1.459228280 <not counted> cycles
1.665606561 <not counted> cycles
1.874981926 <not counted> cycles
2.084297811 <not counted> cycles
2.293471249 <not counted> cycles
2.503231561 <not counted> cycles
2.712993332 <not counted> cycles
2.922744478 <not counted> cycles
3.132502186 <not counted> cycles
3.342255050 <not counted> cycles
3.552010102 <not counted> cycles
3.761760363 <not counted> cycles
/* CPU-1 made online: Event started counting */
3.971459269 1925429 cycles
4.181325206 19391145 cycles
4.391074164 113894 cycles
4.599130519 3150152 cycles
4.805564737 487122 cycles
5.015164581 247533 cycles
5.224764529 103622 cycles
# time counts unit events
5.434360831 238179 cycles
5.645293799 238895 cycles
5.854909320 367543 cycles
6.064487966 2383428 cycles
/* CPU-1 made offline: counting stopped
6.274289476 <not counted> cycles
6.483493903 <not counted> cycles
6.693202705 <not counted> cycles
6.902956195 <not counted> cycles
7.112714268 <not counted> cycles
7.322465570 <not counted> cycles
7.532222340 <not counted> cycles
7.741975830 <not counted> cycles
7.951686246 <not counted> cycles
/* CPU-1 made online: Event started counting
8.161469892 22040750 cycles
8.371219528 114977 cycles
8.580979111 259952 cycles
8.790757132 444661 cycles
9.000559215 248512 cycles
9.210385256 246590 cycles
9.420187704 243819 cycles
9.630052287 7102438 cycles
9.839848225 337454 cycles
10.049645048 644072 cycles
10.259476246 1855410 cycles
Mukesh Ojha (1):
perf: event preserve and create across cpu hotplug
include/linux/perf_event.h | 1 +
kernel/events/core.c | 122 +++++++++++++++++++++++++++++----------------
2 files changed, 79 insertions(+), 44 deletions(-)
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center,
Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH RESEND V4 1/1] perf: event preserve and create across cpu hotplug
2019-06-18 13:46 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
@ 2019-06-18 13:46 ` Mukesh Ojha
2019-07-02 8:25 ` Mukesh Ojha
2019-06-24 9:01 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
1 sibling, 1 reply; 13+ messages in thread
From: Mukesh Ojha @ 2019-06-18 13:46 UTC (permalink / raw)
To: linux-kernel
Cc: Mukesh Ojha, Raghavendra Rao Ananta, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Alexander Shishkin, Jiri Olsa,
Alexei Starovoitov
Perf framework doesn't allow preserving CPU events across
CPU hotplugs. The events are scheduled out as and when the
CPU walks offline. Moreover, the framework also doesn't
allow the clients to create events on an offline CPU. As
a result, the clients have to keep on monitoring the CPU
state until it comes back online.
Therefore, introducing the perf framework to support creation
and preserving of (CPU) events for offline CPUs. Through
this, the CPU's online state would be transparent to the
client and it not have to worry about monitoring the CPU's
state. Success would be returned to the client even while
creating the event on an offline CPU. If during the lifetime
of the event the CPU walks offline, the event would be
preserved and would continue to count as soon as (and if) the
CPU comes back online.
Co-authored-by: Peter Zijlstra <peterz@infradead.org>
Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Alexei Starovoitov <ast@kernel.org>
---
Change in V4:
=============
- Released, __get_cpu_context would not be correct way to get the
cpu context of the cpu which is offline, instead use
container_of to get the cpuctx from ctx.
- Changed the goto label name inside event_function_call from
'remove_event_from_context' to 'out'.
Change in V3:
=============
- Jiri has tried perf stat -a and removed one of the cpu from the other
terminal. This resulted in a crash. Crash was because in
event_function_call(), we were passing NULL as cpuctx in
func(event, NULL, ctx, data).Fixed it in this patch.
Change in V2:
=============
As per long back discussion happened at
https://lkml.org/lkml/2018/2/15/1324
Peter.Z. has suggested to do thing in different way and shared
patch as well. This patch fixes the issue seen while trying
to achieve the purpose.
Fixed issue on top of Peter's patch:
===================================
1. Added a NULL check on task to avoid crash in __perf_install_in_context.
2. while trying to add event to context when cpu is offline.
Inside add_event_to_ctx() to make consistent state machine while hotplug.
-event->state += PERF_EVENT_STATE_HOTPLUG_OFFSET;
+event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
3. In event_function_call(), added a label 'remove_event_from_ctx' to
delete events from context list while cpu is offline.
include/linux/perf_event.h | 1 +
kernel/events/core.c | 123 ++++++++++++++++++++++++++++-----------------
2 files changed, 79 insertions(+), 45 deletions(-)
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 3dc01cf..52b14b2 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -511,6 +511,7 @@ enum perf_event_state {
PERF_EVENT_STATE_OFF = -1,
PERF_EVENT_STATE_INACTIVE = 0,
PERF_EVENT_STATE_ACTIVE = 1,
+ PERF_EVENT_STATE_HOTPLUG_OFFSET = -32,
};
struct file;
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 118ad1a..82b5106 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -248,6 +248,8 @@ static int event_function(void *info)
static void event_function_call(struct perf_event *event, event_f func, void *data)
{
struct perf_event_context *ctx = event->ctx;
+ struct perf_cpu_context *cpuctx =
+ container_of(ctx, struct perf_cpu_context, ctx);
struct task_struct *task = READ_ONCE(ctx->task); /* verified in event_function */
struct event_function_struct efs = {
.event = event,
@@ -264,17 +266,18 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
lockdep_assert_held(&ctx->mutex);
}
- if (!task) {
- cpu_function_call(event->cpu, event_function, &efs);
- return;
- }
-
if (task == TASK_TOMBSTONE)
return;
again:
- if (!task_function_call(task, event_function, &efs))
- return;
+ if (task) {
+ if (!task_function_call(task, event_function, &efs))
+ return;
+ } else {
+ if (!cpu_function_call(event->cpu, event_function, &efs))
+ return;
+ }
+
raw_spin_lock_irq(&ctx->lock);
/*
@@ -286,11 +289,17 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
raw_spin_unlock_irq(&ctx->lock);
return;
}
+
+ if (!task)
+ goto out;
+
if (ctx->is_active) {
raw_spin_unlock_irq(&ctx->lock);
goto again;
}
- func(event, NULL, ctx, data);
+
+out:
+ func(event, cpuctx, ctx, data);
raw_spin_unlock_irq(&ctx->lock);
}
@@ -2310,7 +2319,7 @@ static void perf_set_shadow_time(struct perf_event *event,
struct perf_event *event, *partial_group = NULL;
struct pmu *pmu = ctx->pmu;
- if (group_event->state == PERF_EVENT_STATE_OFF)
+ if (group_event->state <= PERF_EVENT_STATE_OFF)
return 0;
pmu->start_txn(pmu, PERF_PMU_TXN_ADD);
@@ -2389,6 +2398,14 @@ static int group_can_go_on(struct perf_event *event,
static void add_event_to_ctx(struct perf_event *event,
struct perf_event_context *ctx)
{
+ if (!ctx->task) {
+ struct perf_cpu_context *cpuctx =
+ container_of(ctx, struct perf_cpu_context, ctx);
+
+ if (!cpuctx->online)
+ event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
+ }
+
list_add_event(event, ctx);
perf_group_attach(event);
}
@@ -2576,11 +2593,6 @@ static int __perf_install_in_context(void *info)
*/
smp_store_release(&event->ctx, ctx);
- if (!task) {
- cpu_function_call(cpu, __perf_install_in_context, event);
- return;
- }
-
/*
* Should not happen, we validate the ctx is still alive before calling.
*/
@@ -2619,8 +2631,14 @@ static int __perf_install_in_context(void *info)
*/
smp_mb();
again:
- if (!task_function_call(task, __perf_install_in_context, event))
- return;
+
+ if (task) {
+ if (!task_function_call(task, __perf_install_in_context, event))
+ return;
+ } else {
+ if (!cpu_function_call(cpu, __perf_install_in_context, event))
+ return;
+ }
raw_spin_lock_irq(&ctx->lock);
task = ctx->task;
@@ -2637,7 +2655,7 @@ static int __perf_install_in_context(void *info)
* If the task is not running, ctx->lock will avoid it becoming so,
* thus we can safely install the event.
*/
- if (task_curr(task)) {
+ if (task && task_curr(task)) {
raw_spin_unlock_irq(&ctx->lock);
goto again;
}
@@ -11022,16 +11040,7 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
}
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) {
+ if (!cpu_possible(cpu)) {
err = -ENODEV;
goto err_locked;
}
@@ -11213,15 +11222,7 @@ struct perf_event *
}
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) {
+ if (!cpu_possible(cpu)) {
err = -ENODEV;
goto err_unlock;
}
@@ -11949,17 +11950,48 @@ static void perf_swevent_init_cpu(unsigned int cpu)
}
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
+static void __perf_event_init_cpu_context(void *__info)
+{
+ struct perf_cpu_context *cpuctx = __info;
+ struct perf_event_context *ctx = &cpuctx->ctx;
+ struct perf_event_context *task_ctx = cpuctx->task_ctx;
+ struct perf_event *event;
+
+ perf_ctx_lock(cpuctx, task_ctx);
+ ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+ if (task_ctx)
+ ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
+ perf_event_set_state(event, event->state - PERF_EVENT_STATE_HOTPLUG_OFFSET);
+
+ perf_event_sched_in(cpuctx, task_ctx, current);
+ perf_ctx_unlock(cpuctx, task_ctx);
+}
+
+static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx)
+{
+ smp_call_function_single(cpu, __perf_event_init_cpu_context, cpuctx, 1);
+}
+
static void __perf_event_exit_context(void *__info)
{
- struct perf_event_context *ctx = __info;
- struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
+ struct perf_cpu_context *cpuctx = __info;
+ struct perf_event_context *ctx = &cpuctx->ctx;
+ struct perf_event_context *task_ctx = cpuctx->task_ctx;
struct perf_event *event;
- raw_spin_lock(&ctx->lock);
- ctx_sched_out(ctx, cpuctx, EVENT_TIME);
- list_for_each_entry(event, &ctx->event_list, event_entry)
- __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
- raw_spin_unlock(&ctx->lock);
+ perf_ctx_lock(cpuctx, task_ctx);
+ ctx_sched_out(ctx, cpuctx, EVENT_ALL);
+ if (task_ctx)
+ ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
+
+ list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
+ perf_event_set_state(event,
+ event->state + PERF_EVENT_STATE_HOTPLUG_OFFSET);
+
+ perf_event_sched_in(cpuctx, task_ctx, current);
+ perf_ctx_unlock(cpuctx, task_ctx);
}
static void perf_event_exit_cpu_context(int cpu)
@@ -11974,7 +12006,7 @@ static void perf_event_exit_cpu_context(int cpu)
ctx = &cpuctx->ctx;
mutex_lock(&ctx->mutex);
- smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
+ smp_call_function_single(cpu, __perf_event_exit_context, cpuctx, 1);
cpuctx->online = 0;
mutex_unlock(&ctx->mutex);
}
@@ -11982,7 +12014,7 @@ static void perf_event_exit_cpu_context(int cpu)
mutex_unlock(&pmus_lock);
}
#else
-
+static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx) { }
static void perf_event_exit_cpu_context(int cpu) { }
#endif
@@ -12003,6 +12035,7 @@ int perf_event_init_cpu(unsigned int cpu)
mutex_lock(&ctx->mutex);
cpuctx->online = 1;
+ _perf_event_init_cpu_context(cpu, cpuctx);
mutex_unlock(&ctx->mutex);
}
mutex_unlock(&pmus_lock);
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center,
Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events
2019-06-18 13:46 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
2019-06-18 13:46 ` [PATCH RESEND V4 1/1] perf: event preserve and create across cpu hotplug Mukesh Ojha
@ 2019-06-24 9:01 ` Mukesh Ojha
2019-07-26 9:06 ` Mukesh Ojha
1 sibling, 1 reply; 13+ messages in thread
From: Mukesh Ojha @ 2019-06-24 9:01 UTC (permalink / raw)
To: lkml
Friendly ping.
On 6/18/2019 7:16 PM, Mukesh Ojha wrote:
> The embedded world, specifically Android mobile SoCs, rely on CPU
> hotplugs to manage power and thermal constraints. These hotplugs
> can happen at a very rapid pace. Adjacently, they also relies on
> many perf event counters for its management. Therefore, there is
> a need to preserve these events across hotplugs.
>
> In such a scenario, a perf client (kernel or user-space) can create
> events even when the CPU is offline. If the CPU comes online during
> the lifetime of the event, the registered event can start counting
> spontaneously. As an extension to this, the events' count can also
> be preserved across CPU hotplugs. This takes the burden off of the
> clients to monitor the state of the CPU.
>
> The tests were conducted on arm64 device.
> /* CPU-1 is offline: Event created when CPU1 is offline */
>
> / # cat /sys/devices/system/cpu/cpu1/online
> 1
> / # echo 0 > /sys/devices/system/cpu/cpu1/online
>
> Test used for testing
> #!/bin/sh
>
> chmod +x *
>
> # Count the cycles events on cpu-1 for every 200 ms
> ./perf stat -e cycles -I 200 -C 1 &
>
> # Make the CPU-1 offline and online continuously
> while true; do
> sleep 2
> echo 0 > /sys/devices/system/cpu/cpu1/online
> sleep 2
> echo 1 > /sys/devices/system/cpu/cpu1/online
> done
>
> Results:
> / # ./test.sh
> # time counts unit events
> 0.200145885 <not counted> cycles
> 0.410115208 <not counted> cycles
> 0.619922551 <not counted> cycles
> 0.829904635 <not counted> cycles
> 1.039751614 <not counted> cycles
> 1.249547603 <not counted> cycles
> 1.459228280 <not counted> cycles
> 1.665606561 <not counted> cycles
> 1.874981926 <not counted> cycles
> 2.084297811 <not counted> cycles
> 2.293471249 <not counted> cycles
> 2.503231561 <not counted> cycles
> 2.712993332 <not counted> cycles
> 2.922744478 <not counted> cycles
> 3.132502186 <not counted> cycles
> 3.342255050 <not counted> cycles
> 3.552010102 <not counted> cycles
> 3.761760363 <not counted> cycles
>
> /* CPU-1 made online: Event started counting */
>
> 3.971459269 1925429 cycles
> 4.181325206 19391145 cycles
> 4.391074164 113894 cycles
> 4.599130519 3150152 cycles
> 4.805564737 487122 cycles
> 5.015164581 247533 cycles
> 5.224764529 103622 cycles
> # time counts unit events
> 5.434360831 238179 cycles
> 5.645293799 238895 cycles
> 5.854909320 367543 cycles
> 6.064487966 2383428 cycles
>
> /* CPU-1 made offline: counting stopped
>
> 6.274289476 <not counted> cycles
> 6.483493903 <not counted> cycles
> 6.693202705 <not counted> cycles
> 6.902956195 <not counted> cycles
> 7.112714268 <not counted> cycles
> 7.322465570 <not counted> cycles
> 7.532222340 <not counted> cycles
> 7.741975830 <not counted> cycles
> 7.951686246 <not counted> cycles
>
> /* CPU-1 made online: Event started counting
>
> 8.161469892 22040750 cycles
> 8.371219528 114977 cycles
> 8.580979111 259952 cycles
> 8.790757132 444661 cycles
> 9.000559215 248512 cycles
> 9.210385256 246590 cycles
> 9.420187704 243819 cycles
> 9.630052287 7102438 cycles
> 9.839848225 337454 cycles
> 10.049645048 644072 cycles
> 10.259476246 1855410 cycles
>
> Mukesh Ojha (1):
> perf: event preserve and create across cpu hotplug
>
> include/linux/perf_event.h | 1 +
> kernel/events/core.c | 122 +++++++++++++++++++++++++++++----------------
> 2 files changed, 79 insertions(+), 44 deletions(-)
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RESEND V4 1/1] perf: event preserve and create across cpu hotplug
2019-06-18 13:46 ` [PATCH RESEND V4 1/1] perf: event preserve and create across cpu hotplug Mukesh Ojha
@ 2019-07-02 8:25 ` Mukesh Ojha
0 siblings, 0 replies; 13+ messages in thread
From: Mukesh Ojha @ 2019-07-02 8:25 UTC (permalink / raw)
To: linux-kernel
Cc: Raghavendra Rao Ananta, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Alexander Shishkin, Jiri Olsa,
Alexei Starovoitov
Friendly Ping.
More explanation of the usecase added in the coverletter
[PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events.
-Mukesh
On 6/18/2019 7:16 PM, Mukesh Ojha wrote:
> Perf framework doesn't allow preserving CPU events across
> CPU hotplugs. The events are scheduled out as and when the
> CPU walks offline. Moreover, the framework also doesn't
> allow the clients to create events on an offline CPU. As
> a result, the clients have to keep on monitoring the CPU
> state until it comes back online.
>
> Therefore, introducing the perf framework to support creation
> and preserving of (CPU) events for offline CPUs. Through
> this, the CPU's online state would be transparent to the
> client and it not have to worry about monitoring the CPU's
> state. Success would be returned to the client even while
> creating the event on an offline CPU. If during the lifetime
> of the event the CPU walks offline, the event would be
> preserved and would continue to count as soon as (and if) the
> CPU comes back online.
>
> Co-authored-by: Peter Zijlstra <peterz@infradead.org>
> Signed-off-by: Raghavendra Rao Ananta <rananta@codeaurora.org>
> Signed-off-by: Mukesh Ojha <mojha@codeaurora.org>
> Cc: Peter Zijlstra <peterz@infradead.org>
> Cc: Ingo Molnar <mingo@redhat.com>
> Cc: Arnaldo Carvalho de Melo <acme@kernel.org>
> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
> Cc: Jiri Olsa <jolsa@redhat.com>
> Cc: Alexei Starovoitov <ast@kernel.org>
> ---
> Change in V4:
> =============
> - Released, __get_cpu_context would not be correct way to get the
> cpu context of the cpu which is offline, instead use
> container_of to get the cpuctx from ctx.
>
> - Changed the goto label name inside event_function_call from
> 'remove_event_from_context' to 'out'.
>
> Change in V3:
> =============
> - Jiri has tried perf stat -a and removed one of the cpu from the other
> terminal. This resulted in a crash. Crash was because in
> event_function_call(), we were passing NULL as cpuctx in
> func(event, NULL, ctx, data).Fixed it in this patch.
>
> Change in V2:
> =============
> As per long back discussion happened at
> https://lkml.org/lkml/2018/2/15/1324
>
> Peter.Z. has suggested to do thing in different way and shared
> patch as well. This patch fixes the issue seen while trying
> to achieve the purpose.
>
> Fixed issue on top of Peter's patch:
> ===================================
> 1. Added a NULL check on task to avoid crash in __perf_install_in_context.
>
> 2. while trying to add event to context when cpu is offline.
> Inside add_event_to_ctx() to make consistent state machine while hotplug.
>
> -event->state += PERF_EVENT_STATE_HOTPLUG_OFFSET;
> +event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
>
> 3. In event_function_call(), added a label 'remove_event_from_ctx' to
> delete events from context list while cpu is offline.
>
> include/linux/perf_event.h | 1 +
> kernel/events/core.c | 123 ++++++++++++++++++++++++++++-----------------
> 2 files changed, 79 insertions(+), 45 deletions(-)
>
> diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
> index 3dc01cf..52b14b2 100644
> --- a/include/linux/perf_event.h
> +++ b/include/linux/perf_event.h
> @@ -511,6 +511,7 @@ enum perf_event_state {
> PERF_EVENT_STATE_OFF = -1,
> PERF_EVENT_STATE_INACTIVE = 0,
> PERF_EVENT_STATE_ACTIVE = 1,
> + PERF_EVENT_STATE_HOTPLUG_OFFSET = -32,
> };
>
> struct file;
> diff --git a/kernel/events/core.c b/kernel/events/core.c
> index 118ad1a..82b5106 100644
> --- a/kernel/events/core.c
> +++ b/kernel/events/core.c
> @@ -248,6 +248,8 @@ static int event_function(void *info)
> static void event_function_call(struct perf_event *event, event_f func, void *data)
> {
> struct perf_event_context *ctx = event->ctx;
> + struct perf_cpu_context *cpuctx =
> + container_of(ctx, struct perf_cpu_context, ctx);
> struct task_struct *task = READ_ONCE(ctx->task); /* verified in event_function */
> struct event_function_struct efs = {
> .event = event,
> @@ -264,17 +266,18 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
> lockdep_assert_held(&ctx->mutex);
> }
>
> - if (!task) {
> - cpu_function_call(event->cpu, event_function, &efs);
> - return;
> - }
> -
> if (task == TASK_TOMBSTONE)
> return;
>
> again:
> - if (!task_function_call(task, event_function, &efs))
> - return;
> + if (task) {
> + if (!task_function_call(task, event_function, &efs))
> + return;
> + } else {
> + if (!cpu_function_call(event->cpu, event_function, &efs))
> + return;
> + }
> +
>
> raw_spin_lock_irq(&ctx->lock);
> /*
> @@ -286,11 +289,17 @@ static void event_function_call(struct perf_event *event, event_f func, void *da
> raw_spin_unlock_irq(&ctx->lock);
> return;
> }
> +
> + if (!task)
> + goto out;
> +
> if (ctx->is_active) {
> raw_spin_unlock_irq(&ctx->lock);
> goto again;
> }
> - func(event, NULL, ctx, data);
> +
> +out:
> + func(event, cpuctx, ctx, data);
> raw_spin_unlock_irq(&ctx->lock);
> }
>
> @@ -2310,7 +2319,7 @@ static void perf_set_shadow_time(struct perf_event *event,
> struct perf_event *event, *partial_group = NULL;
> struct pmu *pmu = ctx->pmu;
>
> - if (group_event->state == PERF_EVENT_STATE_OFF)
> + if (group_event->state <= PERF_EVENT_STATE_OFF)
> return 0;
>
> pmu->start_txn(pmu, PERF_PMU_TXN_ADD);
> @@ -2389,6 +2398,14 @@ static int group_can_go_on(struct perf_event *event,
> static void add_event_to_ctx(struct perf_event *event,
> struct perf_event_context *ctx)
> {
> + if (!ctx->task) {
> + struct perf_cpu_context *cpuctx =
> + container_of(ctx, struct perf_cpu_context, ctx);
> +
> + if (!cpuctx->online)
> + event->state = PERF_EVENT_STATE_HOTPLUG_OFFSET;
> + }
> +
> list_add_event(event, ctx);
> perf_group_attach(event);
> }
> @@ -2576,11 +2593,6 @@ static int __perf_install_in_context(void *info)
> */
> smp_store_release(&event->ctx, ctx);
>
> - if (!task) {
> - cpu_function_call(cpu, __perf_install_in_context, event);
> - return;
> - }
> -
> /*
> * Should not happen, we validate the ctx is still alive before calling.
> */
> @@ -2619,8 +2631,14 @@ static int __perf_install_in_context(void *info)
> */
> smp_mb();
> again:
> - if (!task_function_call(task, __perf_install_in_context, event))
> - return;
> +
> + if (task) {
> + if (!task_function_call(task, __perf_install_in_context, event))
> + return;
> + } else {
> + if (!cpu_function_call(cpu, __perf_install_in_context, event))
> + return;
> + }
>
> raw_spin_lock_irq(&ctx->lock);
> task = ctx->task;
> @@ -2637,7 +2655,7 @@ static int __perf_install_in_context(void *info)
> * If the task is not running, ctx->lock will avoid it becoming so,
> * thus we can safely install the event.
> */
> - if (task_curr(task)) {
> + if (task && task_curr(task)) {
> raw_spin_unlock_irq(&ctx->lock);
> goto again;
> }
> @@ -11022,16 +11040,7 @@ static int perf_event_set_clock(struct perf_event *event, clockid_t clk_id)
> }
>
> 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) {
> + if (!cpu_possible(cpu)) {
> err = -ENODEV;
> goto err_locked;
> }
> @@ -11213,15 +11222,7 @@ struct perf_event *
> }
>
> 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) {
> + if (!cpu_possible(cpu)) {
> err = -ENODEV;
> goto err_unlock;
> }
> @@ -11949,17 +11950,48 @@ static void perf_swevent_init_cpu(unsigned int cpu)
> }
>
> #if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
> +static void __perf_event_init_cpu_context(void *__info)
> +{
> + struct perf_cpu_context *cpuctx = __info;
> + struct perf_event_context *ctx = &cpuctx->ctx;
> + struct perf_event_context *task_ctx = cpuctx->task_ctx;
> + struct perf_event *event;
> +
> + perf_ctx_lock(cpuctx, task_ctx);
> + ctx_sched_out(ctx, cpuctx, EVENT_ALL);
> + if (task_ctx)
> + ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
> +
> + list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
> + perf_event_set_state(event, event->state - PERF_EVENT_STATE_HOTPLUG_OFFSET);
> +
> + perf_event_sched_in(cpuctx, task_ctx, current);
> + perf_ctx_unlock(cpuctx, task_ctx);
> +}
> +
> +static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx)
> +{
> + smp_call_function_single(cpu, __perf_event_init_cpu_context, cpuctx, 1);
> +}
> +
> static void __perf_event_exit_context(void *__info)
> {
> - struct perf_event_context *ctx = __info;
> - struct perf_cpu_context *cpuctx = __get_cpu_context(ctx);
> + struct perf_cpu_context *cpuctx = __info;
> + struct perf_event_context *ctx = &cpuctx->ctx;
> + struct perf_event_context *task_ctx = cpuctx->task_ctx;
> struct perf_event *event;
>
> - raw_spin_lock(&ctx->lock);
> - ctx_sched_out(ctx, cpuctx, EVENT_TIME);
> - list_for_each_entry(event, &ctx->event_list, event_entry)
> - __perf_remove_from_context(event, cpuctx, ctx, (void *)DETACH_GROUP);
> - raw_spin_unlock(&ctx->lock);
> + perf_ctx_lock(cpuctx, task_ctx);
> + ctx_sched_out(ctx, cpuctx, EVENT_ALL);
> + if (task_ctx)
> + ctx_sched_out(task_ctx, cpuctx, EVENT_ALL);
> +
> + list_for_each_entry_rcu(event, &ctx->event_list, event_entry)
> + perf_event_set_state(event,
> + event->state + PERF_EVENT_STATE_HOTPLUG_OFFSET);
> +
> + perf_event_sched_in(cpuctx, task_ctx, current);
> + perf_ctx_unlock(cpuctx, task_ctx);
> }
>
> static void perf_event_exit_cpu_context(int cpu)
> @@ -11974,7 +12006,7 @@ static void perf_event_exit_cpu_context(int cpu)
> ctx = &cpuctx->ctx;
>
> mutex_lock(&ctx->mutex);
> - smp_call_function_single(cpu, __perf_event_exit_context, ctx, 1);
> + smp_call_function_single(cpu, __perf_event_exit_context, cpuctx, 1);
> cpuctx->online = 0;
> mutex_unlock(&ctx->mutex);
> }
> @@ -11982,7 +12014,7 @@ static void perf_event_exit_cpu_context(int cpu)
> mutex_unlock(&pmus_lock);
> }
> #else
> -
> +static void _perf_event_init_cpu_context(int cpu, struct perf_cpu_context *cpuctx) { }
> static void perf_event_exit_cpu_context(int cpu) { }
>
> #endif
> @@ -12003,6 +12035,7 @@ int perf_event_init_cpu(unsigned int cpu)
>
> mutex_lock(&ctx->mutex);
> cpuctx->online = 1;
> + _perf_event_init_cpu_context(cpu, cpuctx);
> mutex_unlock(&ctx->mutex);
> }
> mutex_unlock(&pmus_lock);
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events
2019-06-24 9:01 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
@ 2019-07-26 9:06 ` Mukesh Ojha
0 siblings, 0 replies; 13+ messages in thread
From: Mukesh Ojha @ 2019-07-26 9:06 UTC (permalink / raw)
To: lkml, Peter Zijlstra, Jiri Olsa, mingo, acme
Hi All,
Can you please review this ?
Thanks,
Mukesh
On 6/24/2019 2:31 PM, Mukesh Ojha wrote:
> Friendly ping.
>
> On 6/18/2019 7:16 PM, Mukesh Ojha wrote:
>> The embedded world, specifically Android mobile SoCs, rely on CPU
>> hotplugs to manage power and thermal constraints. These hotplugs
>> can happen at a very rapid pace. Adjacently, they also relies on
>> many perf event counters for its management. Therefore, there is
>> a need to preserve these events across hotplugs.
>>
>> In such a scenario, a perf client (kernel or user-space) can create
>> events even when the CPU is offline. If the CPU comes online during
>> the lifetime of the event, the registered event can start counting
>> spontaneously. As an extension to this, the events' count can also
>> be preserved across CPU hotplugs. This takes the burden off of the
>> clients to monitor the state of the CPU.
>>
>> The tests were conducted on arm64 device.
>> /* CPU-1 is offline: Event created when CPU1 is offline */
>>
>> / # cat /sys/devices/system/cpu/cpu1/online
>> 1
>> / # echo 0 > /sys/devices/system/cpu/cpu1/online
>>
>> Test used for testing
>> #!/bin/sh
>>
>> chmod +x *
>>
>> # Count the cycles events on cpu-1 for every 200 ms
>> ./perf stat -e cycles -I 200 -C 1 &
>>
>> # Make the CPU-1 offline and online continuously
>> while true; do
>> sleep 2
>> echo 0 > /sys/devices/system/cpu/cpu1/online
>> sleep 2
>> echo 1 > /sys/devices/system/cpu/cpu1/online
>> done
>>
>> Results:
>> / # ./test.sh
>> # time counts unit events
>> 0.200145885 <not counted> cycles
>> 0.410115208 <not counted> cycles
>> 0.619922551 <not counted> cycles
>> 0.829904635 <not counted> cycles
>> 1.039751614 <not counted> cycles
>> 1.249547603 <not counted> cycles
>> 1.459228280 <not counted> cycles
>> 1.665606561 <not counted> cycles
>> 1.874981926 <not counted> cycles
>> 2.084297811 <not counted> cycles
>> 2.293471249 <not counted> cycles
>> 2.503231561 <not counted> cycles
>> 2.712993332 <not counted> cycles
>> 2.922744478 <not counted> cycles
>> 3.132502186 <not counted> cycles
>> 3.342255050 <not counted> cycles
>> 3.552010102 <not counted> cycles
>> 3.761760363 <not counted> cycles
>>
>> /* CPU-1 made online: Event started counting */
>>
>> 3.971459269 1925429 cycles
>> 4.181325206 19391145 cycles
>> 4.391074164 113894 cycles
>> 4.599130519 3150152 cycles
>> 4.805564737 487122 cycles
>> 5.015164581 247533 cycles
>> 5.224764529 103622 cycles
>> # time counts unit events
>> 5.434360831 238179 cycles
>> 5.645293799 238895 cycles
>> 5.854909320 367543 cycles
>> 6.064487966 2383428 cycles
>>
>> /* CPU-1 made offline: counting stopped
>>
>> 6.274289476 <not counted> cycles
>> 6.483493903 <not counted> cycles
>> 6.693202705 <not counted> cycles
>> 6.902956195 <not counted> cycles
>> 7.112714268 <not counted> cycles
>> 7.322465570 <not counted> cycles
>> 7.532222340 <not counted> cycles
>> 7.741975830 <not counted> cycles
>> 7.951686246 <not counted> cycles
>>
>> /* CPU-1 made online: Event started counting
>>
>> 8.161469892 22040750 cycles
>> 8.371219528 114977 cycles
>> 8.580979111 259952 cycles
>> 8.790757132 444661 cycles
>> 9.000559215 248512 cycles
>> 9.210385256 246590 cycles
>> 9.420187704 243819 cycles
>> 9.630052287 7102438 cycles
>> 9.839848225 337454 cycles
>> 10.049645048 644072 cycles
>> 10.259476246 1855410 cycles
>>
>> Mukesh Ojha (1):
>> perf: event preserve and create across cpu hotplug
>>
>> include/linux/perf_event.h | 1 +
>> kernel/events/core.c | 122
>> +++++++++++++++++++++++++++++----------------
>> 2 files changed, 79 insertions(+), 44 deletions(-)
>>
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2019-07-26 9:06 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-31 13:39 [PATCH V2 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
2019-05-31 13:39 ` [PATCH V2 1/1] perf: event preserve and create across cpu hotplug Mukesh Ojha
2019-06-03 17:53 ` Jiri Olsa
2019-06-04 14:09 ` Mukesh Ojha
2019-06-12 10:57 ` [PATCH V3] " Mukesh Ojha
2019-06-18 8:54 ` [PATCH V4] " Mukesh Ojha
2019-06-18 12:23 ` Peter Zijlstra
2019-06-18 13:40 ` Mukesh Ojha
2019-06-18 13:46 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
2019-06-18 13:46 ` [PATCH RESEND V4 1/1] perf: event preserve and create across cpu hotplug Mukesh Ojha
2019-07-02 8:25 ` Mukesh Ojha
2019-06-24 9:01 ` [PATCH RESEND V4 0/1] perf: Add CPU hotplug support for events Mukesh Ojha
2019-07-26 9:06 ` Mukesh Ojha
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).