Re: [patch 2/5] KVM: reintroduce guest mode bit and unify remote request code

Marcelo Tosatti
2009-08-27T12:58:50Z

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);
}