| Mapped-ram |
| ========== |
| |
| Mapped-ram is a new stream format for the RAM section designed to |
| supplement the existing ``file:`` migration and make it compatible |
| with ``multifd``. This enables parallel migration of a guest's RAM to |
| a file. |
| |
| The core of the feature is to ensure that RAM pages are mapped |
| directly to offsets in the resulting migration file. This enables the |
| ``multifd`` threads to write exclusively to those offsets even if the |
| guest is constantly dirtying pages (i.e. live migration). Another |
| benefit is that the resulting file will have a bounded size, since |
| pages which are dirtied multiple times will always go to a fixed |
| location in the file, rather than constantly being added to a |
| sequential stream. Having the pages at fixed offsets also allows the |
| usage of O_DIRECT for save/restore of the migration stream as the |
| pages are ensured to be written respecting O_DIRECT alignment |
| restrictions. |
| |
| Usage |
| ----- |
| |
| On both source and destination, enable the ``multifd`` and |
| ``mapped-ram`` capabilities: |
| |
| ``migrate_set_capability multifd on`` |
| |
| ``migrate_set_capability mapped-ram on`` |
| |
| Use a ``file:`` URL for migration: |
| |
| ``migrate file:/path/to/migration/file`` |
| |
| Mapped-ram migration is best done non-live, i.e. by stopping the VM on |
| the source side before migrating. |
| |
| For best performance enable the ``direct-io`` parameter as well: |
| |
| ``migrate_set_parameter direct-io on`` |
| |
| Use-cases |
| --------- |
| |
| The mapped-ram feature was designed for use cases where the migration |
| stream will be directed to a file in the filesystem and not |
| immediately restored on the destination VM\ [#alternatives]_. These could be |
| thought of as snapshots. We can further categorize them into live and |
| non-live. |
| |
| - Non-live snapshot |
| |
| If the use case requires a VM to be stopped before taking a snapshot, |
| that's the ideal scenario for mapped-ram migration. Not having to |
| track dirty pages, the migration will write the RAM pages to the disk |
| as fast as it can. |
| |
| Note: if a snapshot is taken of a running VM, but the VM will be |
| stopped after the snapshot by the admin, then consider stopping it |
| right before the snapshot to take benefit of the performance gains |
| mentioned above. |
| |
| - Live snapshot |
| |
| If the use case requires that the VM keeps running during and after |
| the snapshot operation, then mapped-ram migration can still be used, |
| but will be less performant. Other strategies such as |
| background-snapshot should be evaluated as well. One benefit of |
| mapped-ram in this scenario is portability since background-snapshot |
| depends on async dirty tracking (KVM_GET_DIRTY_LOG) which is not |
| supported outside of Linux. |
| |
| .. [#alternatives] While this same effect could be obtained with the usage of |
| snapshots or the ``file:`` migration alone, mapped-ram provides |
| a performance increase for VMs with larger RAM sizes (10s to |
| 100s of GiBs), specially if the VM has been stopped beforehand. |
| |
| RAM section format |
| ------------------ |
| |
| Instead of having a sequential stream of pages that follow the |
| RAMBlock headers, the dirty pages for a RAMBlock follow its header |
| instead. This ensures that each RAM page has a fixed offset in the |
| resulting migration file. |
| |
| A bitmap is introduced to track which pages have been written in the |
| migration file. Pages are written at a fixed location for every |
| ramblock. Zero pages are ignored as they'd be zero in the destination |
| migration as well. |
| |
| :: |
| |
| Without mapped-ram: With mapped-ram: |
| |
| --------------------- -------------------------------- |
| | ramblock 1 header | | ramblock 1 header | |
| --------------------- -------------------------------- |
| | ramblock 2 header | | ramblock 1 mapped-ram header | |
| --------------------- -------------------------------- |
| | ... | | padding to next 1MB boundary | |
| --------------------- | ... | |
| | ramblock n header | -------------------------------- |
| --------------------- | ramblock 1 pages | |
| | RAM_SAVE_FLAG_EOS | | ... | |
| --------------------- -------------------------------- |
| | stream of pages | | ramblock 2 header | |
| | (iter 1) | -------------------------------- |
| | ... | | ramblock 2 mapped-ram header | |
| --------------------- -------------------------------- |
| | RAM_SAVE_FLAG_EOS | | padding to next 1MB boundary | |
| --------------------- | ... | |
| | stream of pages | -------------------------------- |
| | (iter 2) | | ramblock 2 pages | |
| | ... | | ... | |
| --------------------- -------------------------------- |
| | ... | | ... | |
| --------------------- -------------------------------- |
| | RAM_SAVE_FLAG_EOS | |
| -------------------------------- |
| | ... | |
| -------------------------------- |
| |
| where: |
| - ramblock header: the generic information for a ramblock, such as |
| idstr, used_len, etc. |
| |
| - ramblock mapped-ram header: the information added by this feature: |
| bitmap of pages written, bitmap size and offset of pages in the |
| migration file. |
| |
| Restrictions |
| ------------ |
| |
| Since pages are written to their relative offsets and out of order |
| (due to the memory dirtying patterns), streaming channels such as |
| sockets are not supported. A seekable channel such as a file is |
| required. This can be verified in the QIOChannel by the presence of |
| the QIO_CHANNEL_FEATURE_SEEKABLE. |
| |
| The improvements brought by this feature apply only to guest physical |
| RAM. Other types of memory such as VRAM are migrated as part of device |
| states. |