diff mbox series

[v8,4/6] migration/ram.c: add ram save state notifiers

Message ID 1528445443-43406-5-git-send-email-wei.w.wang@intel.com
State New
Headers show
Series virtio-balloon: free page hint reporting support | expand

Commit Message

Wang, Wei W June 8, 2018, 8:10 a.m. UTC
This patch adds a ram save state notifier list, and expose RAMState for
the notifer callbacks to use.

Signed-off-by: Wei Wang <wei.w.wang@intel.com>
CC: Dr. David Alan Gilbert <dgilbert@redhat.com>
CC: Juan Quintela <quintela@redhat.com>
CC: Michael S. Tsirkin <mst@redhat.com>
CC: Peter Xu <peterx@redhat.com>
---
 include/migration/misc.h | 52 +++++++++++++++++++++++++++++++++++++++
 migration/ram.c          | 64 +++++++++++++++++-------------------------------
 2 files changed, 75 insertions(+), 41 deletions(-)

Comments

Peter Xu June 12, 2018, 7:50 a.m. UTC | #1
On Fri, Jun 08, 2018 at 04:10:41PM +0800, Wei Wang wrote:
> This patch adds a ram save state notifier list, and expose RAMState for
> the notifer callbacks to use.
> 
> Signed-off-by: Wei Wang <wei.w.wang@intel.com>
> CC: Dr. David Alan Gilbert <dgilbert@redhat.com>
> CC: Juan Quintela <quintela@redhat.com>
> CC: Michael S. Tsirkin <mst@redhat.com>
> CC: Peter Xu <peterx@redhat.com>
> ---
>  include/migration/misc.h | 52 +++++++++++++++++++++++++++++++++++++++
>  migration/ram.c          | 64 +++++++++++++++++-------------------------------
>  2 files changed, 75 insertions(+), 41 deletions(-)
> 
> diff --git a/include/migration/misc.h b/include/migration/misc.h
> index 113320e..b970d7d 100644
> --- a/include/migration/misc.h
> +++ b/include/migration/misc.h
> @@ -16,9 +16,61 @@
>  
>  #include "exec/cpu-common.h"
>  #include "qemu/notify.h"
> +#include "qemu/thread.h"
>  
>  /* migration/ram.c */
>  
> +typedef enum RamSaveState {
> +    RAM_SAVE_ERR = 0,
> +    RAM_SAVE_RESET = 1,
> +    RAM_SAVE_BEFORE_SYNC_BITMAP = 2,
> +    RAM_SAVE_AFTER_SYNC_BITMAP = 3,
> +    RAM_SAVE_MAX = 4,
> +} RamSaveState;
> +
> +/* State of RAM for migration */
> +typedef struct RAMState {
> +    /* QEMUFile used for this migration */
> +    QEMUFile *f;
> +    /* Last block that we have visited searching for dirty pages */
> +    RAMBlock *last_seen_block;
> +    /* Last block from where we have sent data */
> +    RAMBlock *last_sent_block;
> +    /* Last dirty target page we have sent */
> +    ram_addr_t last_page;
> +    /* last ram version we have seen */
> +    uint32_t last_version;
> +    /* We are in the first round */
> +    bool ram_bulk_stage;
> +    /* How many times we have dirty too many pages */
> +    int dirty_rate_high_cnt;
> +    /* ram save states used for notifiers */
> +    int ram_save_state;
> +    /* these variables are used for bitmap sync */
> +    /* last time we did a full bitmap_sync */
> +    int64_t time_last_bitmap_sync;
> +    /* bytes transferred at start_time */
> +    uint64_t bytes_xfer_prev;
> +    /* number of dirty pages since start_time */
> +    uint64_t num_dirty_pages_period;
> +    /* xbzrle misses since the beginning of the period */
> +    uint64_t xbzrle_cache_miss_prev;
> +    /* number of iterations at the beginning of period */
> +    uint64_t iterations_prev;
> +    /* Iterations since start */
> +    uint64_t iterations;
> +    /* number of dirty bits in the bitmap */
> +    uint64_t migration_dirty_pages;
> +    /* protects modification of the bitmap */
> +    QemuMutex bitmap_mutex;
> +    /* The RAMBlock used in the last src_page_requests */
> +    RAMBlock *last_req_rb;
> +    /* Queue of outstanding page requests from the destination */
> +    QemuMutex src_page_req_mutex;
> +    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
> +} RAMState;

Why move these chunk?  Can it be avoided?

