* [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks @ 2024-07-25 5:26 Saurabh Sengar 2024-07-25 15:23 ` Nuno Das Neves 2024-07-28 4:32 ` Michael Kelley 0 siblings, 2 replies; 13+ messages in thread From: Saurabh Sengar @ 2024-07-25 5:26 UTC (permalink / raw) To: kys, haiyangz, wei.liu, decui, linux-hyperv, linux-kernel Cc: ssengar, srivatsa Currently on a very large system with 1780 CPUs, hv_acpi_init takes around 3 seconds to complete for all the CPUs. This is because of sequential synic initialization for each CPU. Defer these tasks so that each CPU executes hv_acpi_init in parallel to take full advantage of multiple CPUs. This solution saves around 2 seconds of boot time on a 1780 CPU system, that around 66% improvement in the existing logic. Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> --- drivers/hv/vmbus_drv.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c index c857dc3975be..3395526ad0d0 100644 --- a/drivers/hv/vmbus_drv.c +++ b/drivers/hv/vmbus_drv.c @@ -1306,6 +1306,13 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static void vmbus_percpu_work(struct work_struct *work) +{ + unsigned int cpu = smp_processor_id(); + + hv_synic_init(cpu); +} + /* * vmbus_bus_init -Main vmbus driver initialization routine. * @@ -1316,7 +1323,8 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) */ static int vmbus_bus_init(void) { - int ret; + int ret, cpu; + struct work_struct __percpu *works; ret = hv_init(); if (ret != 0) { @@ -1355,12 +1363,31 @@ static int vmbus_bus_init(void) if (ret) goto err_alloc; + works = alloc_percpu(struct work_struct); + if (!works) { + ret = -ENOMEM; + goto err_alloc; + } + /* * Initialize the per-cpu interrupt state and stimer state. * Then connect to the host. */ - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", - hv_synic_init, hv_synic_cleanup); + cpus_read_lock(); + for_each_online_cpu(cpu) { + struct work_struct *work = per_cpu_ptr(works, cpu); + + INIT_WORK(work, vmbus_percpu_work); + schedule_work_on(cpu, work); + } + + for_each_online_cpu(cpu) + flush_work(per_cpu_ptr(works, cpu)); + + ret = __cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", false, + hv_synic_init, hv_synic_cleanup, false); + cpus_read_unlock(); + free_percpu(works); if (ret < 0) goto err_alloc; hyperv_cpuhp_online = ret; -- 2.43.0 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-25 5:26 [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks Saurabh Sengar @ 2024-07-25 15:23 ` Nuno Das Neves 2024-07-25 15:35 ` Saurabh Singh Sengar 2024-07-28 4:32 ` Michael Kelley 1 sibling, 1 reply; 13+ messages in thread From: Nuno Das Neves @ 2024-07-25 15:23 UTC (permalink / raw) To: Saurabh Sengar, kys, haiyangz, wei.liu, decui, linux-hyperv, linux-kernel Cc: ssengar, srivatsa On 7/24/2024 10:26 PM, Saurabh Sengar wrote: > Currently on a very large system with 1780 CPUs, hv_acpi_init takes > around 3 seconds to complete for all the CPUs. This is because of > sequential synic initialization for each CPU. > > Defer these tasks so that each CPU executes hv_acpi_init in parallel > to take full advantage of multiple CPUs. I think you mean hv_synic_init() here, not hv_acpi_init()? > > This solution saves around 2 seconds of boot time on a 1780 CPU system, > that around 66% improvement in the existing logic. > > Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> > --- > drivers/hv/vmbus_drv.c | 33 ++++++++++++++++++++++++++++++--- > 1 file changed, 30 insertions(+), 3 deletions(-) > LGTM otherwise. Reviewed-by: Nuno Das Neves <nunodasneves@linux.microsoft.com> ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-25 15:23 ` Nuno Das Neves @ 2024-07-25 15:35 ` Saurabh Singh Sengar 2024-07-26 0:01 ` Dexuan Cui 0 siblings, 1 reply; 13+ messages in thread From: Saurabh Singh Sengar @ 2024-07-25 15:35 UTC (permalink / raw) To: Nuno Das Neves Cc: kys, haiyangz, wei.liu, decui, linux-hyperv, linux-kernel, ssengar, srivatsa On Thu, Jul 25, 2024 at 08:23:21AM -0700, Nuno Das Neves wrote: > On 7/24/2024 10:26 PM, Saurabh Sengar wrote: > > Currently on a very large system with 1780 CPUs, hv_acpi_init takes > > around 3 seconds to complete for all the CPUs. This is because of > > sequential synic initialization for each CPU. > > > > Defer these tasks so that each CPU executes hv_acpi_init in parallel > > to take full advantage of multiple CPUs. > > I think you mean hv_synic_init() here, not hv_acpi_init()? Thanks, will send v2 correcting this. - Saurabh > > > > > This solution saves around 2 seconds of boot time on a 1780 CPU system, > > that around 66% improvement in the existing logic. > > > > Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> > > --- > > drivers/hv/vmbus_drv.c | 33 ++++++++++++++++++++++++++++++--- > > 1 file changed, 30 insertions(+), 3 deletions(-) > > > > LGTM otherwise. > > Reviewed-by: Nuno Das Neves <nunodasneves@linux.microsoft.com> ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-25 15:35 ` Saurabh Singh Sengar @ 2024-07-26 0:01 ` Dexuan Cui 2024-07-26 5:26 ` Saurabh Singh Sengar 2024-07-26 6:34 ` Srivatsa S. Bhat 0 siblings, 2 replies; 13+ messages in thread From: Dexuan Cui @ 2024-07-26 0:01 UTC (permalink / raw) To: Saurabh Singh Sengar, Nuno Das Neves Cc: KY Srinivasan, Haiyang Zhang, wei.liu@kernel.org, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, Saurabh Singh Sengar, srivatsa@csail.mit.edu > From: Saurabh Singh Sengar <ssengar@linux.microsoft.com> > Sent: Thursday, July 25, 2024 8:35 AM > Subject: Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks Without the patch, I think the current CPU uses IPIs to let the other CPUs, one by one, run the function calls, and synchronously waits for the function calls to finish. IMO the patch is not "Deferring per cpu tasks". "Defer" means "let it happen later". Here it schedules work items to different CPUs, and the work items immediately start to run on these CPUs. I would suggest a more accurate subject: Drivers: hv: vmbus: Run hv_synic_init() concurrently > - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, > "hyperv/vmbus:online", > - hv_synic_init, hv_synic_cleanup); > + cpus_read_lock(); > + for_each_online_cpu(cpu) { > + struct work_struct *work = per_cpu_ptr(works, cpu); > + > + INIT_WORK(work, vmbus_percpu_work); > + schedule_work_on(cpu, work); > + } > + > + for_each_online_cpu(cpu) > + flush_work(per_cpu_ptr(works, cpu)); > + Can you please add a comment to explain we need this for CPU online/offline'ing: > + ret = __cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, > "hyperv/vmbus:online", false, > + hv_synic_init, hv_synic_cleanup, > false); > + cpus_read_unlock(); Add an empty line here to make it slightly more readable? :-) > + free_percpu(works); > if (ret < 0) > goto err_alloc; Thanks, Dexuan ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-26 0:01 ` Dexuan Cui @ 2024-07-26 5:26 ` Saurabh Singh Sengar 2024-07-26 6:02 ` Dexuan Cui 2024-07-26 6:34 ` Srivatsa S. Bhat 1 sibling, 1 reply; 13+ messages in thread From: Saurabh Singh Sengar @ 2024-07-26 5:26 UTC (permalink / raw) To: Dexuan Cui Cc: Nuno Das Neves, KY Srinivasan, Haiyang Zhang, wei.liu@kernel.org, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, Saurabh Singh Sengar, srivatsa@csail.mit.edu On Fri, Jul 26, 2024 at 12:01:33AM +0000, Dexuan Cui wrote: > > From: Saurabh Singh Sengar <ssengar@linux.microsoft.com> > > Sent: Thursday, July 25, 2024 8:35 AM > > Subject: Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks > > Without the patch, I think the current CPU uses IPIs to let the other > CPUs, one by one, run the function calls, and synchronously waits > for the function calls to finish. > > IMO the patch is not "Deferring per cpu tasks". "Defer" means "let it > happen later". Here it schedules work items to different CPUs, and > the work items immediately start to run on these CPUs. > > I would suggest a more accurate subject: > Drivers: hv: vmbus: Run hv_synic_init() concurrently Agree, this explains the change better. > > > - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, > > "hyperv/vmbus:online", > > - hv_synic_init, hv_synic_cleanup); > > + cpus_read_lock(); > > + for_each_online_cpu(cpu) { > > + struct work_struct *work = per_cpu_ptr(works, cpu); > > + > > + INIT_WORK(work, vmbus_percpu_work); > > + schedule_work_on(cpu, work); > > + } > > + > > + for_each_online_cpu(cpu) > > + flush_work(per_cpu_ptr(works, cpu)); > > + > > Can you please add a comment to explain we need this for CPU online/offline'ing: ok > > + ret = __cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, > > "hyperv/vmbus:online", false, > > + hv_synic_init, hv_synic_cleanup, > > false); > > + cpus_read_unlock(); > > Add an empty line here to make it slightly more readable? :-) My personal preference was to have empty line as well here, but then I looked the other places in this file where we used cpus_read_unlock, hence I maintained that style consistent. Please let me know if you have strong opinion about this empty line, I can add in V2. - Saurabh > > + free_percpu(works); > > if (ret < 0) > > goto err_alloc; > > Thanks, > Dexuan > > ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-26 5:26 ` Saurabh Singh Sengar @ 2024-07-26 6:02 ` Dexuan Cui 0 siblings, 0 replies; 13+ messages in thread From: Dexuan Cui @ 2024-07-26 6:02 UTC (permalink / raw) To: Saurabh Singh Sengar Cc: Nuno Das Neves, KY Srinivasan, Haiyang Zhang, wei.liu@kernel.org, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, Saurabh Singh Sengar, srivatsa@csail.mit.edu > From: Saurabh Singh Sengar <ssengar@linux.microsoft.com> > Sent: Thursday, July 25, 2024 10:27 PM > [...] > > > + ret = __cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, > > > "hyperv/vmbus:online", false, > > > + hv_synic_init, hv_synic_cleanup, > > > false); > > > + cpus_read_unlock(); > > > > Add an empty line here to make it slightly more readable? :-) > > My personal preference was to have empty line as well here, but then I > looked the > other places in this file where we used cpus_read_unlock, hence I > maintained that style consistent. > > Please let me know if you have strong opinion about this empty line, I can > add in V2. > > - Saurabh I have no strong opinion here :-) ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-26 0:01 ` Dexuan Cui 2024-07-26 5:26 ` Saurabh Singh Sengar @ 2024-07-26 6:34 ` Srivatsa S. Bhat 2024-07-26 11:26 ` Saurabh Singh Sengar 1 sibling, 1 reply; 13+ messages in thread From: Srivatsa S. Bhat @ 2024-07-26 6:34 UTC (permalink / raw) To: Dexuan Cui Cc: Saurabh Singh Sengar, Nuno Das Neves, KY Srinivasan, Haiyang Zhang, wei.liu@kernel.org, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, Saurabh Singh Sengar On Fri, Jul 26, 2024 at 12:01:33AM +0000, Dexuan Cui wrote: > > From: Saurabh Singh Sengar <ssengar@linux.microsoft.com> > > Sent: Thursday, July 25, 2024 8:35 AM > > Subject: Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks > > Without the patch, I think the current CPU uses IPIs to let the other > CPUs, one by one, run the function calls, and synchronously waits > for the function calls to finish. > > IMO the patch is not "Deferring per cpu tasks". "Defer" means "let it > happen later". Here it schedules work items to different CPUs, and > the work items immediately start to run on these CPUs. > > I would suggest a more accurate subject: > Drivers: hv: vmbus: Run hv_synic_init() concurrently > It would be great to call out the "why" as well in the title, something like: Drivers: hv: vmbus: Speed-up booting by running hv_synic_init() concurrently Regards, Srivatsa Microsoft Linux Systems Group ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-26 6:34 ` Srivatsa S. Bhat @ 2024-07-26 11:26 ` Saurabh Singh Sengar 2024-07-27 12:53 ` Srivatsa S. Bhat 0 siblings, 1 reply; 13+ messages in thread From: Saurabh Singh Sengar @ 2024-07-26 11:26 UTC (permalink / raw) To: Srivatsa S. Bhat Cc: Dexuan Cui, Nuno Das Neves, KY Srinivasan, Haiyang Zhang, wei.liu@kernel.org, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, Saurabh Singh Sengar On Fri, Jul 26, 2024 at 06:34:53AM +0000, Srivatsa S. Bhat wrote: > On Fri, Jul 26, 2024 at 12:01:33AM +0000, Dexuan Cui wrote: > > > From: Saurabh Singh Sengar <ssengar@linux.microsoft.com> > > > Sent: Thursday, July 25, 2024 8:35 AM > > > Subject: Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks > > > > Without the patch, I think the current CPU uses IPIs to let the other > > CPUs, one by one, run the function calls, and synchronously waits > > for the function calls to finish. > > > > IMO the patch is not "Deferring per cpu tasks". "Defer" means "let it > > happen later". Here it schedules work items to different CPUs, and > > the work items immediately start to run on these CPUs. > > > > I would suggest a more accurate subject: > > Drivers: hv: vmbus: Run hv_synic_init() concurrently > > > > It would be great to call out the "why" as well in the title, > something like: > > Drivers: hv: vmbus: Speed-up booting by running hv_synic_init() concurrently Thanks, I can also rephrase it like below if sounds fine to you: Drivers: hv: vmbus: Optimize boot time by concurrent execution of hv_synic_init() - Saurabh > > Regards, > Srivatsa > Microsoft Linux Systems Group ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-26 11:26 ` Saurabh Singh Sengar @ 2024-07-27 12:53 ` Srivatsa S. Bhat 0 siblings, 0 replies; 13+ messages in thread From: Srivatsa S. Bhat @ 2024-07-27 12:53 UTC (permalink / raw) To: Saurabh Singh Sengar Cc: Dexuan Cui, Nuno Das Neves, KY Srinivasan, Haiyang Zhang, wei.liu@kernel.org, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, Saurabh Singh Sengar On Fri, Jul 26, 2024 at 04:26:19AM -0700, Saurabh Singh Sengar wrote: > On Fri, Jul 26, 2024 at 06:34:53AM +0000, Srivatsa S. Bhat wrote: > > On Fri, Jul 26, 2024 at 12:01:33AM +0000, Dexuan Cui wrote: > > > > From: Saurabh Singh Sengar <ssengar@linux.microsoft.com> > > > > Sent: Thursday, July 25, 2024 8:35 AM > > > > Subject: Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks > > > > > > Without the patch, I think the current CPU uses IPIs to let the other > > > CPUs, one by one, run the function calls, and synchronously waits > > > for the function calls to finish. > > > > > > IMO the patch is not "Deferring per cpu tasks". "Defer" means "let it > > > happen later". Here it schedules work items to different CPUs, and > > > the work items immediately start to run on these CPUs. > > > > > > I would suggest a more accurate subject: > > > Drivers: hv: vmbus: Run hv_synic_init() concurrently > > > > > > > It would be great to call out the "why" as well in the title, > > something like: > > > > Drivers: hv: vmbus: Speed-up booting by running hv_synic_init() concurrently > > Thanks, I can also rephrase it like below if sounds fine to you: > > Drivers: hv: vmbus: Optimize boot time by concurrent execution of hv_synic_init() > Sure, that sounds good too. Regards, Srivatsa Microsoft Linux Systems Group ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-25 5:26 [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks Saurabh Sengar 2024-07-25 15:23 ` Nuno Das Neves @ 2024-07-28 4:32 ` Michael Kelley 2024-07-28 9:18 ` Saurabh Singh Sengar 1 sibling, 1 reply; 13+ messages in thread From: Michael Kelley @ 2024-07-28 4:32 UTC (permalink / raw) To: Saurabh Sengar, kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org Cc: ssengar@microsoft.com, srivatsa@csail.mit.edu From: Saurabh Sengar <ssengar@linux.microsoft.com> Sent: Wednesday, July 24, 2024 10:26 PM > > Currently on a very large system with 1780 CPUs, hv_acpi_init takes > around 3 seconds to complete for all the CPUs. This is because of > sequential synic initialization for each CPU. > > Defer these tasks so that each CPU executes hv_acpi_init in parallel > to take full advantage of multiple CPUs. > > This solution saves around 2 seconds of boot time on a 1780 CPU system, > that around 66% improvement in the existing logic. > > Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> > --- > drivers/hv/vmbus_drv.c | 33 ++++++++++++++++++++++++++++++--- > 1 file changed, 30 insertions(+), 3 deletions(-) > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > index c857dc3975be..3395526ad0d0 100644 > --- a/drivers/hv/vmbus_drv.c > +++ b/drivers/hv/vmbus_drv.c > @@ -1306,6 +1306,13 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) > return IRQ_HANDLED; > } > > +static void vmbus_percpu_work(struct work_struct *work) > +{ > + unsigned int cpu = smp_processor_id(); > + > + hv_synic_init(cpu); > +} > + > /* > * vmbus_bus_init -Main vmbus driver initialization routine. > * > @@ -1316,7 +1323,8 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) > */ > static int vmbus_bus_init(void) > { > - int ret; > + int ret, cpu; > + struct work_struct __percpu *works; > > ret = hv_init(); > if (ret != 0) { > @@ -1355,12 +1363,31 @@ static int vmbus_bus_init(void) > if (ret) > goto err_alloc; > > + works = alloc_percpu(struct work_struct); > + if (!works) { > + ret = -ENOMEM; > + goto err_alloc; > + } > + > /* > * Initialize the per-cpu interrupt state and stimer state. > * Then connect to the host. > */ > - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", > - hv_synic_init, hv_synic_cleanup); > + cpus_read_lock(); > + for_each_online_cpu(cpu) { > + struct work_struct *work = per_cpu_ptr(works, cpu); > + > + INIT_WORK(work, vmbus_percpu_work); > + schedule_work_on(cpu, work); > + } > + > + for_each_online_cpu(cpu) > + flush_work(per_cpu_ptr(works, cpu)); > + > + ret = __cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", false, > + hv_synic_init, hv_synic_cleanup, false); I'd suggest using cpuhp_setup_state_nocalls_cpuslocked(). It appears to be the interface intended for users outside the cpuhotplug code, whereas __cpuhp_setup_state_cpuslocked() should be private to the cpuhotplug code. Michael > + cpus_read_unlock(); > + free_percpu(works); > if (ret < 0) > goto err_alloc; > hyperv_cpuhp_online = ret; > -- > 2.43.0 > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-28 4:32 ` Michael Kelley @ 2024-07-28 9:18 ` Saurabh Singh Sengar 2024-07-28 14:06 ` Michael Kelley 0 siblings, 1 reply; 13+ messages in thread From: Saurabh Singh Sengar @ 2024-07-28 9:18 UTC (permalink / raw) To: Michael Kelley Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, ssengar@microsoft.com, srivatsa@csail.mit.edu On Sun, Jul 28, 2024 at 04:32:23AM +0000, Michael Kelley wrote: > From: Saurabh Sengar <ssengar@linux.microsoft.com> Sent: Wednesday, July 24, 2024 10:26 PM > > > > Currently on a very large system with 1780 CPUs, hv_acpi_init takes > > around 3 seconds to complete for all the CPUs. This is because of > > sequential synic initialization for each CPU. > > > > Defer these tasks so that each CPU executes hv_acpi_init in parallel > > to take full advantage of multiple CPUs. > > > > This solution saves around 2 seconds of boot time on a 1780 CPU system, > > that around 66% improvement in the existing logic. > > > > Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> > > --- > > drivers/hv/vmbus_drv.c | 33 ++++++++++++++++++++++++++++++--- > > 1 file changed, 30 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > > index c857dc3975be..3395526ad0d0 100644 > > --- a/drivers/hv/vmbus_drv.c > > +++ b/drivers/hv/vmbus_drv.c > > @@ -1306,6 +1306,13 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) > > return IRQ_HANDLED; > > } > > > > +static void vmbus_percpu_work(struct work_struct *work) > > +{ > > + unsigned int cpu = smp_processor_id(); > > + > > + hv_synic_init(cpu); > > +} > > + > > /* > > * vmbus_bus_init -Main vmbus driver initialization routine. > > * > > @@ -1316,7 +1323,8 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) > > */ > > static int vmbus_bus_init(void) > > { > > - int ret; > > + int ret, cpu; > > + struct work_struct __percpu *works; > > > > ret = hv_init(); > > if (ret != 0) { > > @@ -1355,12 +1363,31 @@ static int vmbus_bus_init(void) > > if (ret) > > goto err_alloc; > > > > + works = alloc_percpu(struct work_struct); > > + if (!works) { > > + ret = -ENOMEM; > > + goto err_alloc; > > + } > > + > > /* > > * Initialize the per-cpu interrupt state and stimer state. > > * Then connect to the host. > > */ > > - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", > > - hv_synic_init, hv_synic_cleanup); > > + cpus_read_lock(); > > + for_each_online_cpu(cpu) { > > + struct work_struct *work = per_cpu_ptr(works, cpu); > > + > > + INIT_WORK(work, vmbus_percpu_work); > > + schedule_work_on(cpu, work); > > + } > > + > > + for_each_online_cpu(cpu) > > + flush_work(per_cpu_ptr(works, cpu)); > > + > > + ret = __cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", false, > > + hv_synic_init, hv_synic_cleanup, false); > > I'd suggest using cpuhp_setup_state_nocalls_cpuslocked(). It appears to be > the interface intended for users outside the cpuhotplug code, whereas > __cpuhp_setup_state_cpuslocked() should be private to the cpuhotplug code. > Thanks for your review. The function cpuhp_setup_state_nocalls_cpuslocked() is commonly used across the kernel drivers hence it was a first choice for me as well. However, it includes a cpus_read_lock that we already introduced separately in above code. To avoid recursive locking, I opted for __cpuhp_setup_state_cpuslocked. One might argue that unlocking and then calling cpuhp_setup_state_nocalls_cpuslocked could be a solution, but I am concerned about potential race conditions, as CPUs could come online during this interval and in such case synic initialization for those CPUs would be missed. - Saurabh ^ permalink raw reply [flat|nested] 13+ messages in thread
* RE: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-28 9:18 ` Saurabh Singh Sengar @ 2024-07-28 14:06 ` Michael Kelley 2024-07-28 15:40 ` Saurabh Singh Sengar 0 siblings, 1 reply; 13+ messages in thread From: Michael Kelley @ 2024-07-28 14:06 UTC (permalink / raw) To: Saurabh Singh Sengar Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, ssengar@microsoft.com, srivatsa@csail.mit.edu From: Saurabh Singh Sengar <ssengar@linux.microsoft.com> Sent: Sunday, July 28, 2024 2:18 AM > > On Sun, Jul 28, 2024 at 04:32:23AM +0000, Michael Kelley wrote: > > From: Saurabh Sengar <ssengar@linux.microsoft.com> Sent: Wednesday, July 24, > 2024 10:26 PM > > > > > > Currently on a very large system with 1780 CPUs, hv_acpi_init takes > > > around 3 seconds to complete for all the CPUs. This is because of > > > sequential synic initialization for each CPU. > > > > > > Defer these tasks so that each CPU executes hv_acpi_init in parallel > > > to take full advantage of multiple CPUs. > > > > > > This solution saves around 2 seconds of boot time on a 1780 CPU system, > > > that around 66% improvement in the existing logic. > > > > > > Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> > > > --- > > > drivers/hv/vmbus_drv.c | 33 ++++++++++++++++++++++++++++++--- > > > 1 file changed, 30 insertions(+), 3 deletions(-) > > > > > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > > > index c857dc3975be..3395526ad0d0 100644 > > > --- a/drivers/hv/vmbus_drv.c > > > +++ b/drivers/hv/vmbus_drv.c > > > @@ -1306,6 +1306,13 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) > > > return IRQ_HANDLED; > > > } > > > > > > +static void vmbus_percpu_work(struct work_struct *work) > > > +{ > > > + unsigned int cpu = smp_processor_id(); > > > + > > > + hv_synic_init(cpu); > > > +} > > > + > > > /* > > > * vmbus_bus_init -Main vmbus driver initialization routine. > > > * > > > @@ -1316,7 +1323,8 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) > > > */ > > > static int vmbus_bus_init(void) > > > { > > > - int ret; > > > + int ret, cpu; > > > + struct work_struct __percpu *works; > > > > > > ret = hv_init(); > > > if (ret != 0) { > > > @@ -1355,12 +1363,31 @@ static int vmbus_bus_init(void) > > > if (ret) > > > goto err_alloc; > > > > > > + works = alloc_percpu(struct work_struct); > > > + if (!works) { > > > + ret = -ENOMEM; > > > + goto err_alloc; > > > + } > > > + > > > /* > > > * Initialize the per-cpu interrupt state and stimer state. > > > * Then connect to the host. > > > */ > > > - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", > > > - hv_synic_init, hv_synic_cleanup); > > > + cpus_read_lock(); > > > + for_each_online_cpu(cpu) { > > > + struct work_struct *work = per_cpu_ptr(works, cpu); > > > + > > > + INIT_WORK(work, vmbus_percpu_work); > > > + schedule_work_on(cpu, work); > > > + } > > > + > > > + for_each_online_cpu(cpu) > > > + flush_work(per_cpu_ptr(works, cpu)); > > > + > > > + ret = __cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", false, > > > + hv_synic_init, hv_synic_cleanup, false); > > > > I'd suggest using cpuhp_setup_state_nocalls_cpuslocked(). It appears to be > > the interface intended for users outside the cpuhotplug code, whereas > > __cpuhp_setup_state_cpuslocked() should be private to the cpuhotplug code. > > > > Thanks for your review. > > The function cpuhp_setup_state_nocalls_cpuslocked() is commonly used across the > kernel drivers hence it was a first choice for me as well. However, it includes a > cpus_read_lock that we already introduced separately in above code. To avoid recursive > locking, I opted for __cpuhp_setup_state_cpuslocked. cpuhp_setup_state_nocalls() includes the cpus_read_lock() as you describe. But cpuhp_setup_state_nocalls_cpuslocked() explicitly assumes that the cpus_read_lock() is already held, so is suitable for use in this case. There are several variants with the _cpuslocked suffix, which indicates that the caller is responsible for the cpus_read_lock(). Michael > > One might argue that unlocking and then calling cpuhp_setup_state_nocalls_cpuslocked > could be a solution, but I am concerned about potential race conditions, as CPUs could > come online during this interval and in such case synic initialization for those CPUs > would be missed. > > - Saurabh ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks 2024-07-28 14:06 ` Michael Kelley @ 2024-07-28 15:40 ` Saurabh Singh Sengar 0 siblings, 0 replies; 13+ messages in thread From: Saurabh Singh Sengar @ 2024-07-28 15:40 UTC (permalink / raw) To: Michael Kelley Cc: kys@microsoft.com, haiyangz@microsoft.com, wei.liu@kernel.org, decui@microsoft.com, linux-hyperv@vger.kernel.org, linux-kernel@vger.kernel.org, ssengar@microsoft.com, srivatsa@csail.mit.edu On Sun, Jul 28, 2024 at 02:06:41PM +0000, Michael Kelley wrote: > From: Saurabh Singh Sengar <ssengar@linux.microsoft.com> Sent: Sunday, July 28, 2024 2:18 AM > > > > On Sun, Jul 28, 2024 at 04:32:23AM +0000, Michael Kelley wrote: > > > From: Saurabh Sengar <ssengar@linux.microsoft.com> Sent: Wednesday, July 24, > > 2024 10:26 PM > > > > > > > > Currently on a very large system with 1780 CPUs, hv_acpi_init takes > > > > around 3 seconds to complete for all the CPUs. This is because of > > > > sequential synic initialization for each CPU. > > > > > > > > Defer these tasks so that each CPU executes hv_acpi_init in parallel > > > > to take full advantage of multiple CPUs. > > > > > > > > This solution saves around 2 seconds of boot time on a 1780 CPU system, > > > > that around 66% improvement in the existing logic. > > > > > > > > Signed-off-by: Saurabh Sengar <ssengar@linux.microsoft.com> > > > > --- > > > > drivers/hv/vmbus_drv.c | 33 ++++++++++++++++++++++++++++++--- > > > > 1 file changed, 30 insertions(+), 3 deletions(-) > > > > > > > > diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c > > > > index c857dc3975be..3395526ad0d0 100644 > > > > --- a/drivers/hv/vmbus_drv.c > > > > +++ b/drivers/hv/vmbus_drv.c > > > > @@ -1306,6 +1306,13 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) > > > > return IRQ_HANDLED; > > > > } > > > > > > > > +static void vmbus_percpu_work(struct work_struct *work) > > > > +{ > > > > + unsigned int cpu = smp_processor_id(); > > > > + > > > > + hv_synic_init(cpu); > > > > +} > > > > + > > > > /* > > > > * vmbus_bus_init -Main vmbus driver initialization routine. > > > > * > > > > @@ -1316,7 +1323,8 @@ static irqreturn_t vmbus_percpu_isr(int irq, void *dev_id) > > > > */ > > > > static int vmbus_bus_init(void) > > > > { > > > > - int ret; > > > > + int ret, cpu; > > > > + struct work_struct __percpu *works; > > > > > > > > ret = hv_init(); > > > > if (ret != 0) { > > > > @@ -1355,12 +1363,31 @@ static int vmbus_bus_init(void) > > > > if (ret) > > > > goto err_alloc; > > > > > > > > + works = alloc_percpu(struct work_struct); > > > > + if (!works) { > > > > + ret = -ENOMEM; > > > > + goto err_alloc; > > > > + } > > > > + > > > > /* > > > > * Initialize the per-cpu interrupt state and stimer state. > > > > * Then connect to the host. > > > > */ > > > > - ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", > > > > - hv_synic_init, hv_synic_cleanup); > > > > + cpus_read_lock(); > > > > + for_each_online_cpu(cpu) { > > > > + struct work_struct *work = per_cpu_ptr(works, cpu); > > > > + > > > > + INIT_WORK(work, vmbus_percpu_work); > > > > + schedule_work_on(cpu, work); > > > > + } > > > > + > > > > + for_each_online_cpu(cpu) > > > > + flush_work(per_cpu_ptr(works, cpu)); > > > > + > > > > + ret = __cpuhp_setup_state_cpuslocked(CPUHP_AP_ONLINE_DYN, "hyperv/vmbus:online", false, > > > > + hv_synic_init, hv_synic_cleanup, false); > > > > > > I'd suggest using cpuhp_setup_state_nocalls_cpuslocked(). It appears to be > > > the interface intended for users outside the cpuhotplug code, whereas > > > __cpuhp_setup_state_cpuslocked() should be private to the cpuhotplug code. > > > > > > > Thanks for your review. > > > > The function cpuhp_setup_state_nocalls_cpuslocked() is commonly used across the > > kernel drivers hence it was a first choice for me as well. However, it includes a > > cpus_read_lock that we already introduced separately in above code. To avoid recursive > > locking, I opted for __cpuhp_setup_state_cpuslocked. > > cpuhp_setup_state_nocalls() includes the cpus_read_lock() as you describe. > But cpuhp_setup_state_nocalls_cpuslocked() explicitly assumes that the > cpus_read_lock() is already held, so is suitable for use in this case. There are > several variants with the _cpuslocked suffix, which indicates that the caller > is responsible for the cpus_read_lock(). > Thank you for the clarification. I will fix this up in v2. - Saurabh ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2024-07-28 15:40 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-07-25 5:26 [PATCH] Drivers: hv: vmbus: Deferring per cpu tasks Saurabh Sengar 2024-07-25 15:23 ` Nuno Das Neves 2024-07-25 15:35 ` Saurabh Singh Sengar 2024-07-26 0:01 ` Dexuan Cui 2024-07-26 5:26 ` Saurabh Singh Sengar 2024-07-26 6:02 ` Dexuan Cui 2024-07-26 6:34 ` Srivatsa S. Bhat 2024-07-26 11:26 ` Saurabh Singh Sengar 2024-07-27 12:53 ` Srivatsa S. Bhat 2024-07-28 4:32 ` Michael Kelley 2024-07-28 9:18 ` Saurabh Singh Sengar 2024-07-28 14:06 ` Michael Kelley 2024-07-28 15:40 ` Saurabh Singh Sengar
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox