From: Daniel Bristot de Oliveira <bristot@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
"H. Peter Anvin" <hpa@zytor.com>,
Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
Masami Hiramatsu <mhiramat@kernel.org>,
"Steven Rostedt (VMware)" <rostedt@goodmis.org>,
Jiri Kosina <jkosina@suse.cz>,
Josh Poimboeuf <jpoimboe@redhat.com>,
"Peter Zijlstra (Intel)" <peterz@infradead.org>,
Chris von Recklinghausen <crecklin@redhat.com>,
Jason Baron <jbaron@akamai.com>, Scott Wood <swood@redhat.com>,
Marcelo Tosatti <mtosatti@redhat.com>,
Clark Williams <williams@redhat.com>,
x86@kernel.org
Subject: Re: [PATCH V3 0/9] x86/jump_label: Bound IPIs sent when updating a static key
Date: Mon, 21 Jan 2019 13:52:46 +0100 [thread overview]
Message-ID: <83a1647b-bdcb-80e6-87ea-1919b41be8b2@redhat.com> (raw)
In-Reply-To: <cover.1545228276.git.bristot@redhat.com>
On 12/21/18 11:27 AM, Daniel Bristot de Oliveira wrote:
> While tuning a system with CPUs isolated as much as possible, we've
> noticed that isolated CPUs were receiving bursts of 12 IPIs, periodically.
> Tracing the functions that emit IPIs, we saw chronyd - an unprivileged
> process - generating the IPIs when changing a static key, enabling
> network timestaping on sockets.
>
> For instance, the trace pointed:
>
> # trace-cmd record --func-stack -p function -l smp_call_function_single -e irq_vectors -f 'vector == 251'...
> # trace-cmde report...
> [...]
> chronyd-858 [000] 433.286406: function: smp_call_function_single
> chronyd-858 [000] 433.286408: kernel_stack: <stack trace>
> => smp_call_function_many (ffffffffbc10ab22)
> => smp_call_function (ffffffffbc10abaa)
> => on_each_cpu (ffffffffbc10ac0b)
> => text_poke_bp (ffffffffbc02436a)
> => arch_jump_label_transform (ffffffffbc020ec8)
> => __jump_label_update (ffffffffbc1b300f)
> => jump_label_update (ffffffffbc1b30ed)
> => static_key_slow_inc (ffffffffbc1b334d)
> => net_enable_timestamp (ffffffffbc625c44)
> => sock_enable_timestamp (ffffffffbc6127d5)
> => sock_setsockopt (ffffffffbc612d2f)
> => SyS_setsockopt (ffffffffbc60d5e6)
> => tracesys (ffffffffbc7681c5)
> <idle>-0 [001] 433.286416: call_function_single_entry: vector=251
> <idle>-0 [001] 433.286419: call_function_single_exit: vector=251
>
> [... The IPI takes place 12 times]
>
> The static key in case was the netstamp_needed_key. A static key
> change from enabled->disabled/disabled->enabled causes the code to be
> patched, and this is done in three steps:
>
> -- Pseudo-code #1 - Current implementation ---
> For each key to be updated:
> 1) add an int3 trap to the address that will be patched
> sync cores (send IPI to all other CPUs)
> 2) update all but the first byte of the patched range
> sync cores (send IPI to all other CPUs)
> 3) replace the first byte (int3) by the first byte of replacing opcode
> sync cores (send IPI to all other CPUs)
> -- Pseudo-code #1 ---
>
> As the static key netstamp_needed_key has four entries (used in for
> places in the code) in our kernel, 3 IPIs were generated for each
> entry, resulting in 12 IPIs. The number of IPIs then is linear with
> regard to the number 'n' of entries of a key: O(n*3), which is O(n).
>
> This algorithm works fine for the update of a single key. But we think
> it is possible to optimize the case in which a static key has more than
> one entry. For instance, the sched_schedstats jump label has 56 entries
> in my (updated) fedora kernel, resulting in 168 IPIs for each CPU in
> which the thread that is enabling is _not_ running.
>
> Rather than doing each updated at once, it is possible to queue all updates
> first, and then apply all updates at once, rewriting the pseudo-code #1
> in this way:
>
> -- Pseudo-code #2 - proposal ---
> 1) for each key in the queue:
> add an int3 trap to the address that will be patched
> sync cores (send IPI to all other CPUs)
>
> 2) for each key in the queue:
> update all but the first byte of the patched range
> sync cores (send IPI to all other CPUs)
>
> 3) for each key in the queue:
> replace the first byte (int3) by the first byte of replacing opcode
> sync cores (send IPI to all other CPUs)
> -- Pseudo-code #2 - proposal ---
>
> Doing the update in this way, the number of IPI becomes O(3) with regard
> to the number of keys, which is O(1).
>
> Currently, the jump label of a static key is transformed via the arch
> specific function:
>
> void arch_jump_label_transform(struct jump_entry *entry,
> enum jump_label_type type)
>
> The new approach (batch mode) uses two arch functions, the first has the
> same arguments of the arch_jump_label_transform(), and is the function:
>
> void arch_jump_label_transform_queue(struct jump_entry *entry,
> enum jump_label_type type)
>
> Rather than transforming the code, it adds the jump_entry in a queue of
> entries to be updated.
>
> After queuing all jump_entries, the function:
>
> void arch_jump_label_transform_apply(void)
>
> Applies the changes in the queue.
>
> One easy way to see the benefits of this patch is switching the
> schedstats on and off. For instance:
>
> -------------------------- %< ----------------------------
> #!/bin/bash
>
> while [ true ]; do
> sysctl -w kernel.sched_schedstats=1
> sleep 2
> sysctl -w kernel.sched_schedstats=0
> sleep 2
> done
> -------------------------- >% ----------------------------
>
> while watching the IPI count:
>
> -------------------------- %< ----------------------------
> # watch -n1 "cat /proc/interrupts | grep Function"
> -------------------------- >% ----------------------------
>
> With the current mode, it is possible to see +- 168 IPIs each 2 seconds,
> while with the batch mode the number of IPIs goes to 3 each 2 seconds.
>
> Regarding the performance impact of this patch set, I made two measurements:
>
> The time to update a key (the task that is causing the change)
> The time to run the int3 handler (the side effect on a thread that
> hits the code being changed)
>
> The sched_schedstats static key was chosen as the key to being switched on and
> off. The reason being is that it is used in more than 56 places, in a hot path.
> The change in the schedstats static key will be done with the following
> command:
>
> while [ true ]; do
> sysctl -w kernel.sched_schedstats=1
> usleep 500000
> sysctl -w kernel.sched_schedstats=0
> usleep 500000
> done
>
> In this way, they key will be updated twice per second. To force the hit of the
> int3 handler, the system will also run a kernel compilation with two jobs per
> CPU. The test machine is a two nodes/24 CPUs box with an Intel Xeon processor
> @2.27GHz.
>
> Regarding the update part, on average, the regular kernel takes 57 ms to update
> the static key, while the kernel with the batch updates takes just 1.4 ms on
> average. Although it seems to be too good to be true, it makes sense: the
> sched_schedstats key is used in 56 places, so it was expected that it would take
> around 56 times to update the keys with the current implementation, as the
> IPIs are the most expensive part of the update.
>
> Regarding the int3 handler, the non-batch handler takes 45 ns on average, while
> the batch version takes around 180 ns. At first glance, it seems to be a high
> value. But it is not, considering that it is doing 56 updates, rather than one!
> It is taking four times more, only. This gain is possible because the patch
> uses a binary search in the vector: log2(56)=5.8. So, it was expected to have
> an overhead within four times.
>
> (voice of tv propaganda) But, that is not all! As the int3 handler keeps on for
> a shorter period (because the update part is on for a shorter time), the number
> of hits in the int3 handler decreased by 10%.
>
> The question then is: Is it worth paying the price of "135 ns" more in the int3
> handler?
>
> Considering that, in this test case, we are saving the handling of 53 IPIs,
> that takes more than these 135 ns, it seems to be a meager price to be paid.
> Moreover, the test case was forcing the hit of the int3, in practice, it
> does not take that often. While the IPI takes place on all CPUs, hitting
> the int3 handler or not!
>
> For instance, in an isolated CPU with a process running in user-space
> (nohz_full use-case), the chances of hitting the int3 handler is barely zero,
> while there is no way to avoid the IPIs. By bounding the IPIs, we are improving
> this scenario a lot.
>
> Changes from v2:
> - Switch the order of patches 8 and 9 (Steven Rostedt)
> - Fallback in the case of failure in the batch mode (Steven Rostedt)
> - Fix a pointer in patch 7 (Steven Rostedt)
> - Adjust the commit log of the patch 1 (Borislav Petkov)
> - Adjust the commit log of the patch 3 (Jiri Kosina/Thomas Gleixner)
> Changes from v1:
> - Split the patch in jump-label/x86-jump-label/alternative (Jason Baron)
> - Use bserach in the int3 handler (Steven Rostedt)
> - Use a pre-allocated page to store the vector (Jason/Steven)
> - Do performance tests in the int3 handler (peterz)
>
> Daniel Bristot de Oliveira (9):
> jump_label: Add for_each_label_entry helper
> jump_label: Add the jump_label_can_update_check() helper
> x86/jump_label: Move checking code away from __jump_label_transform()
> x86/jump_label: Add __jump_label_set_jump_code() helper
> x86/alternative: Split text_poke_bp() into tree steps
> jump_label: Sort entries of the same key by the code
> x86/alternative: Batch of patch operations
> jump_label: Batch updates if arch supports it
> x86/jump_label: Batch jump label updates
>
> arch/x86/include/asm/jump_label.h | 2 +
> arch/x86/include/asm/text-patching.h | 15 +++
> arch/x86/kernel/alternative.c | 140 ++++++++++++++++++---
> arch/x86/kernel/jump_label.c | 174 ++++++++++++++++++++++-----
> include/linux/jump_label.h | 6 +
> kernel/jump_label.c | 73 +++++++++--
> 6 files changed, 359 insertions(+), 51 deletions(-)
>
Hi,
This is just a gentle ping... Any thoughts about this patch series?
Thanks!
-- Daniel
next prev parent reply other threads:[~2019-01-21 12:53 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-12-21 10:27 Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 1/9] jump_label: Add for_each_label_entry helper Daniel Bristot de Oliveira
2019-04-19 18:36 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 2/9] jump_label: Add the jump_label_can_update_check() helper Daniel Bristot de Oliveira
2019-04-19 18:37 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 3/9] x86/jump_label: Move checking code away from __jump_label_transform() Daniel Bristot de Oliveira
2019-04-19 18:38 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 4/9] x86/jump_label: Add __jump_label_set_jump_code() helper Daniel Bristot de Oliveira
2019-04-19 18:38 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 5/9] x86/alternative: Split text_poke_bp() into tree steps Daniel Bristot de Oliveira
2019-04-19 18:39 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 6/9] jump_label: Sort entries of the same key by the code Daniel Bristot de Oliveira
2019-04-19 18:40 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 7/9] x86/alternative: Batch of patch operations Daniel Bristot de Oliveira
2019-01-23 5:15 ` Masami Hiramatsu
2019-01-26 11:52 ` Daniel Bristot de Oliveira
2019-01-28 13:52 ` Masami Hiramatsu
2019-02-01 12:49 ` Daniel Bristot de Oliveira
2019-02-01 14:47 ` Masami Hiramatsu
2019-02-01 15:51 ` Daniel Bristot de Oliveira
2019-04-19 18:41 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 8/9] jump_label: Batch updates if arch supports it Daniel Bristot de Oliveira
2019-04-19 18:42 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2018-12-21 10:27 ` [PATCH V3 9/9] x86/jump_label: Batch jump label updates Daniel Bristot de Oliveira
2019-04-19 18:42 ` [tip:x86/alternatives] " tip-bot for Daniel Bristot de Oliveira
2019-01-21 12:52 ` Daniel Bristot de Oliveira [this message]
2019-04-19 19:01 ` [PATCH V3 0/9] x86/jump_label: Bound IPIs sent when updating a static key Ingo Molnar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=83a1647b-bdcb-80e6-87ea-1919b41be8b2@redhat.com \
--to=bristot@redhat.com \
--cc=bp@alien8.de \
--cc=crecklin@redhat.com \
--cc=gregkh@linuxfoundation.org \
--cc=hpa@zytor.com \
--cc=jbaron@akamai.com \
--cc=jkosina@suse.cz \
--cc=jpoimboe@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mhiramat@kernel.org \
--cc=mingo@redhat.com \
--cc=mtosatti@redhat.com \
--cc=peterz@infradead.org \
--cc=rostedt@goodmis.org \
--cc=swood@redhat.com \
--cc=tglx@linutronix.de \
--cc=williams@redhat.com \
--cc=x86@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Powered by JetHome