All of lore.kernel.org
 help / color / mirror / Atom feed
From: Joao Martins <joao.m.martins@oracle.com>
To: qemu-devel@nongnu.org
Cc: "Joao Martins" <joao.m.martins@oracle.com>,
	"Paolo Bonzini" <pbonzini@redhat.com>,
	"Dr. David Alan Gilbert" <dgilbert@redhat.com>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Eduardo Habkost" <eduardo@habkost.net>,
	"Michael S. Tsirkin" <mst@redhat.com>,
	"Marcel Apfelbaum" <marcel.apfelbaum@gmail.com>,
	"Peter Xu" <peterx@redhat.com>,
	"Jason Wang" <jasowang@redhat.com>,
	"Alex Williamson" <alex.williamson@redhat.com>,
	"David Hildenbrand" <david@redhat.com>,
	"Philippe Mathieu-Daudé" <f4bug@amsat.org>,
	"Cornelia Huck" <cohuck@redhat.com>,
	"Juan Quintela" <quintela@redhat.com>,
	"Eric Blake" <eblake@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>,
	"Jason Gunthorpe" <jgg@nvidia.com>,
	"Nicolin Chen" <nicolinc@nvidia.com>,
	"Yishai Hadas" <yishaih@nvidia.com>,
	"Kevin Tian" <kevin.tian@intel.com>,
	"Yi Liu" <yi.l.liu@intel.com>,
	"Eric Auger" <eric.auger@redhat.com>,
	"Thanos Makatos" <thanos.makatos@nutanix.com>,
	"John G . Johnson" <john.g.johnson@oracle.com>,
	kvm@vger.kernel.org
Subject: [PATCH RFC 09/10] migration/dirtyrate: Expand dirty_bitmap to be tracked separately for devices
Date: Thu, 28 Apr 2022 22:13:50 +0100	[thread overview]
Message-ID: <20220428211351.3897-10-joao.m.martins@oracle.com> (raw)
In-Reply-To: <20220428211351.3897-1-joao.m.martins@oracle.com>

Expand dirtyrate measurer that is accessible via HMP calc_dirty_rate
or QMP 'calc-dirty-rate' to receive a @scope argument. The scope
then restricts the dirty tracking to be done at devices only,
while neither enabling or using the KVM (CPU) dirty tracker.
The default stays as is i.e. dirty-ring / dirty-bitmap from KVM.

This is useful to test, exercise the IOMMU dirty tracker and observe
how much a given device is dirtying memory.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 accel/kvm/kvm-all.c   | 12 +++++++++
 hmp-commands.hx       |  5 ++--
 hw/vfio/container.c   |  8 ++++++
 hw/vfio/iommufd.c     |  4 +++
 include/exec/memory.h | 10 +++++++-
 migration/dirtyrate.c | 59 +++++++++++++++++++++++++++++++++----------
 migration/dirtyrate.h |  1 +
 qapi/migration.json   | 15 +++++++++++
 softmmu/memory.c      |  5 ++++
 9 files changed, 102 insertions(+), 17 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 5f1377ca048c..b4bbe0d20f6e 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -1517,6 +1517,10 @@ static void kvm_log_sync(MemoryListener *listener,
 {
     KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener);
 
+    if (memory_global_dirty_devices()) {
+        return;
+    }
+
     kvm_slots_lock();
     kvm_physical_sync_dirty_bitmap(kml, section);
     kvm_slots_unlock();
@@ -1529,6 +1533,10 @@ static void kvm_log_sync_global(MemoryListener *l)
     KVMSlot *mem;
     int i;
 
+    if (memory_global_dirty_devices()) {
+        return;
+    }
+
     /* Flush all kernel dirty addresses into KVMSlot dirty bitmap */
     kvm_dirty_ring_flush();
 
@@ -1558,6 +1566,10 @@ static void kvm_log_clear(MemoryListener *listener,
     KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener);
     int r;
 
+    if (memory_global_dirty_devices()) {
+        return;
+    }
+
     r = kvm_physical_log_clear(kml, section);
     if (r < 0) {
         error_report_once("%s: kvm log clear failed: mr=%s "
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9c9..28122d268ea3 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1739,10 +1739,11 @@ ERST
 
     {
         .name       = "calc_dirty_rate",
-        .args_type  = "dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?",
-        .params     = "[-r] [-b] second [sample_pages_per_GB]",
+        .args_type  = "dirty_devices:-d,dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?",
+        .params     = "[-d] [-r] [-b] second [sample_pages_per_GB]",
         .help       = "start a round of guest dirty rate measurement (using -r to"
                       "\n\t\t\t specify dirty ring as the method of calculation and"
+                      "\n\t\t\t specify devices as the only scope and"
                       "\n\t\t\t -b to specify dirty bitmap as method of calculation)",
         .cmd        = hmp_calc_dirty_rate,
     },
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 6bc1b8763f75..fff8319c0036 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -84,6 +84,10 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *bcontainer)
     VFIODevice *vbasedev;
     MigrationState *ms = migrate_get_current();
 
+    if (bcontainer->dirty_pages_supported) {
+        return true;
+    }
+
     if (!migration_is_setup_or_active(ms->state)) {
         return false;
     }
@@ -311,6 +315,10 @@ static int vfio_get_dirty_bitmap(VFIOContainer *bcontainer, uint64_t iova,
     uint64_t pages;
     int ret;
 
+    if (!memory_global_dirty_devices()) {
+        return 0;
+    }
+
     dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range));
 
     dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range);
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index d75ecbf2ae52..4686cc713aac 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -150,6 +150,10 @@ static int iommufd_get_dirty_bitmap(VFIOContainer *bcontainer, uint64_t iova,
     VFIOIOASHwpt *hwpt;
     unsigned long *data, page_size, bitmap_size, pages;
 
+    if (!memory_global_dirty_devices()) {
+        return 0;
+    }
+
     if (!bcontainer->dirty_pages_supported) {
         return 0;
     }
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 4d5997e6bbae..59c1d8bcc495 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -69,7 +69,10 @@ static inline void fuzz_dma_read_cb(size_t addr,
 /* Dirty tracking enabled because measuring dirty rate */
 #define GLOBAL_DIRTY_DIRTY_RATE (1U << 1)
 
-#define GLOBAL_DIRTY_MASK  (0x3)
+/* Dirty tracking enabled because measuring devices dirty rate */
+#define GLOBAL_DIRTY_DIRTY_RATE_DEVICES (1U << 2)
+
+#define GLOBAL_DIRTY_MASK  (0x7)
 
 extern unsigned int global_dirty_tracking;
 
@@ -2433,6 +2436,11 @@ void memory_global_dirty_log_start(unsigned int flags);
  */
 void memory_global_dirty_log_stop(unsigned int flags);
 
+/**
+ * memory_global_dirty_devices: check if the scope is just devices
+ */
+bool memory_global_dirty_devices(void);
+
 void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled);
 
 /**
diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index aace12a78764..8c00cb6a3702 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -45,6 +45,8 @@ static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED;
 static struct DirtyRateStat DirtyStat;
 static DirtyRateMeasureMode dirtyrate_mode =
                 DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING;
+static DirtyRateScope dirtyrate_scope =
+                DIRTY_RATE_SCOPE_ALL;
 
 static int64_t set_sample_page_period(int64_t msec, int64_t initial_time)
 {
@@ -99,6 +101,7 @@ static struct DirtyRateInfo *query_dirty_rate_info(void)
     info->calc_time = DirtyStat.calc_time;
     info->sample_pages = DirtyStat.sample_pages;
     info->mode = dirtyrate_mode;
+    info->scope = dirtyrate_scope;
 
     if (qatomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURED) {
         info->has_dirty_rate = true;
@@ -406,32 +409,44 @@ static inline void record_dirtypages(DirtyPageRecord *dirty_pages,
     }
 }
 
-static void dirtyrate_global_dirty_log_start(void)
+static void dirtyrate_global_dirty_log_start(DirtyRateScope scope)
 {
+    unsigned int flags = GLOBAL_DIRTY_DIRTY_RATE;
+
+    if (scope == DIRTY_RATE_SCOPE_DIRTY_DEVICES) {
+        flags |= GLOBAL_DIRTY_DIRTY_RATE_DEVICES;
+    }
+
     qemu_mutex_lock_iothread();
-    memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE);
+    memory_global_dirty_log_start(flags);
     qemu_mutex_unlock_iothread();
 }
 
-static void dirtyrate_global_dirty_log_stop(void)
+static void dirtyrate_global_dirty_log_stop(DirtyRateScope scope)
 {
+    unsigned int flags = GLOBAL_DIRTY_DIRTY_RATE;
+
+    if (scope == DIRTY_RATE_SCOPE_DIRTY_DEVICES) {
+        flags |= GLOBAL_DIRTY_DIRTY_RATE_DEVICES;
+    }
+
     qemu_mutex_lock_iothread();
     memory_global_dirty_log_sync();
-    memory_global_dirty_log_stop(GLOBAL_DIRTY_DIRTY_RATE);
+    memory_global_dirty_log_stop(flags);
     qemu_mutex_unlock_iothread();
 }
 
 static int64_t do_calculate_dirtyrate_vcpu(DirtyPageRecord dirty_pages)
 {
-    uint64_t memory_size_MB;
+    uint64_t memory_size_KB;
     int64_t time_s;
     uint64_t increased_dirty_pages =
         dirty_pages.end_pages - dirty_pages.start_pages;
 
-    memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20;
+    memory_size_KB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 10;
     time_s = DirtyStat.calc_time;
 
-    return memory_size_MB / time_s;
+    return memory_size_KB / time_s;
 }
 
 static inline void record_dirtypages_bitmap(DirtyPageRecord *dirty_pages,
@@ -466,9 +481,14 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config)
     int64_t msec = 0;
     int64_t start_time;
     DirtyPageRecord dirty_pages;
+    unsigned int flags = GLOBAL_DIRTY_DIRTY_RATE;
+
+    if (config.scope == DIRTY_RATE_SCOPE_DIRTY_DEVICES) {
+        flags |= GLOBAL_DIRTY_DIRTY_RATE_DEVICES;
+    }
 
     qemu_mutex_lock_iothread();
-    memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE);
+    memory_global_dirty_log_start(flags);
 
     /*
      * 1'round of log sync may return all 1 bits with
@@ -500,7 +520,7 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config)
      * 1. fetch dirty bitmap from kvm
      * 2. stop dirty tracking
      */
-    dirtyrate_global_dirty_log_stop();
+    dirtyrate_global_dirty_log_stop(config.scope);
 
     record_dirtypages_bitmap(&dirty_pages, false);
 
@@ -527,7 +547,7 @@ static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config)
     DirtyStat.dirty_ring.nvcpu = nvcpu;
     DirtyStat.dirty_ring.rates = malloc(sizeof(DirtyRateVcpu) * nvcpu);
 
