Hi Peter, Am 12.06.2015 um 20:03 schrieb Peter Maydell: > On 12 June 2015 at 17:38, Alex Züpke <alexander.zue...@hs-rm.de> wrote: >> Hi, >> >> I'm benchmarking some IPI (== inter-processor-interrupt) synchronization >> stuff of my custom kernel on QEMU ARM (qemu-system-arm -M vexpress-a15 -smp >> 2) and ran into the following problem: pending IPIs are delayed until the >> QEMU main loop receives an event (for example the timer interrupt expires or >> I press a key on the console). >> >> The following timing diagram tries to show this: >> >> CPU #0 CPU #1 >> ====== ====== >> ... other stuff ... WFI (wait for interrupt, like x86 "HLT") >> send SGI in MPCore >> polls for completeness >> <time passes ...> >> polls ... >> <... and passes ...> >> still polls ... >> <... and passes ...> >> still polls ... >> <... and passes ...> >> >> >> <timer interrupt expires> >> <now QEMU switches to CPU #1> >> receives IPI >> signals completeness >> WFI >> <QEMU switches to CPU #0> >> polling done >> process timer interrupt >> ... > > Right. The problem is that we don't have any way of telling > that CPU 0 is just sat busy waiting for CPU 1. > >> It works as expects (I get thousands of IPIs per second now), but >> it does not "feel right", so is there a better way to improve the >> responsiveness of IPI handling in QEMU? > > Probably the best approach would be to have something in > arm_cpu_set_irq() which says "if we are CPU X and we've > just caused an interrupt to be set for CPU Y, then we > should ourselves yield back to the main loop". > > Something like this, maybe, though I have done no more testing > than checking it doesn't actively break kernel booting :-)
Thanks! One more check for "level" is needed to get it work: --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -325,6 +325,18 @@ static void arm_cpu_set_irq(void *opaque, int irq, int level) default: hw_error("arm_cpu_set_irq: Bad interrupt line %d\n", irq); } + + /* If we are currently executing code for CPU X, and this + * CPU we've just triggered an interrupt on is CPU Y, then + * make CPU X yield control back to the main loop at the + * end of the TB it's currently executing. + * This avoids problems where the interrupt was an IPI + * and CPU X would otherwise sit busy looping for the rest + * of its timeslice because Y hasn't had a chance to run. + */ + if (level && current_cpu && current_cpu != cs) { + cpu_exit(current_cpu); + } } static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level) Do you need a testcase for this? Best regards Alex