From: robherring2@gmail.com (Rob Herring)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH] ARM: implement optimized percpu variable access
Date: Mon, 26 Nov 2012 11:30:55 -0600 [thread overview]
Message-ID: <50B3A74F.20602@gmail.com> (raw)
In-Reply-To: <20121126151534.GA13620@mudshark.cambridge.arm.com>
On 11/26/2012 09:15 AM, Will Deacon wrote:
> On Mon, Nov 26, 2012 at 11:13:37AM +0000, Will Deacon wrote:
>> On Sun, Nov 25, 2012 at 06:46:55PM +0000, Rob Herring wrote:
>>> On 11/22/2012 05:34 AM, Will Deacon wrote:
>>>> As an aside, you also need to make the asm block volatile in
>>>> __my_cpu_offset -- I can see it being re-ordered before the set for
>>>> secondary CPUs otherwise.
>>>
>>> I don't really see where there would be a re-ordering issue. There's no
>>> percpu var access before or near the setting that I can see.
>>
>> The issue is on bringing up the secondary core, so I assumed that a lot
>> of inlining goes on inside secondary_start_kernel and then the result is
>> shuffled around, placing a cpu-offset read before we've done the set.
>>
>> Unfortunately, looking at the disassembly I can't see this happening at
>> all, so I'll keep digging. The good news is that I've just reproduced the
>> problem on the model, so I've got more visibility now (although both cores
>> are just stuck in spinlocks...).
>
> That was a fun bit of debugging -- my hunch was right, but I was looking in the
> wrong place because I had an unrelated problem with my bootloader.
>
> What happens is that every man and his dog is inlined into __schedule,
> including all the runqueue accessors, such as this_rq(), which make use of
> per-cpu offsets to get the correct pointer. The compiler then spits out
> something like this near the start of the function:
>
> c02c1d66: af04 add r7, sp, #16
> [...]
> c02c1d6c: ee1d 3f90 mrc 15, 0, r3, cr13, cr0, {4}
> c02c1d70: 199b adds r3, r3, r6
> c02c1d72: f8c7 e008 str.w lr, [r7, #8]
> c02c1d76: 617b str r3, [r7, #20]
> c02c1d78: 613e str r6, [r7, #16]
> c02c1d7a: 60fb str r3, [r7, #12]
>
> so the address of the current runqueue has been calculated and stored, with
> a bunch of other stuff, in a structure on the stack.
>
> We then do our context_switch dance (which is also inlined) and return as
> the next task (since we've done switch_{mm,to}) before doing:
>
> barrier();
> /*
> * this_rq must be evaluated again because prev may have moved
> * CPUs since it called schedule(), thus the 'rq' on its stack
> * frame will be invalid.
> */
> finish_task_switch(this_rq(), prev);
>
> The problem here is that, because our CPU accessors don't actually make any
> memory references, the barrier() has no effect and the old value is just
> reloaded off the stack:
>
> c02c1f22: f54a fe49 bl c000cbb8 <__switch_to>
> c02c1f26: 4601 mov r1, r0
> c02c1f28: 68f8 ldr r0, [r7, #12]
> c02c1f2a: f56f ffd5 bl c0031ed8 <finish_task_switch>
>
> which obviously causes complete chaos if the new task has been pulled from
> a different runqueue! (this appears as a double spin unlock on rq->lock).
>
> Fixing this without giving up the performance improvement we gain by *avoiding*
> the memory access in the first place is going to be tricky...
What compiler and config are you using? I get a reload of the register here:
c0350fba: f001 fa9d bl c03524f8 <__switch_to>
c0350fbe: 4601 mov r1, r0
c0350fc0: ee1d 0f90 mrc 15, 0, r0, cr13, cr0, {4}
c0350fc4: 4c2a ldr r4, [pc, #168] ; (c0351070
<__schedule+0x390>)
c0350fc6: f649 1590 movw r5, #39312 ; 0x9990
c0350fca: 1900 adds r0, r0, r4
c0350fcc: f2cc 0556 movt r5, #49238 ; 0xc056
c0350fd0: f4e7 fd56 bl c0038a80 <finish_task_switch>
Rob
next prev parent reply other threads:[~2012-11-26 17:30 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-11 3:20 [PATCH] ARM: implement optimized percpu variable access Rob Herring
2012-11-12 10:23 ` Will Deacon
2012-11-12 13:03 ` Rob Herring
2012-11-12 13:28 ` Will Deacon
2012-11-12 14:03 ` Rob Herring
2012-11-27 17:29 ` Nicolas Pitre
2012-11-12 14:21 ` Rob Herring
2012-11-12 14:41 ` Will Deacon
2012-11-12 16:51 ` Will Deacon
2012-11-12 21:01 ` Rob Herring
2012-11-13 10:40 ` Will Deacon
2012-11-22 11:34 ` Will Deacon
2012-11-22 11:39 ` Russell King - ARM Linux
2012-11-23 17:06 ` Rob Herring
2012-11-23 17:12 ` Russell King - ARM Linux
2012-11-23 17:16 ` Will Deacon
2012-11-23 20:34 ` Tony Lindgren
2012-11-23 20:32 ` Tony Lindgren
2012-11-25 18:46 ` Rob Herring
2012-11-26 11:13 ` Will Deacon
2012-11-26 15:15 ` Will Deacon
2012-11-26 17:30 ` Rob Herring [this message]
2012-11-27 13:17 ` Will Deacon
2012-11-27 13:26 ` Russell King - ARM Linux
2012-11-26 21:58 ` Jamie Lokier
2012-11-26 23:50 ` Jamie Lokier
2012-11-27 1:02 ` Jamie Lokier
2012-11-27 22:02 ` Rob Herring
2012-11-28 12:34 ` Will Deacon
2012-11-27 17:35 ` Nicolas Pitre
2012-11-27 19:27 ` Nicolas Pitre
2012-11-27 17:19 ` Nicolas Pitre
2012-11-27 19:37 ` Rob Herring
2012-11-27 20:42 ` Rob Herring
2012-11-27 22:02 ` Nicolas Pitre
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=50B3A74F.20602@gmail.com \
--to=robherring2@gmail.com \
--cc=linux-arm-kernel@lists.infradead.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.