2024-01-30 07:22:52

by maobibo

[permalink] [raw]
Subject: [PATCH 0/2] LoongArch: KVM: Start SW timer only when vcpu is blocking

SW timer is enabled when vcpu thread is scheduled out, and it is
to wake up vcpu from blocked queue. If vcpu thread is scheduled out
however is not blocked, such as it is preempted by other threads,
it is not necessary to enable SW timer. Since vcpu thread is still
on running queue and SW timer is only to wake up tasks on blocking
queue, so SW timer is not useful in this situation.

This patch enables SW timer only when vcpu is scheduled out and
is blocking. Also when SW timer is expired, it only wakes up vcpu
thread in blocking queue and need not restart SW timer.

Bibo Mao (2):
LoongArch: KVM: Start SW timer only when vcpu is blocking
LoongArch: KVM: Do not restart SW timer when it is expired

arch/loongarch/kvm/timer.c | 42 ++++++++------------------------------
1 file changed, 9 insertions(+), 33 deletions(-)


base-commit: 41bccc98fb7931d63d03f326a746ac4d429c1dd3
--
2.39.3



2024-01-30 07:23:29

by maobibo

[permalink] [raw]
Subject: [PATCH 2/2] LoongArch: KVM: Do not restart SW timer when it is expired

LoongArch guest has separate hw timer, SW timer is to wake up
blocked vcpu thread, rather than HW timer emulation. When blocking
vcpu schedules out, SW timer is used to wakeup blocked vcpu thread
and injects timer interrupt. It does not care about whether guest
timer is in period mode or oneshot mode, and SW timer needs not be
restarted since vcpu has been woken.

This patch does not restart sw timer when it is expired.

Signed-off-by: Bibo Mao <[email protected]>
---
arch/loongarch/kvm/timer.c | 20 +-------------------
1 file changed, 1 insertion(+), 19 deletions(-)

diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c
index a9125f0a12d1..d3282f01d4d9 100644
--- a/arch/loongarch/kvm/timer.c
+++ b/arch/loongarch/kvm/timer.c
@@ -23,24 +23,6 @@ static inline u64 tick_to_ns(struct kvm_vcpu *vcpu, u64 tick)
return div_u64(tick * MNSEC_PER_SEC, vcpu->arch.timer_mhz);
}

-/*
- * Push timer forward on timeout.
- * Handle an hrtimer event by push the hrtimer forward a period.
- */
-static enum hrtimer_restart kvm_count_timeout(struct kvm_vcpu *vcpu)
-{
- unsigned long cfg, period;
-
- /* Add periodic tick to current expire time */
- cfg = kvm_read_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TCFG);
- if (cfg & CSR_TCFG_PERIOD) {
- period = tick_to_ns(vcpu, cfg & CSR_TCFG_VAL);
- hrtimer_add_expires_ns(&vcpu->arch.swtimer, period);
- return HRTIMER_RESTART;
- } else
- return HRTIMER_NORESTART;
-}
-
/* Low level hrtimer wake routine */
enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer)
{
@@ -50,7 +32,7 @@ enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer)
kvm_queue_irq(vcpu, INT_TI);
rcuwait_wake_up(&vcpu->wait);

- return kvm_count_timeout(vcpu);
+ return HRTIMER_NORESTART;
}