> +
> +void add_ram_save_state_change_notifier(Notifier *notify);
>  void ram_mig_init(void);
>  void qemu_guest_free_page_hint(void *addr, size_t len);
>  
> diff --git a/migration/ram.c b/migration/ram.c
> index 237f11e..d45b5a4 100644
> --- a/migration/ram.c
> +++ b/migration/ram.c
> @@ -56,6 +56,9 @@
>  #include "qemu/uuid.h"
>  #include "savevm.h"
>  
> +static NotifierList ram_save_state_notifiers =
> +    NOTIFIER_LIST_INITIALIZER(ram_save_state_notifiers);
> +
>  /***********************************************************/
>  /* ram save/restore */
>  
> @@ -267,49 +270,18 @@ struct RAMSrcPageRequest {
>      QSIMPLEQ_ENTRY(RAMSrcPageRequest) next_req;
>  };
>  
> -/* State of RAM for migration */
> -struct RAMState {
> -    /* QEMUFile used for this migration */
> -    QEMUFile *f;
> -    /* Last block that we have visited searching for dirty pages */
> -    RAMBlock *last_seen_block;
> -    /* Last block from where we have sent data */
> -    RAMBlock *last_sent_block;
> -    /* Last dirty target page we have sent */
> -    ram_addr_t last_page;
> -    /* last ram version we have seen */
> -    uint32_t last_version;
> -    /* We are in the first round */
> -    bool ram_bulk_stage;
> -    /* How many times we have dirty too many pages */
> -    int dirty_rate_high_cnt;
> -    /* these variables are used for bitmap sync */
> -    /* last time we did a full bitmap_sync */
> -    int64_t time_last_bitmap_sync;
> -    /* bytes transferred at start_time */
> -    uint64_t bytes_xfer_prev;
> -    /* number of dirty pages since start_time */
> -    uint64_t num_dirty_pages_period;
> -    /* xbzrle misses since the beginning of the period */
> -    uint64_t xbzrle_cache_miss_prev;
> -    /* number of iterations at the beginning of period */
> -    uint64_t iterations_prev;
> -    /* Iterations since start */
> -    uint64_t iterations;
> -    /* number of dirty bits in the bitmap */
> -    uint64_t migration_dirty_pages;
> -    /* protects modification of the bitmap */
> -    QemuMutex bitmap_mutex;
> -    /* The RAMBlock used in the last src_page_requests */
> -    RAMBlock *last_req_rb;
> -    /* Queue of outstanding page requests from the destination */
> -    QemuMutex src_page_req_mutex;
> -    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
> -};
> -typedef struct RAMState RAMState;
> -
>  static RAMState *ram_state;
>  
> +void add_ram_save_state_change_notifier(Notifier *notify)
> +{
> +    notifier_list_add(&ram_save_state_notifiers, notify);
> +}
> +
> +static void notify_ram_save_state_change_notifier(void)
> +{
> +    notifier_list_notify(&ram_save_state_notifiers, ram_state);
> +}
> +
>  uint64_t ram_bytes_remaining(void)
>  {
>      return ram_state ? (ram_state->migration_dirty_pages * TARGET_PAGE_SIZE) :
> @@ -1139,6 +1111,9 @@ static void migration_bitmap_sync(RAMState *rs)
>      int64_t end_time;
>      uint64_t bytes_xfer_now;
>  
> +    rs->ram_save_state = RAM_SAVE_BEFORE_SYNC_BITMAP;

What's the point to keep this state after all?...

> +    notify_ram_save_state_change_notifier();
> +
>      ram_counters.dirty_sync_count++;
>  
>      if (!rs->time_last_bitmap_sync) {
> @@ -1205,6 +1180,9 @@ static void migration_bitmap_sync(RAMState *rs)
>      if (migrate_use_events()) {
>          qapi_event_send_migration_pass(ram_counters.dirty_sync_count, NULL);
>      }
> +
> +    rs->ram_save_state = RAM_SAVE_AFTER_SYNC_BITMAP;
> +    notify_ram_save_state_change_notifier();
>  }
>  
>  /**
> @@ -1961,6 +1939,8 @@ static void ram_state_reset(RAMState *rs)
>      rs->last_page = 0;
>      rs->last_version = ram_list.version;
>      rs->ram_bulk_stage = true;
> +    rs->ram_save_state = RAM_SAVE_RESET;

... and this state is much more meaningless afaict ...

> +    notify_ram_save_state_change_notifier();
>  }
>  
>  #define MAX_WAIT 50 /* ms, half buffered_file limit */
> @@ -2709,6 +2689,8 @@ out:
>  
>      ret = qemu_file_get_error(f);
>      if (ret < 0) {
> +        rs->ram_save_state = RAM_SAVE_ERR;
> +        notify_ram_save_state_change_notifier();
>          return ret;
>      }

Also, I would prefer to add a general event framework for migration
rather than "ram save" specific.  Then we add SYNC_START/SYNC_END
events.  These notifiers aren't a lot, it'll be a bit awkward to
introduce the framework multiple times for similar purpuse (after we
have a common notifier we can merge the postcopy notifiers AFAIU).

Regards,
Wang, Wei W June 12, 2018, 11:12 a.m. UTC | #2
On 06/12/2018 03:50 PM, Peter Xu wrote:
> On Fri, Jun 08, 2018 at 04:10:41PM +0800, Wei Wang wrote:
>> This patch adds a ram save state notifier list, and expose RAMState for
>> the notifer callbacks to use.
>>
>> Signed-off-by: Wei Wang <wei.w.wang@intel.com>
>> CC: Dr. David Alan Gilbert <dgilbert@redhat.com>
>> CC: Juan Quintela <quintela@redhat.com>
>> CC: Michael S. Tsirkin <mst@redhat.com>
>> CC: Peter Xu <peterx@redhat.com>
>> ---
>>   include/migration/misc.h | 52 +++++++++++++++++++++++++++++++++++++++
>>   migration/ram.c          | 64 +++++++++++++++++-------------------------------
>>   2 files changed, 75 insertions(+), 41 deletions(-)
>>
>> diff --git a/include/migration/misc.h b/include/migration/misc.h
>> index 113320e..b970d7d 100644
>> --- a/include/migration/misc.h
>> +++ b/include/migration/misc.h
>> @@ -16,9 +16,61 @@
>>   
>>   #include "exec/cpu-common.h"
>>   #include "qemu/notify.h"
>> +#include "qemu/thread.h"
>>   
>>   /* migration/ram.c */
>>   
>> +typedef enum RamSaveState {
>> +    RAM_SAVE_ERR = 0,
>> +    RAM_SAVE_RESET = 1,
>> +    RAM_SAVE_BEFORE_SYNC_BITMAP = 2,
>> +    RAM_SAVE_AFTER_SYNC_BITMAP = 3,
>> +    RAM_SAVE_MAX = 4,
>> +} RamSaveState;
>> +
>> +/* State of RAM for migration */
>> +typedef struct RAMState {
>> +    /* QEMUFile used for this migration */
>> +    QEMUFile *f;
>> +    /* Last block that we have visited searching for dirty pages */
>> +    RAMBlock *last_seen_block;
>> +    /* Last block from where we have sent data */
>> +    RAMBlock *last_sent_block;
>> +    /* Last dirty target page we have sent */
>> +    ram_addr_t last_page;
>> +    /* last ram version we have seen */
>> +    uint32_t last_version;
>> +    /* We are in the first round */
>> +    bool ram_bulk_stage;
>> +    /* How many times we have dirty too many pages */
>> +    int dirty_rate_high_cnt;
>> +    /* ram save states used for notifiers */
>> +    int ram_save_state;
>> +    /* these variables are used for bitmap sync */
>> +    /* last time we did a full bitmap_sync */
>> +    int64_t time_last_bitmap_sync;
>> +    /* bytes transferred at start_time */
>> +    uint64_t bytes_xfer_prev;
>> +    /* number of dirty pages since start_time */
>> +    uint64_t num_dirty_pages_period;
>> +    /* xbzrle misses since the beginning of the period */
>> +    uint64_t xbzrle_cache_miss_prev;
>> +    /* number of iterations at the beginning of period */
>> +    uint64_t iterations_prev;
>> +    /* Iterations since start */
>> +    uint64_t iterations;
>> +    /* number of dirty bits in the bitmap */
>> +    uint64_t migration_dirty_pages;
>> +    /* protects modification of the bitmap */
>> +    QemuMutex bitmap_mutex;
>> +    /* The RAMBlock used in the last src_page_requests */
>> +    RAMBlock *last_req_rb;
>> +    /* Queue of outstanding page requests from the destination */
>> +    QemuMutex src_page_req_mutex;
>> +    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
>> +} RAMState;
> Why move these chunk?  Can it be avoided?
>
>> +
>> +void add_ram_save_state_change_notifier(Notifier *notify);
>>   void ram_mig_init(void);
>>   void qemu_guest_free_page_hint(void *addr, size_t len);
>>   
>> diff --git a/migration/ram.c b/migration/ram.c
>> index 237f11e..d45b5a4 100644
>> --- a/migration/ram.c
>> +++ b/migration/ram.c
>> @@ -56,6 +56,9 @@
>>   #include "qemu/uuid.h"
>>   #include "savevm.h"
>>   
>> +static NotifierList ram_save_state_notifiers =
>> +    NOTIFIER_LIST_INITIALIZER(ram_save_state_notifiers);
>> +
>>   /***********************************************************/
>>   /* ram save/restore */
>>   
>> @@ -267,49 +270,18 @@ struct RAMSrcPageRequest {
>>       QSIMPLEQ_ENTRY(RAMSrcPageRequest) next_req;
>>   };
>>   
>> -/* State of RAM for migration */
>> -struct RAMState {
>> -    /* QEMUFile used for this migration */
>> -    QEMUFile *f;
>> -    /* Last block that we have visited searching for dirty pages */
>> -    RAMBlock *last_seen_block;
>> -    /* Last block from where we have sent data */
>> -    RAMBlock *last_sent_block;
>> -    /* Last dirty target page we have sent */
>> -    ram_addr_t last_page;
>> -    /* last ram version we have seen */
>> -    uint32_t last_version;
>> -    /* We are in the first round */
>> -    bool ram_bulk_stage;
>> -    /* How many times we have dirty too many pages */
>> -    int dirty_rate_high_cnt;
>> -    /* these variables are used for bitmap sync */
>> -    /* last time we did a full bitmap_sync */
>> -    int64_t time_last_bitmap_sync;
>> -    /* bytes transferred at start_time */
>> -    uint64_t bytes_xfer_prev;
>> -    /* number of dirty pages since start_time */
>> -    uint64_t num_dirty_pages_period;
>> -    /* xbzrle misses since the beginning of the period */
>> -    uint64_t xbzrle_cache_miss_prev;
>> -    /* number of iterations at the beginning of period */
>> -    uint64_t iterations_prev;
>> -    /* Iterations since start */
>> -    uint64_t iterations;
>> -    /* number of dirty bits in the bitmap */
>> -    uint64_t migration_dirty_pages;
>> -    /* protects modification of the bitmap */
>> -    QemuMutex bitmap_mutex;
>> -    /* The RAMBlock used in the last src_page_requests */
>> -    RAMBlock *last_req_rb;
>> -    /* Queue of outstanding page requests from the destination */
>> -    QemuMutex src_page_req_mutex;
>> -    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
>> -};
>> -typedef struct RAMState RAMState;
>> -
>>   static RAMState *ram_state;
>>   
>> +void add_ram_save_state_change_notifier(Notifier *notify)
>> +{
>> +    notifier_list_add(&ram_save_state_notifiers, notify);
>> +}
>> +
>> +static void notify_ram_save_state_change_notifier(void)
>> +{
>> +    notifier_list_notify(&ram_save_state_notifiers, ram_state);
>> +}
>> +
>>   uint64_t ram_bytes_remaining(void)
>>   {
>>       return ram_state ? (ram_state->migration_dirty_pages * TARGET_PAGE_SIZE) :
>> @@ -1139,6 +1111,9 @@ static void migration_bitmap_sync(RAMState *rs)
>>       int64_t end_time;
>>       uint64_t bytes_xfer_now;
>>   
>> +    rs->ram_save_state = RAM_SAVE_BEFORE_SYNC_BITMAP;
> What's the point to keep this state after all?...
>
>> +    notify_ram_save_state_change_notifier();
>> +
>>       ram_counters.dirty_sync_count++;
>>   
>>       if (!rs->time_last_bitmap_sync) {
>> @@ -1205,6 +1180,9 @@ static void migration_bitmap_sync(RAMState *rs)
>>       if (migrate_use_events()) {
>>           qapi_event_send_migration_pass(ram_counters.dirty_sync_count, NULL);
>>       }
>> +
>> +    rs->ram_save_state = RAM_SAVE_AFTER_SYNC_BITMAP;
>> +    notify_ram_save_state_change_notifier();
>>   }
>>   
>>   /**
>> @@ -1961,6 +1939,8 @@ static void ram_state_reset(RAMState *rs)
>>       rs->last_page = 0;
>>       rs->last_version = ram_list.version;
>>       rs->ram_bulk_stage = true;
>> +    rs->ram_save_state = RAM_SAVE_RESET;
> ... and this state is much more meaningless afaict ...
>
>> +    notify_ram_save_state_change_notifier();
>>   }
>>   
>>   #define MAX_WAIT 50 /* ms, half buffered_file limit */
>> @@ -2709,6 +2689,8 @@ out:
>>   
>>       ret = qemu_file_get_error(f);
>>       if (ret < 0) {
>> +        rs->ram_save_state = RAM_SAVE_ERR;
>> +        notify_ram_save_state_change_notifier();
>>           return ret;
>>       }
> Also, I would prefer to add a general event framework for migration
> rather than "ram save" specific.  Then we add SYNC_START/SYNC_END
> events.  These notifiers aren't a lot, it'll be a bit awkward to
> introduce the framework multiple times for similar purpuse (after we
> have a common notifier we can merge the postcopy notifiers AFAIU).

Hi Peter,

Thanks for the review. We just got a little accident in the kernel part, 
which may cause some modifications to the QEMU side interfaces. So I 
will implement a new version and let you review in v9 patches.

Best,
Wei
Peter Xu June 13, 2018, 2:01 a.m. UTC | #3
On Tue, Jun 12, 2018 at 07:12:47PM +0800, Wei Wang wrote:

[...]

> Hi Peter,
> 
> Thanks for the review. We just got a little accident in the kernel part,
> which may cause some modifications to the QEMU side interfaces. So I will
> implement a new version and let you review in v9 patches.

No problem.  Yeah I actually noticed the accident.  Please feel free
to postpone the QEMU part until the kernel part is fully settled.

Regards,
Dr. David Alan Gilbert June 19, 2018, 5:31 p.m. UTC | #4
* Wei Wang (wei.w.wang@intel.com) wrote:
> On 06/12/2018 03:50 PM, Peter Xu wrote:
> > On Fri, Jun 08, 2018 at 04:10:41PM +0800, Wei Wang wrote:
> > > This patch adds a ram save state notifier list, and expose RAMState for
> > > the notifer callbacks to use.
> > > 
> > > Signed-off-by: Wei Wang <wei.w.wang@intel.com>
> > > CC: Dr. David Alan Gilbert <dgilbert@redhat.com>
> > > CC: Juan Quintela <quintela@redhat.com>
> > > CC: Michael S. Tsirkin <mst@redhat.com>
> > > CC: Peter Xu <peterx@redhat.com>
> > > ---
> > >   include/migration/misc.h | 52 +++++++++++++++++++++++++++++++++++++++
> > >   migration/ram.c          | 64 +++++++++++++++++-------------------------------
> > >   2 files changed, 75 insertions(+), 41 deletions(-)
> > > 
> > > diff --git a/include/migration/misc.h b/include/migration/misc.h
> > > index 113320e..b970d7d 100644
> > > --- a/include/migration/misc.h
> > > +++ b/include/migration/misc.h
> > > @@ -16,9 +16,61 @@
> > >   #include "exec/cpu-common.h"
> > >   #include "qemu/notify.h"
> > > +#include "qemu/thread.h"
> > >   /* migration/ram.c */
> > > +typedef enum RamSaveState {
> > > +    RAM_SAVE_ERR = 0,
> > > +    RAM_SAVE_RESET = 1,
> > > +    RAM_SAVE_BEFORE_SYNC_BITMAP = 2,
> > > +    RAM_SAVE_AFTER_SYNC_BITMAP = 3,
> > > +    RAM_SAVE_MAX = 4,
> > > +} RamSaveState;
> > > +
> > > +/* State of RAM for migration */
> > > +typedef struct RAMState {
> > > +    /* QEMUFile used for this migration */
> > > +    QEMUFile *f;
> > > +    /* Last block that we have visited searching for dirty pages */
> > > +    RAMBlock *last_seen_block;
> > > +    /* Last block from where we have sent data */
> > > +    RAMBlock *last_sent_block;
> > > +    /* Last dirty target page we have sent */
> > > +    ram_addr_t last_page;
> > > +    /* last ram version we have seen */
> > > +    uint32_t last_version;
> > > +    /* We are in the first round */
> > > +    bool ram_bulk_stage;
> > > +    /* How many times we have dirty too many pages */
> > > +    int dirty_rate_high_cnt;
> > > +    /* ram save states used for notifiers */
> > > +    int ram_save_state;
> > > +    /* these variables are used for bitmap sync */
> > > +    /* last time we did a full bitmap_sync */
> > > +    int64_t time_last_bitmap_sync;
> > > +    /* bytes transferred at start_time */
> > > +    uint64_t bytes_xfer_prev;
> > > +    /* number of dirty pages since start_time */
> > > +    uint64_t num_dirty_pages_period;
> > > +    /* xbzrle misses since the beginning of the period */
> > > +    uint64_t xbzrle_cache_miss_prev;
> > > +    /* number of iterations at the beginning of period */
> > > +    uint64_t iterations_prev;
> > > +    /* Iterations since start */
> > > +    uint64_t iterations;
> > > +    /* number of dirty bits in the bitmap */
> > > +    uint64_t migration_dirty_pages;
> > > +    /* protects modification of the bitmap */
> > > +    QemuMutex bitmap_mutex;
> > > +    /* The RAMBlock used in the last src_page_requests */
> > > +    RAMBlock *last_req_rb;
> > > +    /* Queue of outstanding page requests from the destination */
> > > +    QemuMutex src_page_req_mutex;
> > > +    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
> > > +} RAMState;
> > Why move these chunk?  Can it be avoided?
> > 
> > > +
> > > +void add_ram_save_state_change_notifier(Notifier *notify);
> > >   void ram_mig_init(void);
> > >   void qemu_guest_free_page_hint(void *addr, size_t len);
> > > diff --git a/migration/ram.c b/migration/ram.c
> > > index 237f11e..d45b5a4 100644
> > > --- a/migration/ram.c
> > > +++ b/migration/ram.c
> > > @@ -56,6 +56,9 @@
> > >   #include "qemu/uuid.h"
> > >   #include "savevm.h"
> > > +static NotifierList ram_save_state_notifiers =
> > > +    NOTIFIER_LIST_INITIALIZER(ram_save_state_notifiers);
> > > +
> > >   /***********************************************************/
> > >   /* ram save/restore */
> > > @@ -267,49 +270,18 @@ struct RAMSrcPageRequest {
> > >       QSIMPLEQ_ENTRY(RAMSrcPageRequest) next_req;
> > >   };
> > > -/* State of RAM for migration */
> > > -struct RAMState {
> > > -    /* QEMUFile used for this migration */
> > > -    QEMUFile *f;
> > > -    /* Last block that we have visited searching for dirty pages */
> > > -    RAMBlock *last_seen_block;
> > > -    /* Last block from where we have sent data */
> > > -    RAMBlock *last_sent_block;
> > > -    /* Last dirty target page we have sent */
> > > -    ram_addr_t last_page;
> > > -    /* last ram version we have seen */
> > > -    uint32_t last_version;
> > > -    /* We are in the first round */
> > > -    bool ram_bulk_stage;
> > > -    /* How many times we have dirty too many pages */
> > > -    int dirty_rate_high_cnt;
> > > -    /* these variables are used for bitmap sync */
> > > -    /* last time we did a full bitmap_sync */
> > > -    int64_t time_last_bitmap_sync;
> > > -    /* bytes transferred at start_time */
> > > -    uint64_t bytes_xfer_prev;
> > > -    /* number of dirty pages since start_time */
> > > -    uint64_t num_dirty_pages_period;
> > > -    /* xbzrle misses since the beginning of the period */
> > > -    uint64_t xbzrle_cache_miss_prev;
> > > -    /* number of iterations at the beginning of period */
> > > -    uint64_t iterations_prev;
> > > -    /* Iterations since start */
> > > -    uint64_t iterations;
> > > -    /* number of dirty bits in the bitmap */
> > > -    uint64_t migration_dirty_pages;
> > > -    /* protects modification of the bitmap */
> > > -    QemuMutex bitmap_mutex;
> > > -    /* The RAMBlock used in the last src_page_requests */
> > > -    RAMBlock *last_req_rb;
> > > -    /* Queue of outstanding page requests from the destination */
> > > -    QemuMutex src_page_req_mutex;
> > > -    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
> > > -};
> > > -typedef struct RAMState RAMState;
> > > -
> > >   static RAMState *ram_state;
> > > +void add_ram_save_state_change_notifier(Notifier *notify)
> > > +{
> > > +    notifier_list_add(&ram_save_state_notifiers, notify);
> > > +}
> > > +
> > > +static void notify_ram_save_state_change_notifier(void)
> > > +{
> > > +    notifier_list_notify(&ram_save_state_notifiers, ram_state);
> > > +}
> > > +
> > >   uint64_t ram_bytes_remaining(void)
> > >   {
> > >       return ram_state ? (ram_state->migration_dirty_pages * TARGET_PAGE_SIZE) :
> > > @@ -1139,6 +1111,9 @@ static void migration_bitmap_sync(RAMState *rs)
> > >       int64_t end_time;
> > >       uint64_t bytes_xfer_now;
> > > +    rs->ram_save_state = RAM_SAVE_BEFORE_SYNC_BITMAP;
> > What's the point to keep this state after all?...
> > 
> > > +    notify_ram_save_state_change_notifier();
> > > +
> > >       ram_counters.dirty_sync_count++;
> > >       if (!rs->time_last_bitmap_sync) {
> > > @@ -1205,6 +1180,9 @@ static void migration_bitmap_sync(RAMState *rs)
> > >       if (migrate_use_events()) {
> > >           qapi_event_send_migration_pass(ram_counters.dirty_sync_count, NULL);
> > >       }
> > > +
> > > +    rs->ram_save_state = RAM_SAVE_AFTER_SYNC_BITMAP;
> > > +    notify_ram_save_state_change_notifier();
> > >   }
> > >   /**
> > > @@ -1961,6 +1939,8 @@ static void ram_state_reset(RAMState *rs)
> > >       rs->last_page = 0;
> > >       rs->last_version = ram_list.version;
> > >       rs->ram_bulk_stage = true;
> > > +    rs->ram_save_state = RAM_SAVE_RESET;
> > ... and this state is much more meaningless afaict ...
> > 
> > > +    notify_ram_save_state_change_notifier();
> > >   }
> > >   #define MAX_WAIT 50 /* ms, half buffered_file limit */
> > > @@ -2709,6 +2689,8 @@ out:
> > >       ret = qemu_file_get_error(f);
> > >       if (ret < 0) {
> > > +        rs->ram_save_state = RAM_SAVE_ERR;
> > > +        notify_ram_save_state_change_notifier();
> > >           return ret;
> > >       }
> > Also, I would prefer to add a general event framework for migration
> > rather than "ram save" specific.  Then we add SYNC_START/SYNC_END
> > events.  These notifiers aren't a lot, it'll be a bit awkward to
> > introduce the framework multiple times for similar purpuse (after we
> > have a common notifier we can merge the postcopy notifiers AFAIU).
> 
> Hi Peter,
> 
> Thanks for the review. We just got a little accident in the kernel part,
> which may cause some modifications to the QEMU side interfaces. So I will
> implement a new version and let you review in v9 patches.

Yes, but please do try and keep RAMState private to ram.c.

Dave

> Best,
> Wei
> 
--
Dr. David Alan Gilbert / dgilbert@redhat.com / Manchester, UK
Wang, Wei W June 20, 2018, 11:15 a.m. UTC | #5
On 06/20/2018 01:31 AM, Dr. David Alan Gilbert wrote:
> * Wei Wang (wei.w.wang@intel.com) wrote:
>> On 06/12/2018 03:50 PM, Peter Xu wrote:
>>> On Fri, Jun 08, 2018 at 04:10:41PM +0800, Wei Wang wrote:
>>>> This patch adds a ram save state notifier list, and expose RAMState for
>>>> the notifer callbacks to use.
>>>>
>>>> Signed-off-by: Wei Wang <wei.w.wang@intel.com>
>>>> CC: Dr. David Alan Gilbert <dgilbert@redhat.com>
>>>> CC: Juan Quintela <quintela@redhat.com>
>>>> CC: Michael S. Tsirkin <mst@redhat.com>
>>>> CC: Peter Xu <peterx@redhat.com>
>>>> ---
>>>>    include/migration/misc.h | 52 +++++++++++++++++++++++++++++++++++++++
>>>>    migration/ram.c          | 64 +++++++++++++++++-------------------------------
>>>>    2 files changed, 75 insertions(+), 41 deletions(-)
>>>>
>>>> diff --git a/include/migration/misc.h b/include/migration/misc.h
>>>> index 113320e..b970d7d 100644
>>>> --- a/include/migration/misc.h
>>>> +++ b/include/migration/misc.h
>>>> @@ -16,9 +16,61 @@
>>>>    #include "exec/cpu-common.h"
>>>>    #include "qemu/notify.h"
>>>> +#include "qemu/thread.h"
>>>>    /* migration/ram.c */
>>>> +typedef enum RamSaveState {
>>>> +    RAM_SAVE_ERR = 0,
>>>> +    RAM_SAVE_RESET = 1,
>>>> +    RAM_SAVE_BEFORE_SYNC_BITMAP = 2,
>>>> +    RAM_SAVE_AFTER_SYNC_BITMAP = 3,
>>>> +    RAM_SAVE_MAX = 4,
>>>> +} RamSaveState;
>>>> +
>>>> +/* State of RAM for migration */
>>>> +typedef struct RAMState {
>>>> +    /* QEMUFile used for this migration */
>>>> +    QEMUFile *f;
>>>> +    /* Last block that we have visited searching for dirty pages */
>>>> +    RAMBlock *last_seen_block;
>>>> +    /* Last block from where we have sent data */
>>>> +    RAMBlock *last_sent_block;
>>>> +    /* Last dirty target page we have sent */
>>>> +    ram_addr_t last_page;
>>>> +    /* last ram version we have seen */
>>>> +    uint32_t last_version;
>>>> +    /* We are in the first round */
>>>> +    bool ram_bulk_stage;
>>>> +    /* How many times we have dirty too many pages */
>>>> +    int dirty_rate_high_cnt;
>>>> +    /* ram save states used for notifiers */
>>>> +    int ram_save_state;
>>>> +    /* these variables are used for bitmap sync */
>>>> +    /* last time we did a full bitmap_sync */
>>>> +    int64_t time_last_bitmap_sync;
>>>> +    /* bytes transferred at start_time */
>>>> +    uint64_t bytes_xfer_prev;
>>>> +    /* number of dirty pages since start_time */
>>>> +    uint64_t num_dirty_pages_period;
>>>> +    /* xbzrle misses since the beginning of the period */
>>>> +    uint64_t xbzrle_cache_miss_prev;
>>>> +    /* number of iterations at the beginning of period */
>>>> +    uint64_t iterations_prev;
>>>> +    /* Iterations since start */
>>>> +    uint64_t iterations;
>>>> +    /* number of dirty bits in the bitmap */
>>>> +    uint64_t migration_dirty_pages;
>>>> +    /* protects modification of the bitmap */
>>>> +    QemuMutex bitmap_mutex;
>>>> +    /* The RAMBlock used in the last src_page_requests */
>>>> +    RAMBlock *last_req_rb;
>>>> +    /* Queue of outstanding page requests from the destination */
>>>> +    QemuMutex src_page_req_mutex;
>>>> +    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
>>>> +} RAMState;
>>> Why move these chunk?  Can it be avoided?
>>>
>>>> +
>>>> +void add_ram_save_state_change_notifier(Notifier *notify);
>>>>    void ram_mig_init(void);
>>>>    void qemu_guest_free_page_hint(void *addr, size_t len);
>>>> diff --git a/migration/ram.c b/migration/ram.c
>>>> index 237f11e..d45b5a4 100644
>>>> --- a/migration/ram.c
>>>> +++ b/migration/ram.c
>>>> @@ -56,6 +56,9 @@
>>>>    #include "qemu/uuid.h"
>>>>    #include "savevm.h"
>>>> +static NotifierList ram_save_state_notifiers =
>>>> +    NOTIFIER_LIST_INITIALIZER(ram_save_state_notifiers);
>>>> +
>>>>    /***********************************************************/
>>>>    /* ram save/restore */
>>>> @@ -267,49 +270,18 @@ struct RAMSrcPageRequest {
>>>>        QSIMPLEQ_ENTRY(RAMSrcPageRequest) next_req;
>>>>    };
>>>> -/* State of RAM for migration */
>>>> -struct RAMState {
>>>> -    /* QEMUFile used for this migration */
>>>> -    QEMUFile *f;
>>>> -    /* Last block that we have visited searching for dirty pages */
>>>> -    RAMBlock *last_seen_block;
>>>> -    /* Last block from where we have sent data */
>>>> -    RAMBlock *last_sent_block;
>>>> -    /* Last dirty target page we have sent */
>>>> -    ram_addr_t last_page;
>>>> -    /* last ram version we have seen */
>>>> -    uint32_t last_version;
>>>> -    /* We are in the first round */
>>>> -    bool ram_bulk_stage;
>>>> -    /* How many times we have dirty too many pages */
>>>> -    int dirty_rate_high_cnt;
>>>> -    /* these variables are used for bitmap sync */
>>>> -    /* last time we did a full bitmap_sync */
>>>> -    int64_t time_last_bitmap_sync;
>>>> -    /* bytes transferred at start_time */
>>>> -    uint64_t bytes_xfer_prev;
>>>> -    /* number of dirty pages since start_time */
>>>> -    uint64_t num_dirty_pages_period;
>>>> -    /* xbzrle misses since the beginning of the period */
>>>> -    uint64_t xbzrle_cache_miss_prev;
>>>> -    /* number of iterations at the beginning of period */
>>>> -    uint64_t iterations_prev;
>>>> -    /* Iterations since start */
>>>> -    uint64_t iterations;
>>>> -    /* number of dirty bits in the bitmap */
>>>> -    uint64_t migration_dirty_pages;
>>>> -    /* protects modification of the bitmap */
>>>> -    QemuMutex bitmap_mutex;
>>>> -    /* The RAMBlock used in the last src_page_requests */
>>>> -    RAMBlock *last_req_rb;
>>>> -    /* Queue of outstanding page requests from the destination */
>>>> -    QemuMutex src_page_req_mutex;
>>>> -    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
>>>> -};
>>>> -typedef struct RAMState RAMState;
>>>> -
>>>>    static RAMState *ram_state;
>>>> +void add_ram_save_state_change_notifier(Notifier *notify)
>>>> +{
>>>> +    notifier_list_add(&ram_save_state_notifiers, notify);
>>>> +}
>>>> +
>>>> +static void notify_ram_save_state_change_notifier(void)
>>>> +{
>>>> +    notifier_list_notify(&ram_save_state_notifiers, ram_state);
>>>> +}
>>>> +
>>>>    uint64_t ram_bytes_remaining(void)
>>>>    {
>>>>        return ram_state ? (ram_state->migration_dirty_pages * TARGET_PAGE_SIZE) :
>>>> @@ -1139,6 +1111,9 @@ static void migration_bitmap_sync(RAMState *rs)
>>>>        int64_t end_time;
>>>>        uint64_t bytes_xfer_now;
>>>> +    rs->ram_save_state = RAM_SAVE_BEFORE_SYNC_BITMAP;
>>> What's the point to keep this state after all?...
>>>
>>>> +    notify_ram_save_state_change_notifier();
>>>> +
>>>>        ram_counters.dirty_sync_count++;
>>>>        if (!rs->time_last_bitmap_sync) {
>>>> @@ -1205,6 +1180,9 @@ static void migration_bitmap_sync(RAMState *rs)
>>>>        if (migrate_use_events()) {
>>>>            qapi_event_send_migration_pass(ram_counters.dirty_sync_count, NULL);
>>>>        }
>>>> +
>>>> +    rs->ram_save_state = RAM_SAVE_AFTER_SYNC_BITMAP;
>>>> +    notify_ram_save_state_change_notifier();
>>>>    }
>>>>    /**
>>>> @@ -1961,6 +1939,8 @@ static void ram_state_reset(RAMState *rs)
>>>>        rs->last_page = 0;
>>>>        rs->last_version = ram_list.version;
>>>>        rs->ram_bulk_stage = true;
>>>> +    rs->ram_save_state = RAM_SAVE_RESET;
>>> ... and this state is much more meaningless afaict ...
>>>
>>>> +    notify_ram_save_state_change_notifier();
>>>>    }
>>>>    #define MAX_WAIT 50 /* ms, half buffered_file limit */
>>>> @@ -2709,6 +2689,8 @@ out:
>>>>        ret = qemu_file_get_error(f);
>>>>        if (ret < 0) {
>>>> +        rs->ram_save_state = RAM_SAVE_ERR;
>>>> +        notify_ram_save_state_change_notifier();
>>>>            return ret;
>>>>        }
>>> Also, I would prefer to add a general event framework for migration
>>> rather than "ram save" specific.  Then we add SYNC_START/SYNC_END
>>> events.  These notifiers aren't a lot, it'll be a bit awkward to
>>> introduce the framework multiple times for similar purpuse (after we
>>> have a common notifier we can merge the postcopy notifiers AFAIU).
>> Hi Peter,
>>
>> Thanks for the review. We just got a little accident in the kernel part,
>> which may cause some modifications to the QEMU side interfaces. So I will
>> implement a new version and let you review in v9 patches.
> Yes, but please do try and keep RAMState private to ram.c.
>

OK, will use functions to expose the related fields (e.g. ram_bulk_stage).

Best,
Wei
diff mbox series

Patch

diff --git a/include/migration/misc.h b/include/migration/misc.h
index 113320e..b970d7d 100644
--- a/include/migration/misc.h
+++ b/include/migration/misc.h
@@ -16,9 +16,61 @@ 
 
 #include "exec/cpu-common.h"
 #include "qemu/notify.h"
+#include "qemu/thread.h"
 
 /* migration/ram.c */
 
+typedef enum RamSaveState {
+    RAM_SAVE_ERR = 0,
+    RAM_SAVE_RESET = 1,
+    RAM_SAVE_BEFORE_SYNC_BITMAP = 2,
+    RAM_SAVE_AFTER_SYNC_BITMAP = 3,
+    RAM_SAVE_MAX = 4,
+} RamSaveState;
+
+/* State of RAM for migration */
+typedef struct RAMState {
+    /* QEMUFile used for this migration */
+    QEMUFile *f;
+    /* Last block that we have visited searching for dirty pages */
+    RAMBlock *last_seen_block;
+    /* Last block from where we have sent data */
+    RAMBlock *last_sent_block;
+    /* Last dirty target page we have sent */
+    ram_addr_t last_page;
+    /* last ram version we have seen */
+    uint32_t last_version;
+    /* We are in the first round */
+    bool ram_bulk_stage;
+    /* How many times we have dirty too many pages */
+    int dirty_rate_high_cnt;
+    /* ram save states used for notifiers */
+    int ram_save_state;
+    /* these variables are used for bitmap sync */
+    /* last time we did a full bitmap_sync */
+    int64_t time_last_bitmap_sync;
+    /* bytes transferred at start_time */
+    uint64_t bytes_xfer_prev;
+    /* number of dirty pages since start_time */
+    uint64_t num_dirty_pages_period;
+    /* xbzrle misses since the beginning of the period */
+    uint64_t xbzrle_cache_miss_prev;
+    /* number of iterations at the beginning of period */
+    uint64_t iterations_prev;
+    /* Iterations since start */
+    uint64_t iterations;
+    /* number of dirty bits in the bitmap */
+    uint64_t migration_dirty_pages;
+    /* protects modification of the bitmap */
+    QemuMutex bitmap_mutex;
+    /* The RAMBlock used in the last src_page_requests */
+    RAMBlock *last_req_rb;
+    /* Queue of outstanding page requests from the destination */
+    QemuMutex src_page_req_mutex;
+    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
+} RAMState;
+
+void add_ram_save_state_change_notifier(Notifier *notify);
 void ram_mig_init(void);
 void qemu_guest_free_page_hint(void *addr, size_t len);
 
diff --git a/migration/ram.c b/migration/ram.c
index 237f11e..d45b5a4 100644
--- a/migration/ram.c
+++ b/migration/ram.c
@@ -56,6 +56,9 @@ 
 #include "qemu/uuid.h"
 #include "savevm.h"
 
+static NotifierList ram_save_state_notifiers =
+    NOTIFIER_LIST_INITIALIZER(ram_save_state_notifiers);
+
 /***********************************************************/
 /* ram save/restore */
 
@@ -267,49 +270,18 @@  struct RAMSrcPageRequest {
     QSIMPLEQ_ENTRY(RAMSrcPageRequest) next_req;
 };
 
-/* State of RAM for migration */
-struct RAMState {
-    /* QEMUFile used for this migration */
-    QEMUFile *f;
-    /* Last block that we have visited searching for dirty pages */
-    RAMBlock *last_seen_block;
-    /* Last block from where we have sent data */
-    RAMBlock *last_sent_block;
-    /* Last dirty target page we have sent */
-    ram_addr_t last_page;
-    /* last ram version we have seen */
-    uint32_t last_version;
-    /* We are in the first round */
-    bool ram_bulk_stage;
-    /* How many times we have dirty too many pages */
-    int dirty_rate_high_cnt;
-    /* these variables are used for bitmap sync */
-    /* last time we did a full bitmap_sync */
-    int64_t time_last_bitmap_sync;
-    /* bytes transferred at start_time */
-    uint64_t bytes_xfer_prev;
-    /* number of dirty pages since start_time */
-    uint64_t num_dirty_pages_period;
-    /* xbzrle misses since the beginning of the period */
-    uint64_t xbzrle_cache_miss_prev;
-    /* number of iterations at the beginning of period */
-    uint64_t iterations_prev;
-    /* Iterations since start */
-    uint64_t iterations;
-    /* number of dirty bits in the bitmap */
-    uint64_t migration_dirty_pages;
-    /* protects modification of the bitmap */
-    QemuMutex bitmap_mutex;
-    /* The RAMBlock used in the last src_page_requests */
-    RAMBlock *last_req_rb;
-    /* Queue of outstanding page requests from the destination */
-    QemuMutex src_page_req_mutex;
-    QSIMPLEQ_HEAD(src_page_requests, RAMSrcPageRequest) src_page_requests;
-};
-typedef struct RAMState RAMState;
-
 static RAMState *ram_state;
 
+void add_ram_save_state_change_notifier(Notifier *notify)
+{
+    notifier_list_add(&ram_save_state_notifiers, notify);
+}
+
+static void notify_ram_save_state_change_notifier(void)
+{
+    notifier_list_notify(&ram_save_state_notifiers, ram_state);
+}
+
 uint64_t ram_bytes_remaining(void)
 {
     return ram_state ? (ram_state->migration_dirty_pages * TARGET_PAGE_SIZE) :
@@ -1139,6 +1111,9 @@  static void migration_bitmap_sync(RAMState *rs)
     int64_t end_time;
     uint64_t bytes_xfer_now;
 
+    rs->ram_save_state = RAM_SAVE_BEFORE_SYNC_BITMAP;
+    notify_ram_save_state_change_notifier();
+
     ram_counters.dirty_sync_count++;
 
     if (!rs->time_last_bitmap_sync) {
@@ -1205,6 +1180,9 @@  static void migration_bitmap_sync(RAMState *rs)
     if (migrate_use_events()) {
         qapi_event_send_migration_pass(ram_counters.dirty_sync_count, NULL);
     }
+
+    rs->ram_save_state = RAM_SAVE_AFTER_SYNC_BITMAP;
+    notify_ram_save_state_change_notifier();
 }
 
 /**
@@ -1961,6 +1939,8 @@  static void ram_state_reset(RAMState *rs)
     rs->last_page = 0;
     rs->last_version = ram_list.version;
     rs->ram_bulk_stage = true;
+    rs->ram_save_state = RAM_SAVE_RESET;
+    notify_ram_save_state_change_notifier();
 }
 
 #define MAX_WAIT 50 /* ms, half buffered_file limit */
@@ -2709,6 +2689,8 @@  out:
 
     ret = qemu_file_get_error(f);
     if (ret < 0) {
+        rs->ram_save_state = RAM_SAVE_ERR;
+        notify_ram_save_state_change_notifier();
         return ret;
     }