-    dirtyrate_global_dirty_log_start();
+    dirtyrate_global_dirty_log_start(config.scope);
 
     CPU_FOREACH(cpu) {
         record_dirtypages(dirty_pages, cpu, true);
@@ -540,7 +560,7 @@ static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config)
     msec = set_sample_page_period(msec, start_time);
     DirtyStat.calc_time = msec / 1000;
 
-    dirtyrate_global_dirty_log_stop();
+    dirtyrate_global_dirty_log_stop(config.scope);
 
     CPU_FOREACH(cpu) {
         record_dirtypages(dirty_pages, cpu, false);
@@ -631,6 +651,8 @@ void *get_dirtyrate_thread(void *arg)
 void qmp_calc_dirty_rate(int64_t calc_time,
                          bool has_sample_pages,
                          int64_t sample_pages,
+                         bool has_scope,
+                         DirtyRateScope scope,
                          bool has_mode,
                          DirtyRateMeasureMode mode,
                          Error **errp)
@@ -701,6 +723,7 @@ void qmp_calc_dirty_rate(int64_t calc_time,
     config.sample_period_seconds = calc_time;
     config.sample_pages_per_gigabytes = sample_pages;
     config.mode = mode;
+    config.scope = scope;
 
     cleanup_dirtyrate_stat(config);
 
@@ -709,6 +732,7 @@ void qmp_calc_dirty_rate(int64_t calc_time,
      * been used in last calculation
      **/
     dirtyrate_mode = mode;
+    dirtyrate_scope = scope;
 
     start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000;
     init_dirtyrate_stat(start_time, config);
@@ -736,9 +760,11 @@ void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict)
                    info->calc_time);
     monitor_printf(mon, "Mode: %s\n",
                    DirtyRateMeasureMode_str(info->mode));
+    monitor_printf(mon, "Scope: %s\n",
+                   DirtyRateScope_str(info->scope));
     monitor_printf(mon, "Dirty rate: ");
     if (info->has_dirty_rate) {
-        monitor_printf(mon, "%"PRIi64" (MB/s)\n", info->dirty_rate);
+        monitor_printf(mon, "%"PRIi64" (KB/s)\n", info->dirty_rate);
         if (info->has_vcpu_dirty_rate) {
             DirtyRateVcpuList *rate, *head = info->vcpu_dirty_rate;
             for (rate = head; rate != NULL; rate = rate->next) {
@@ -762,7 +788,9 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict)
     bool has_sample_pages = (sample_pages != -1);
     bool dirty_ring = qdict_get_try_bool(qdict, "dirty_ring", false);
     bool dirty_bitmap = qdict_get_try_bool(qdict, "dirty_bitmap", false);
+    bool dirty_devices = qdict_get_try_bool(qdict, "dirty_devices", false);
     DirtyRateMeasureMode mode = DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING;
+    DirtyRateScope scope = DIRTY_RATE_SCOPE_ALL;
     Error *err = NULL;
 
     if (!sec) {
@@ -781,9 +809,12 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict)
     } else if (dirty_ring) {
         mode = DIRTY_RATE_MEASURE_MODE_DIRTY_RING;
     }
+    if (dirty_devices) {
+        scope = DIRTY_RATE_SCOPE_DIRTY_DEVICES;
+    }
 
-    qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages, true,
-                        mode, &err);
+    qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages,
+                       true, scope, true, mode, &err);
     if (err) {
         hmp_handle_error(mon, err);
         return;
diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
index 69d4c5b8655f..4061edf9f4de 100644
--- a/migration/dirtyrate.h
+++ b/migration/dirtyrate.h
@@ -44,6 +44,7 @@ struct DirtyRateConfig {
     uint64_t sample_pages_per_gigabytes; /* sample pages per GB */
     int64_t sample_period_seconds; /* time duration between two sampling */
     DirtyRateMeasureMode mode; /* mode of dirtyrate measurement */
+    DirtyRateScope scope; /* scope of dirtyrate measurement */
 };
 
 /*
diff --git a/qapi/migration.json b/qapi/migration.json
index 27d7b281581d..082830c6e771 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1793,6 +1793,19 @@
 { 'enum': 'DirtyRateMeasureMode',
   'data': ['page-sampling', 'dirty-ring', 'dirty-bitmap'] }
 
+##
+# @DirtyRateScope:
+#
+# An enumeration of scope of measuring dirtyrate.
+#
+# @dirty-devices: calculate dirtyrate by devices only.
+#
+# Since: 6.2
+#
+##
+{ 'enum': 'DirtyRateScope',
+  'data': ['all', 'dirty-devices'] }
+
 ##
 # @DirtyRateInfo:
 #
@@ -1827,6 +1840,7 @@
            'calc-time': 'int64',
            'sample-pages': 'uint64',
            'mode': 'DirtyRateMeasureMode',
+           'scope': 'DirtyRateScope',
            '*vcpu-dirty-rate': [ 'DirtyRateVcpu' ] } }
 
 ##
@@ -1851,6 +1865,7 @@
 ##
 { 'command': 'calc-dirty-rate', 'data': {'calc-time': 'int64',
                                          '*sample-pages': 'int',
+                                         '*scope': 'DirtyRateScope',
                                          '*mode': 'DirtyRateMeasureMode'} }
 
 ##
diff --git a/softmmu/memory.c b/softmmu/memory.c
index bfa5d5178c5b..120c41f3b303 100644
--- a/softmmu/memory.c
+++ b/softmmu/memory.c
@@ -2826,6 +2826,11 @@ void memory_global_dirty_log_start(unsigned int flags)
     }
 }
 
+bool memory_global_dirty_devices(void)
+{
+    return !!(global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE_DEVICES);
+}
+
 static void memory_global_dirty_log_do_stop(unsigned int flags)
 {
     assert(flags && !(flags & (~GLOBAL_DIRTY_MASK)));
-- 
2.17.2


WARNING: multiple messages have this Message-ID (diff)
From: Joao Martins <joao.m.martins@oracle.com>
To: qemu-devel@nongnu.org
Cc: "John G . Johnson" <john.g.johnson@oracle.com>,
	kvm@vger.kernel.org, "Michael S. Tsirkin" <mst@redhat.com>,
	"Jason Wang" <jasowang@redhat.com>,
	"Peter Xu" <peterx@redhat.com>,
	"Joao Martins" <joao.m.martins@oracle.com>,
	"Eric Blake" <eblake@redhat.com>, "Yi Liu" <yi.l.liu@intel.com>,
	"Juan Quintela" <quintela@redhat.com>,
	"David Hildenbrand" <david@redhat.com>,
	"Markus Armbruster" <armbru@redhat.com>,
	"Nicolin Chen" <nicolinc@nvidia.com>,
	"Jason Gunthorpe" <jgg@nvidia.com>,
	"Kevin Tian" <kevin.tian@intel.com>,
	"Richard Henderson" <richard.henderson@linaro.org>,
	"Dr. David Alan Gilbert" <dgilbert@redhat.com>,
	"Eric Auger" <eric.auger@redhat.com>,
	"Alex Williamson" <alex.williamson@redhat.com>,
	"Thanos Makatos" <thanos.makatos@nutanix.com>,
	"Eduardo Habkost" <eduardo@habkost.net>,
	"Yishai Hadas" <yishaih@nvidia.com>,
	"Cornelia Huck" <cohuck@redhat.com>,
	"Philippe Mathieu-Daudé" <f4bug@amsat.org>,
	"Paolo Bonzini" <pbonzini@redhat.com>
Subject: [PATCH RFC 09/10] migration/dirtyrate: Expand dirty_bitmap to be tracked separately for devices
Date: Thu, 28 Apr 2022 22:13:50 +0100	[thread overview]
Message-ID: <20220428211351.3897-10-joao.m.martins@oracle.com> (raw)
In-Reply-To: <20220428211351.3897-1-joao.m.martins@oracle.com>

Expand dirtyrate measurer that is accessible via HMP calc_dirty_rate
or QMP 'calc-dirty-rate' to receive a @scope argument. The scope
then restricts the dirty tracking to be done at devices only,
while neither enabling or using the KVM (CPU) dirty tracker.
The default stays as is i.e. dirty-ring / dirty-bitmap from KVM.

This is useful to test, exercise the IOMMU dirty tracker and observe
how much a given device is dirtying memory.

Signed-off-by: Joao Martins <joao.m.martins@oracle.com>
---
 accel/kvm/kvm-all.c   | 12 +++++++++
 hmp-commands.hx       |  5 ++--
 hw/vfio/container.c   |  8 ++++++
 hw/vfio/iommufd.c     |  4 +++
 include/exec/memory.h | 10 +++++++-
 migration/dirtyrate.c | 59 +++++++++++++++++++++++++++++++++----------
 migration/dirtyrate.h |  1 +
 qapi/migration.json   | 15 +++++++++++
 softmmu/memory.c      |  5 ++++
 9 files changed, 102 insertions(+), 17 deletions(-)

diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c
index 5f1377ca048c..b4bbe0d20f6e 100644
--- a/accel/kvm/kvm-all.c
+++ b/accel/kvm/kvm-all.c
@@ -1517,6 +1517,10 @@ static void kvm_log_sync(MemoryListener *listener,
 {
     KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener);
 
+    if (memory_global_dirty_devices()) {
+        return;
+    }
+
     kvm_slots_lock();
     kvm_physical_sync_dirty_bitmap(kml, section);
     kvm_slots_unlock();
@@ -1529,6 +1533,10 @@ static void kvm_log_sync_global(MemoryListener *l)
     KVMSlot *mem;
     int i;
 
+    if (memory_global_dirty_devices()) {
+        return;
+    }
+
     /* Flush all kernel dirty addresses into KVMSlot dirty bitmap */
     kvm_dirty_ring_flush();
 
@@ -1558,6 +1566,10 @@ static void kvm_log_clear(MemoryListener *listener,
     KVMMemoryListener *kml = container_of(listener, KVMMemoryListener, listener);
     int r;
 
+    if (memory_global_dirty_devices()) {
+        return;
+    }
+
     r = kvm_physical_log_clear(kml, section);
     if (r < 0) {
         error_report_once("%s: kvm log clear failed: mr=%s "
diff --git a/hmp-commands.hx b/hmp-commands.hx
index 8476277aa9c9..28122d268ea3 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1739,10 +1739,11 @@ ERST
 
     {
         .name       = "calc_dirty_rate",
-        .args_type  = "dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?",
-        .params     = "[-r] [-b] second [sample_pages_per_GB]",
+        .args_type  = "dirty_devices:-d,dirty_ring:-r,dirty_bitmap:-b,second:l,sample_pages_per_GB:l?",
+        .params     = "[-d] [-r] [-b] second [sample_pages_per_GB]",
         .help       = "start a round of guest dirty rate measurement (using -r to"
                       "\n\t\t\t specify dirty ring as the method of calculation and"
+                      "\n\t\t\t specify devices as the only scope and"
                       "\n\t\t\t -b to specify dirty bitmap as method of calculation)",
         .cmd        = hmp_calc_dirty_rate,
     },
diff --git a/hw/vfio/container.c b/hw/vfio/container.c
index 6bc1b8763f75..fff8319c0036 100644
--- a/hw/vfio/container.c
+++ b/hw/vfio/container.c
@@ -84,6 +84,10 @@ static bool vfio_devices_all_dirty_tracking(VFIOContainer *bcontainer)
     VFIODevice *vbasedev;
     MigrationState *ms = migrate_get_current();
 
+    if (bcontainer->dirty_pages_supported) {
+        return true;
+    }
+
     if (!migration_is_setup_or_active(ms->state)) {
         return false;
     }
@@ -311,6 +315,10 @@ static int vfio_get_dirty_bitmap(VFIOContainer *bcontainer, uint64_t iova,
     uint64_t pages;
     int ret;
 
+    if (!memory_global_dirty_devices()) {
+        return 0;
+    }
+
     dbitmap = g_malloc0(sizeof(*dbitmap) + sizeof(*range));
 
     dbitmap->argsz = sizeof(*dbitmap) + sizeof(*range);
diff --git a/hw/vfio/iommufd.c b/hw/vfio/iommufd.c
index d75ecbf2ae52..4686cc713aac 100644
--- a/hw/vfio/iommufd.c
+++ b/hw/vfio/iommufd.c
@@ -150,6 +150,10 @@ static int iommufd_get_dirty_bitmap(VFIOContainer *bcontainer, uint64_t iova,
     VFIOIOASHwpt *hwpt;
     unsigned long *data, page_size, bitmap_size, pages;
 
+    if (!memory_global_dirty_devices()) {
+        return 0;
+    }
+
     if (!bcontainer->dirty_pages_supported) {
         return 0;
     }
diff --git a/include/exec/memory.h b/include/exec/memory.h
index 4d5997e6bbae..59c1d8bcc495 100644
--- a/include/exec/memory.h
+++ b/include/exec/memory.h
@@ -69,7 +69,10 @@ static inline void fuzz_dma_read_cb(size_t addr,
 /* Dirty tracking enabled because measuring dirty rate */
 #define GLOBAL_DIRTY_DIRTY_RATE (1U << 1)
 
-#define GLOBAL_DIRTY_MASK  (0x3)
+/* Dirty tracking enabled because measuring devices dirty rate */
+#define GLOBAL_DIRTY_DIRTY_RATE_DEVICES (1U << 2)
+
+#define GLOBAL_DIRTY_MASK  (0x7)
 
 extern unsigned int global_dirty_tracking;
 
@@ -2433,6 +2436,11 @@ void memory_global_dirty_log_start(unsigned int flags);
  */
 void memory_global_dirty_log_stop(unsigned int flags);
 
+/**
+ * memory_global_dirty_devices: check if the scope is just devices
+ */
+bool memory_global_dirty_devices(void);
+
 void mtree_info(bool flatview, bool dispatch_tree, bool owner, bool disabled);
 
 /**
diff --git a/migration/dirtyrate.c b/migration/dirtyrate.c
index aace12a78764..8c00cb6a3702 100644
--- a/migration/dirtyrate.c
+++ b/migration/dirtyrate.c
@@ -45,6 +45,8 @@ static int CalculatingState = DIRTY_RATE_STATUS_UNSTARTED;
 static struct DirtyRateStat DirtyStat;
 static DirtyRateMeasureMode dirtyrate_mode =
                 DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING;
+static DirtyRateScope dirtyrate_scope =
+                DIRTY_RATE_SCOPE_ALL;
 
 static int64_t set_sample_page_period(int64_t msec, int64_t initial_time)
 {
@@ -99,6 +101,7 @@ static struct DirtyRateInfo *query_dirty_rate_info(void)
     info->calc_time = DirtyStat.calc_time;
     info->sample_pages = DirtyStat.sample_pages;
     info->mode = dirtyrate_mode;
+    info->scope = dirtyrate_scope;
 
     if (qatomic_read(&CalculatingState) == DIRTY_RATE_STATUS_MEASURED) {
         info->has_dirty_rate = true;
@@ -406,32 +409,44 @@ static inline void record_dirtypages(DirtyPageRecord *dirty_pages,
     }
 }
 
-static void dirtyrate_global_dirty_log_start(void)
+static void dirtyrate_global_dirty_log_start(DirtyRateScope scope)
 {
+    unsigned int flags = GLOBAL_DIRTY_DIRTY_RATE;
+
+    if (scope == DIRTY_RATE_SCOPE_DIRTY_DEVICES) {
+        flags |= GLOBAL_DIRTY_DIRTY_RATE_DEVICES;
+    }
+
     qemu_mutex_lock_iothread();
-    memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE);
+    memory_global_dirty_log_start(flags);
     qemu_mutex_unlock_iothread();
 }
 
-static void dirtyrate_global_dirty_log_stop(void)
+static void dirtyrate_global_dirty_log_stop(DirtyRateScope scope)
 {
+    unsigned int flags = GLOBAL_DIRTY_DIRTY_RATE;
+
+    if (scope == DIRTY_RATE_SCOPE_DIRTY_DEVICES) {
+        flags |= GLOBAL_DIRTY_DIRTY_RATE_DEVICES;
+    }
+
     qemu_mutex_lock_iothread();
     memory_global_dirty_log_sync();
-    memory_global_dirty_log_stop(GLOBAL_DIRTY_DIRTY_RATE);
+    memory_global_dirty_log_stop(flags);
     qemu_mutex_unlock_iothread();
 }
 
 static int64_t do_calculate_dirtyrate_vcpu(DirtyPageRecord dirty_pages)
 {
-    uint64_t memory_size_MB;
+    uint64_t memory_size_KB;
     int64_t time_s;
     uint64_t increased_dirty_pages =
         dirty_pages.end_pages - dirty_pages.start_pages;
 
-    memory_size_MB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 20;
+    memory_size_KB = (increased_dirty_pages * TARGET_PAGE_SIZE) >> 10;
     time_s = DirtyStat.calc_time;
 
-    return memory_size_MB / time_s;
+    return memory_size_KB / time_s;
 }
 
 static inline void record_dirtypages_bitmap(DirtyPageRecord *dirty_pages,
@@ -466,9 +481,14 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config)
     int64_t msec = 0;
     int64_t start_time;
     DirtyPageRecord dirty_pages;
+    unsigned int flags = GLOBAL_DIRTY_DIRTY_RATE;
+
+    if (config.scope == DIRTY_RATE_SCOPE_DIRTY_DEVICES) {
+        flags |= GLOBAL_DIRTY_DIRTY_RATE_DEVICES;
+    }
 
     qemu_mutex_lock_iothread();
-    memory_global_dirty_log_start(GLOBAL_DIRTY_DIRTY_RATE);
+    memory_global_dirty_log_start(flags);
 
     /*
      * 1'round of log sync may return all 1 bits with
@@ -500,7 +520,7 @@ static void calculate_dirtyrate_dirty_bitmap(struct DirtyRateConfig config)
      * 1. fetch dirty bitmap from kvm
      * 2. stop dirty tracking
      */
-    dirtyrate_global_dirty_log_stop();
+    dirtyrate_global_dirty_log_stop(config.scope);
 
     record_dirtypages_bitmap(&dirty_pages, false);
 
@@ -527,7 +547,7 @@ static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config)
     DirtyStat.dirty_ring.nvcpu = nvcpu;
     DirtyStat.dirty_ring.rates = malloc(sizeof(DirtyRateVcpu) * nvcpu);
 
-    dirtyrate_global_dirty_log_start();
+    dirtyrate_global_dirty_log_start(config.scope);
 
     CPU_FOREACH(cpu) {
         record_dirtypages(dirty_pages, cpu, true);
@@ -540,7 +560,7 @@ static void calculate_dirtyrate_dirty_ring(struct DirtyRateConfig config)
     msec = set_sample_page_period(msec, start_time);
     DirtyStat.calc_time = msec / 1000;
 
-    dirtyrate_global_dirty_log_stop();
+    dirtyrate_global_dirty_log_stop(config.scope);
 
     CPU_FOREACH(cpu) {
         record_dirtypages(dirty_pages, cpu, false);
@@ -631,6 +651,8 @@ void *get_dirtyrate_thread(void *arg)
 void qmp_calc_dirty_rate(int64_t calc_time,
                          bool has_sample_pages,
                          int64_t sample_pages,
+                         bool has_scope,
+                         DirtyRateScope scope,
                          bool has_mode,
                          DirtyRateMeasureMode mode,
                          Error **errp)
@@ -701,6 +723,7 @@ void qmp_calc_dirty_rate(int64_t calc_time,
     config.sample_period_seconds = calc_time;
     config.sample_pages_per_gigabytes = sample_pages;
     config.mode = mode;
+    config.scope = scope;
 
     cleanup_dirtyrate_stat(config);
 
@@ -709,6 +732,7 @@ void qmp_calc_dirty_rate(int64_t calc_time,
      * been used in last calculation
      **/
     dirtyrate_mode = mode;
+    dirtyrate_scope = scope;
 
     start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME) / 1000;
     init_dirtyrate_stat(start_time, config);
@@ -736,9 +760,11 @@ void hmp_info_dirty_rate(Monitor *mon, const QDict *qdict)
                    info->calc_time);
     monitor_printf(mon, "Mode: %s\n",
                    DirtyRateMeasureMode_str(info->mode));
+    monitor_printf(mon, "Scope: %s\n",
+                   DirtyRateScope_str(info->scope));
     monitor_printf(mon, "Dirty rate: ");
     if (info->has_dirty_rate) {
-        monitor_printf(mon, "%"PRIi64" (MB/s)\n", info->dirty_rate);
+        monitor_printf(mon, "%"PRIi64" (KB/s)\n", info->dirty_rate);
         if (info->has_vcpu_dirty_rate) {
             DirtyRateVcpuList *rate, *head = info->vcpu_dirty_rate;
             for (rate = head; rate != NULL; rate = rate->next) {
@@ -762,7 +788,9 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict)
     bool has_sample_pages = (sample_pages != -1);
     bool dirty_ring = qdict_get_try_bool(qdict, "dirty_ring", false);
     bool dirty_bitmap = qdict_get_try_bool(qdict, "dirty_bitmap", false);
+    bool dirty_devices = qdict_get_try_bool(qdict, "dirty_devices", false);
     DirtyRateMeasureMode mode = DIRTY_RATE_MEASURE_MODE_PAGE_SAMPLING;
+    DirtyRateScope scope = DIRTY_RATE_SCOPE_ALL;
     Error *err = NULL;
 
     if (!sec) {
@@ -781,9 +809,12 @@ void hmp_calc_dirty_rate(Monitor *mon, const QDict *qdict)
     } else if (dirty_ring) {
         mode = DIRTY_RATE_MEASURE_MODE_DIRTY_RING;
     }
+    if (dirty_devices) {
+        scope = DIRTY_RATE_SCOPE_DIRTY_DEVICES;
+    }
 
-    qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages, true,
-                        mode, &err);
+    qmp_calc_dirty_rate(sec, has_sample_pages, sample_pages,
+                       true, scope, true, mode, &err);
     if (err) {
         hmp_handle_error(mon, err);
         return;
diff --git a/migration/dirtyrate.h b/migration/dirtyrate.h
index 69d4c5b8655f..4061edf9f4de 100644
--- a/migration/dirtyrate.h
+++ b/migration/dirtyrate.h
@@ -44,6 +44,7 @@ struct DirtyRateConfig {
     uint64_t sample_pages_per_gigabytes; /* sample pages per GB */
     int64_t sample_period_seconds; /* time duration between two sampling */
     DirtyRateMeasureMode mode; /* mode of dirtyrate measurement */
+    DirtyRateScope scope; /* scope of dirtyrate measurement */
 };
 
 /*
diff --git a/qapi/migration.json b/qapi/migration.json
index 27d7b281581d..082830c6e771 100644
--- a/qapi/migration.json
+++ b/qapi/migration.json
@@ -1793,6 +1793,19 @@
 { 'enum': 'DirtyRateMeasureMode',
   'data': ['page-sampling', 'dirty-ring', 'dirty-bitmap'] }
 
+##
+# @DirtyRateScope:
+#
+# An enumeration of scope of measuring dirtyrate.
+#
+# @dirty-devices: calculate dirtyrate by devices only.
+#
+# Since: 6.2
+#
+##
+{ 'enum': 'DirtyRateScope',
+  'data': ['all', 'dirty-devices'] }
+
 ##
 # @DirtyRateInfo:
 #
@@ -1827,6 +1840,7 @@
            'calc-time': 'int64',
            'sample-pages': 'uint64',
            'mode': 'DirtyRateMeasureMode',
+           'scope': 'DirtyRateScope',
            '*vcpu-dirty-rate': [ 'DirtyRateVcpu' ] } }
 
 ##
@@ -1851,6 +1865,7 @@
 ##
 { 'command': 'calc-dirty-rate', 'data': {'calc-time': 'int64',
                                          '*sample-pages': 'int',
+                                         '*scope': 'DirtyRateScope',
                                          '*mode': 'DirtyRateMeasureMode'} }
 
 ##
diff --git a/softmmu/memory.c b/softmmu/memory.c
index bfa5d5178c5b..120c41f3b303 100644
--- a/softmmu/memory.c
+++ b/softmmu/memory.c
@@ -2826,6 +2826,11 @@ void memory_global_dirty_log_start(unsigned int flags)
     }
 }
 
+bool memory_global_dirty_devices(void)
+{
+    return !!(global_dirty_tracking & GLOBAL_DIRTY_DIRTY_RATE_DEVICES);
+}
+
 static void memory_global_dirty_log_do_stop(unsigned int flags)
 {
     assert(flags && !(flags & (~GLOBAL_DIRTY_MASK)));
-- 
2.17.2



  parent reply	other threads:[~2022-04-28 21:15 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-04-28 21:13 [PATCH RFC 00/10] hw/vfio, x86/iommu: IOMMUFD Dirty Tracking Joao Martins
2022-04-28 21:13 ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 01/10] amd-iommu: Cache PTE/DTE info in IOTLB Joao Martins
2022-04-28 21:13   ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 02/10] amd-iommu: Access/Dirty bit support Joao Martins
2022-04-28 21:13   ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 03/10] intel-iommu: Cache PASID entry flags Joao Martins
2022-04-28 21:13   ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 04/10] intel_iommu: Second Stage Access Dirty bit support Joao Martins
2022-04-28 21:13   ` Joao Martins
2022-04-29  2:26   ` Jason Wang
2022-04-29  2:26     ` Jason Wang
2022-04-29  9:12     ` Joao Martins
2022-04-29  9:12       ` Joao Martins
2022-04-29 18:21       ` Peter Xu
2022-04-29 18:21         ` Peter Xu
2022-05-03 11:54         ` Joao Martins
2022-05-05  7:41           ` Jason Wang
2022-05-05  9:57             ` Joao Martins
2022-05-04 20:11   ` Peter Xu
2022-05-05  9:54     ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 05/10] linux-headers: import iommufd.h hwpt extensions Joao Martins
2022-04-28 21:13   ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 06/10] vfio/iommufd: Add HWPT_SET_DIRTY support Joao Martins
2022-04-28 21:13   ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 07/10] vfio/iommufd: Add HWPT_GET_DIRTY_IOVA support Joao Martins
2022-04-28 21:13   ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 08/10] vfio/iommufd: Add IOAS_UNMAP_DIRTY support Joao Martins
2022-04-28 21:13   ` Joao Martins
2022-04-28 21:13 ` Joao Martins [this message]
2022-04-28 21:13   ` [PATCH RFC 09/10] migration/dirtyrate: Expand dirty_bitmap to be tracked separately for devices Joao Martins
2022-05-02 12:54   ` Markus Armbruster
2022-05-02 12:54     ` Markus Armbruster
2022-05-02 14:35     ` Joao Martins
2022-05-02 14:35       ` Joao Martins
2022-04-28 21:13 ` [PATCH RFC 10/10] hw/vfio: Add nr of dirty pages to tracepoints Joao Martins
2022-04-28 21:13   ` Joao Martins

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220428211351.3897-10-joao.m.martins@oracle.com \
    --to=joao.m.martins@oracle.com \
    --cc=alex.williamson@redhat.com \
    --cc=armbru@redhat.com \
    --cc=cohuck@redhat.com \
    --cc=david@redhat.com \
    --cc=dgilbert@redhat.com \
    --cc=eblake@redhat.com \
    --cc=eduardo@habkost.net \
    --cc=eric.auger@redhat.com \
    --cc=f4bug@amsat.org \
    --cc=jasowang@redhat.com \
    --cc=jgg@nvidia.com \
    --cc=john.g.johnson@oracle.com \
    --cc=kevin.tian@intel.com \
    --cc=kvm@vger.kernel.org \
    --cc=marcel.apfelbaum@gmail.com \
    --cc=mst@redhat.com \
    --cc=nicolinc@nvidia.com \
    --cc=pbonzini@redhat.com \
    --cc=peterx@redhat.com \
    --cc=qemu-devel@nongnu.org \
    --cc=quintela@redhat.com \
    --cc=richard.henderson@linaro.org \
    --cc=thanos.makatos@nutanix.com \
    --cc=yi.l.liu@intel.com \
    --cc=yishaih@nvidia.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.