Hao Xiang <hao.xi...@bytedance.com> writes: > Multifd sender path gets an array of pages queued by the migration > thread. It performs zero page checking on every page in the array. > The pages are classfied as either a zero page or a normal page. This > change uses Intel DSA to offload the zero page checking from CPU to > the DSA accelerator. The sender thread submits a batch of pages to DSA > hardware and waits for the DSA completion thread to signal for work > completion. > > Signed-off-by: Hao Xiang <hao.xi...@bytedance.com> > --- > migration/multifd.c | 101 +++++++++++++++++++++++++++++++++++++------- > migration/multifd.h | 3 ++ > 2 files changed, 89 insertions(+), 15 deletions(-) > > diff --git a/migration/multifd.c b/migration/multifd.c > index 452fb158b8..79fecbd3ae 100644 > --- a/migration/multifd.c > +++ b/migration/multifd.c > @@ -13,6 +13,8 @@ > #include "qemu/osdep.h" > #include "qemu/rcu.h" > #include "qemu/cutils.h" > +#include "qemu/dsa.h" > +#include "qemu/memalign.h" > #include "exec/target_page.h" > #include "sysemu/sysemu.h" > #include "exec/ramblock.h" > @@ -555,6 +557,8 @@ void multifd_save_cleanup(void) > qemu_thread_join(&p->thread); > } > } > + dsa_stop(); > + dsa_cleanup(); > for (i = 0; i < migrate_multifd_channels(); i++) { > MultiFDSendParams *p = &multifd_send_state->params[i]; > Error *local_err = NULL; > @@ -571,6 +575,11 @@ void multifd_save_cleanup(void) > p->name = NULL; > multifd_pages_clear(p->pages); > p->pages = NULL; > + g_free(p->addr); > + p->addr = NULL; > + buffer_zero_batch_task_destroy(p->dsa_batch_task); > + qemu_vfree(p->dsa_batch_task); > + p->dsa_batch_task = NULL; > p->packet_len = 0; > g_free(p->packet); > p->packet = NULL; > @@ -675,13 +684,71 @@ int multifd_send_sync_main(QEMUFile *f) > return 0; > } > > +static void set_page(MultiFDSendParams *p, bool zero_page, uint64_t offset) > +{ > + RAMBlock *rb = p->pages->block; > + if (zero_page) { > + p->zero[p->zero_num] = offset; > + p->zero_num++; > + ram_release_page(rb->idstr, offset); > + } else { > + p->normal[p->normal_num] = offset; > + p->normal_num++; > + } > +} > + > +static void buffer_is_zero_use_cpu(MultiFDSendParams *p) > +{ > + const void **buf = (const void **)p->addr; > + assert(!migrate_use_main_zero_page()); > + assert(!dsa_is_running()); > + > + for (int i = 0; i < p->pages->num; i++) { > + p->dsa_batch_task->results[i] = buffer_is_zero(buf[i], p->page_size); > + } > +} > + > +static void buffer_is_zero_use_dsa(MultiFDSendParams *p) > +{ > + assert(!migrate_use_main_zero_page()); > + assert(dsa_is_running()); > + > + buffer_is_zero_dsa_batch_async(p->dsa_batch_task, > + (const void **)p->addr, > + p->pages->num, > + p->page_size); > +} > + > +static void multifd_zero_page_check(MultiFDSendParams *p) > +{ > + /* older qemu don't understand zero page on multifd channel */ > + bool use_multifd_zero_page = !migrate_use_main_zero_page(); > + bool use_multifd_dsa_accel = dsa_is_running(); > + > + RAMBlock *rb = p->pages->block; > + > + for (int i = 0; i < p->pages->num; i++) { > + p->addr[i] = (ram_addr_t)(rb->host + p->pages->offset[i]); > + } > + > + if (!use_multifd_zero_page || !use_multifd_dsa_accel) { > + buffer_is_zero_use_cpu(p); > + } else { > + buffer_is_zero_use_dsa(p); > + } > + > + for (int i = 0; i < p->pages->num; i++) { > + uint64_t offset = p->pages->offset[i]; > + bool zero_page = p->dsa_batch_task->results[i]; > + set_page(p, zero_page, offset); > + } > +}
You're moving existing (not really, but ok) code and adding dsa support at the same time. The introduction of this function needs to be in a separate patch. That would be a preliminary patch that isolates all of the use_cpu code and a subsequent one that adds the use_dsa part.