/*
--
2.39.3


2024-01-30 07:25:54

by maobibo

[permalink] [raw]
Subject: [PATCH 1/2] LoongArch: KVM: Start SW timer only when vcpu is blocking

SW timer is enabled when vcpu thread is scheduled out, and it is
to wake up vcpu from blocked queue. If vcpu thread is scheduled out
however is not blocked, such as it is preempted by other threads,
it is not necessary to enable SW timer. Since vcpu thread is still
on running queue if preempted and SW timer is only to wake up vcpu
on blocking queue, so SW timer is not useful in this situation.

This patch enables SW timer only when vcpu is scheduled out and
is blocking.

Signed-off-by: Bibo Mao <[email protected]>
---
arch/loongarch/kvm/timer.c | 22 ++++++++--------------
1 file changed, 8 insertions(+), 14 deletions(-)

diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c
index 111328f60872..a9125f0a12d1 100644
--- a/arch/loongarch/kvm/timer.c
+++ b/arch/loongarch/kvm/timer.c
@@ -93,7 +93,8 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu)
/*
* Freeze the soft-timer and sync the guest stable timer with it.
*/
- hrtimer_cancel(&vcpu->arch.swtimer);
+ if (kvm_vcpu_is_blocking(vcpu))
+ hrtimer_cancel(&vcpu->arch.swtimer);

/*
* From LoongArch Reference Manual Volume 1 Chapter 7.6.2
@@ -168,26 +169,19 @@ static void _kvm_save_timer(struct kvm_vcpu *vcpu)
* Here judge one-shot timer fired by checking whether TVAL is larger
* than TCFG
*/
- if (ticks < cfg) {
+ if (ticks < cfg)
delta = tick_to_ns(vcpu, ticks);
- expire = ktime_add_ns(ktime_get(), delta);
- vcpu->arch.expire = expire;
+ else
+ delta = 0;
+ expire = ktime_add_ns(ktime_get(), delta);
+ vcpu->arch.expire = expire;
+ if (kvm_vcpu_is_blocking(vcpu)) {

/*
* HRTIMER_MODE_PINNED is suggested since vcpu may run in
* the same physical cpu in next time
*/
hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
- } else if (vcpu->stat.generic.blocking) {
- /*
- * Inject timer interrupt so that halt polling can dectect and exit.
- * VCPU is scheduled out already and sleeps in rcuwait queue and
- * will not poll pending events again. kvm_queue_irq() is not enough,
- * hrtimer swtimer should be used here.
- */
- expire = ktime_add_ns(ktime_get(), 10);
- vcpu->arch.expire = expire;
- hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
}
}

--
2.39.3


2024-02-26 12:59:58

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH 1/2] LoongArch: KVM: Start SW timer only when vcpu is blocking

Queued for loongarch-kvm, thanks.

Huacai

On Tue, Jan 30, 2024 at 3:22 PM Bibo Mao <[email protected]> wrote:
>
> SW timer is enabled when vcpu thread is scheduled out, and it is
> to wake up vcpu from blocked queue. If vcpu thread is scheduled out
> however is not blocked, such as it is preempted by other threads,
> it is not necessary to enable SW timer. Since vcpu thread is still
> on running queue if preempted and SW timer is only to wake up vcpu
> on blocking queue, so SW timer is not useful in this situation.
>
> This patch enables SW timer only when vcpu is scheduled out and
> is blocking.
>
> Signed-off-by: Bibo Mao <[email protected]>
> ---
> arch/loongarch/kvm/timer.c | 22 ++++++++--------------
> 1 file changed, 8 insertions(+), 14 deletions(-)
>
> diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c
> index 111328f60872..a9125f0a12d1 100644
> --- a/arch/loongarch/kvm/timer.c
> +++ b/arch/loongarch/kvm/timer.c
> @@ -93,7 +93,8 @@ void kvm_restore_timer(struct kvm_vcpu *vcpu)
> /*
> * Freeze the soft-timer and sync the guest stable timer with it.
> */
> - hrtimer_cancel(&vcpu->arch.swtimer);
> + if (kvm_vcpu_is_blocking(vcpu))
> + hrtimer_cancel(&vcpu->arch.swtimer);
>
> /*
> * From LoongArch Reference Manual Volume 1 Chapter 7.6.2
> @@ -168,26 +169,19 @@ static void _kvm_save_timer(struct kvm_vcpu *vcpu)
> * Here judge one-shot timer fired by checking whether TVAL is larger
> * than TCFG
> */
> - if (ticks < cfg) {
> + if (ticks < cfg)
> delta = tick_to_ns(vcpu, ticks);
> - expire = ktime_add_ns(ktime_get(), delta);
> - vcpu->arch.expire = expire;
> + else
> + delta = 0;
> + expire = ktime_add_ns(ktime_get(), delta);
> + vcpu->arch.expire = expire;
> + if (kvm_vcpu_is_blocking(vcpu)) {
>
> /*
> * HRTIMER_MODE_PINNED is suggested since vcpu may run in
> * the same physical cpu in next time
> */
> hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
> - } else if (vcpu->stat.generic.blocking) {
> - /*
> - * Inject timer interrupt so that halt polling can dectect and exit.
> - * VCPU is scheduled out already and sleeps in rcuwait queue and
> - * will not poll pending events again. kvm_queue_irq() is not enough,
> - * hrtimer swtimer should be used here.
> - */
> - expire = ktime_add_ns(ktime_get(), 10);
> - vcpu->arch.expire = expire;
> - hrtimer_start(&vcpu->arch.swtimer, expire, HRTIMER_MODE_ABS_PINNED);
> }
> }
>
> --
> 2.39.3
>

