On Thu, Aug 27, 2009 at 11:25:17AM +0300, Avi Kivity wrote: > On 08/27/2009 04:20 AM, Marcelo Tosatti wrote: > >> +} >> + >> +void kvm_vcpu_ipi(struct kvm_vcpu *vcpu) >> +{ >> + int me; >> + int cpu = vcpu->cpu; >> >> me = get_cpu(); >> - if (cpu != me&& (unsigned)cpu< nr_cpu_ids&& cpu_online(cpu)) >> - if (!test_and_set_bit(KVM_REQ_KICK,&vcpu->requests)) >> - smp_send_reschedule(cpu); >> + if (cpu != me&& (unsigned)cpu< nr_cpu_ids&& cpu_online(cpu)) { >> + if (test_bit(KVM_VCPU_GUEST_MODE,&vcpu->vcpu_state)) { >> + if (!test_and_set_bit(KVM_VCPU_KICKED, >> + &vcpu->vcpu_state)) >> + smp_send_reschedule(cpu); >> + } >> + } >> put_cpu(); >> } >> >> @@ -168,6 +176,30 @@ static bool make_all_cpus_request(struct >> return called; >> } >> >> +static int kvm_req_wait(void *unused) >> +{ >> + cpu_relax(); >> + return 0; >> +} >> + >> +static void kvm_vcpu_request(struct kvm_vcpu *vcpu, unsigned int req) >> +{ >> + set_bit(req,&vcpu->requests); >> + barrier(); >> + kvm_vcpu_ipi(vcpu); >> + wait_on_bit(&vcpu->vcpu_state, KVM_VCPU_GUEST_MODE, kvm_req_wait, >> + TASK_UNINTERRUPTIBLE); >> +} >> + >> +static void kvm_vcpus_request(struct kvm *kvm, unsigned int req) >> +{ >> + int i; >> + struct kvm_vcpu *vcpu; >> + >> + kvm_for_each_vcpu(i, vcpu, kvm) >> + kvm_vcpu_request(vcpu, req); >> +} >> > > Gleb notes there are two problems here: instead of using a multicast > IPI, you're sending multiple unicast IPIs. Second, you're serializing > the waiting. It would be better to batch-send the IPIs, then batch-wait > for results. Right. Playing with multiple variants of batched send/wait but so far haven't been able to see significant improvements for REQ_FLUSH/REQ_RELOAD. Batched send will probably be more visible in guest IPI emulation. Note however that even with multiple unicast IPIs this change collapses kvm_vcpu_kick with the remote requests, so you decrease the number of IPI's. Was hoping to include these changes incrementally? void kvm_vcpus_request(struct kvm *kvm, unsigned int req) { - int i; + int i, me, cpu; struct kvm_vcpu *vcpu; + cpumask_var_t wait_cpus, kick_cpus; + + if (alloc_cpumask_var(&wait_cpus, GFP_ATOMIC)) + cpumask_clear(wait_cpus); + + if (alloc_cpumask_var(&kick_cpus, GFP_ATOMIC)) + cpumask_clear(kick_cpus); + + me = get_cpu(); + kvm_for_each_vcpu(i, vcpu, kvm) { + set_bit(req, &vcpu->requests); + barrier(); + cpu = vcpu->cpu; + if (test_bit(KVM_VCPU_GUEST_MODE, &vcpu->vcpu_state)) { + if (cpu != -1 && cpu != me) { + if (wait_cpus != NULL) + cpumask_set_cpu(cpu, wait_cpus); + if (kick_cpus != NULL) + if (!test_and_set_bit(KVM_VCPU_KICKED, + &vcpu->vcpu_state)) + cpumask_set_cpu(cpu, kick_cpus); + } + } + } + if (unlikely(kick_cpus == NULL)) + smp_call_function_many(cpu_online_mask, ack_flush, + NULL, 1); + else if (!cpumask_empty(kick_cpus)) + smp_send_reschedule_many(kick_cpus); kvm_for_each_vcpu(i, vcpu, kvm) - kvm_vcpu_request(vcpu, req); + if (cpumask_test_cpu(vcpu->cpu, wait_cpus)) + if (test_bit(req, &vcpu->requests)) + wait_on_bit(&vcpu->vcpu_state, KVM_VCPU_GUEST_MODE, + kvm_req_wait, TASK_UNINTERRUPTIBLE); + put_cpu(); + + free_cpumask_var(wait_cpus); + free_cpumask_var(kick_cpus); } -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html