2024-02-26 13:02:46

by Huacai Chen

[permalink] [raw]
Subject: Re: [PATCH 2/2] LoongArch: KVM: Do not restart SW timer when it is expired

The code itself looks good to me, but could you please tell me what
does "LoongArch guest has separate hw timer" mean?

Huacai

On Tue, Jan 30, 2024 at 3:22 PM Bibo Mao <[email protected]> wrote:
>
> LoongArch guest has separate hw timer, SW timer is to wake up
> blocked vcpu thread, rather than HW timer emulation. When blocking
> vcpu schedules out, SW timer is used to wakeup blocked vcpu thread
> and injects timer interrupt. It does not care about whether guest
> timer is in period mode or oneshot mode, and SW timer needs not be
> restarted since vcpu has been woken.
>
> This patch does not restart sw timer when it is expired.
>
> Signed-off-by: Bibo Mao <[email protected]>
> ---
> arch/loongarch/kvm/timer.c | 20 +-------------------
> 1 file changed, 1 insertion(+), 19 deletions(-)
>
> diff --git a/arch/loongarch/kvm/timer.c b/arch/loongarch/kvm/timer.c
> index a9125f0a12d1..d3282f01d4d9 100644
> --- a/arch/loongarch/kvm/timer.c
> +++ b/arch/loongarch/kvm/timer.c
> @@ -23,24 +23,6 @@ static inline u64 tick_to_ns(struct kvm_vcpu *vcpu, u64 tick)
> return div_u64(tick * MNSEC_PER_SEC, vcpu->arch.timer_mhz);
> }
>
> -/*
> - * Push timer forward on timeout.
> - * Handle an hrtimer event by push the hrtimer forward a period.
> - */
> -static enum hrtimer_restart kvm_count_timeout(struct kvm_vcpu *vcpu)
> -{
> - unsigned long cfg, period;
> -
> - /* Add periodic tick to current expire time */
> - cfg = kvm_read_sw_gcsr(vcpu->arch.csr, LOONGARCH_CSR_TCFG);
> - if (cfg & CSR_TCFG_PERIOD) {
> - period = tick_to_ns(vcpu, cfg & CSR_TCFG_VAL);
> - hrtimer_add_expires_ns(&vcpu->arch.swtimer, period);
> - return HRTIMER_RESTART;
> - } else
> - return HRTIMER_NORESTART;
> -}
> -
> /* Low level hrtimer wake routine */
> enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer)
> {
> @@ -50,7 +32,7 @@ enum hrtimer_restart kvm_swtimer_wakeup(struct hrtimer *timer)
> kvm_queue_irq(vcpu, INT_TI);
> rcuwait_wake_up(&vcpu->wait);
>
> - return kvm_count_timeout(vcpu);
> + return HRTIMER_NORESTART;
> }
>
> /*
> --
> 2.39.3
>