• QEMU DirtyLimit特性介绍


    背景

    • 热迁移实现逻辑中,如果虚机内存负载高,源端不断产生新的内存脏页,热迁移由于不断传输源端新产生的脏页,导致剩余脏页量一直无法达到阈值,迟迟无法收敛。因此热迁移实现中,一个重要的逻辑就是实现脏页收敛算法,使得源端脏页能够尽快达到阈值。常用的收敛算法有auto-converge、xbzrle、compression、multifd等,这些算法各有其优缺点。
    • 其中auto-converge是最有效的收敛算法,其核心思想是降低脏页产生的速率。通过减少虚拟机vCPU运行时间来降低虚机脏页产生速率,使其小于迁移拷贝速率,以满足迁移收敛条件,参考cpu throttle原理浅析。该算法优点是任何虚拟化场景都适用且有效。缺点是在限制虚机脏页产生的同时,也限制了虚机vCPU运行时间,虚机的计算性能在迁移过程中也随之下降。
    • 内核引入dirty-ring后,提供了一种基于dirty-ring实现虚机内存脏页统计的方式,参考Dirty Ring脏页统计。dirty-ring的机制让我们很可以计算每个vCPU的脏页速率,如果再给每个vCPU设置一个速率上限,当vCPU超过上限时通过throttle的方式让其睡眠以达到降低脏页速率的目的。最后周期性计算vCPU脏页速率并对比设置的速率上限,当某个vCPU超过该上限时,就通过睡眠“惩罚”它。这样可以实现将所有vCPU都控制在一个设置的速率上限内。这就是DirtyLimit的核心思想。如果将其应用在热迁移中,可以达到和auto-converge相同的收敛效果,并且热迁过程中读性能还不会下降。DirtyLimit的介绍可以参考天翼云公众号文章: 迁移速度与计算性能兼得!天翼云DirtyLimit技术大显身手

    基本原理

    PML

    • Dirty-Ring基于Intel PML(page-modification log buffer)实现,我们首先介绍PML工作流程,其框架如下:
      在这里插入图片描述
      Intel VT-x提供的VMCS(virtual machine control structure)中,有三个地方与PML特性相关:
    1. Extended-Page-Table Pointer: EPTP字段中的bits[6],控制当物理CPU访问内存页后,硬件是否将对应的accessed and dirty flags 置位,PML需要开启。
      在这里插入图片描述
    2. VM-execution control fields: 控制区域中的Secondary Processor-Based VM-Execution Controls子字段的bits[17]控制位用于控制是否开启PML,PML需要开启。Control Field for Page-Modification Logging存放一段4K物理内存的地址,这段内存是就是PML的buffer,其内容是vCPU访问的物理内存页地址(GPA), 每条地址64bit,一共512条,因此其大小为512 * 64bit = 4K:
      在这里插入图片描述
      在这里插入图片描述
    3. Guest State area: Guest状态字段中的PML index子字段,用于指示物理CPU将下一次访问的内存地址记录到PML buffer的哪一条,一旦设置好,CPU填写了一条PML entry后,硬件会自动将PML index加1。
      在这里插入图片描述
    • 使能PML的整个流程是,开启EPTP的页表标脏功能,开启VM-execution control fields的PML开关,为每个CPU的PML buffer分配4K内存,将内存地址填入VM-execution control fields的地址字段,最后设置将CPU填写PML buffer的起始位置写入PML index,执行VMLAUNCH指令进入guest模式。

    Dirty-Ring

    • 基于PML buffer,QEMU引入了可以对每个vCPU脏页跟踪的Dirty-Ring机制,基于该机制实现了每个vCPU的脏页速率计算。参考QEMU脏页速率计算原理中的Dirty-Ring一节。

    Dirty-Limit

    • 实现脏页速率计算后,我们可以设置DirtyLimit并周期性地计算每个vCPU的脏页速率,对比两者的值,如果脏页速率大于DirtyLimit,便通过让对应vCPU睡眠来惩罚它,让vCPU的脏页速率逐渐下降至设置的值,示意图如下:
      在这里插入图片描述
    1. 首先QEMU获取用户设定的DirtyLimit值,将其保存到内存中,DirtyLimit与vCPU为1对1的关系
    2. 之后启动单独线程周期性计算vCPU的脏页速率DirtyRate并保存到内存中,DirtyRate与vCPU也为1对1的关系
    3. 当KVM将某个vCPU的Dirty Ring的条目填满之后,对应vCPU便会抛出异常,vCPU线程从内核态退出到用户态,此时QEMU在该路径上将其拦截,对比该vCPU的DirtyRate和DirtyLimit的,如果发现DirtyRate大于DirtyLimit,便计算用于“惩罚”vCPU的睡眠时间,然后让对应vCPU线程睡眠。

    具体实现

    • dirty-limit的实现在单独的一个文件中:softmmu/dirtylimit.c

    数据结构

    • dirty-limit的核心数据结构就是两个全局变量:DirtyRate和DirtyLimit

    vcpu_dirty_rate_stat

    • 保存DirtyRate的数据结构
    typedef struct VcpuStat {
    	/* 保存rates数组中的vCPU个数 */
        int nvcpu; /* number of vcpu */
        /* dirtyrate数组,记录每个vCPU对应的脏页速率 */
        DirtyRateVcpu *rates; /* array of dirty rate for each vcpu */
    } VcpuStat;
    
    struct {                         
        VcpuStat stat;     	/* 保存虚机脏页速率 */          
        bool running;    	/* 标记当前是否正在周期性计算脏页速率 */
        QemuThread thread; 	/* 周期性计算脏页速率的线程 */
    } *vcpu_dirty_rate_stat
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    dirtylimit_state

    • 保存DirtyLimit数据结构
    typedef struct VcpuDirtyLimitState {
        int cpu_index;		/* vCPU ID*/
        bool enabled;   	/* 标记该vCPU是否使能DirtyLimit*/
        /*
         * Quota dirty page rate, unit is MB/s
         * zero if not enabled.
         */
        uint64_t quota;	 	/* vCPU使能DirtyLimit时用户设置的上限值 */
    } VcpuDirtyLimitState;
    
    struct {
        VcpuDirtyLimitState *states;	/* 保存虚机的DirtyLimit */
        /* Max cpus number configured by user */
        int max_cpus;					/* 虚机配置的最大vCPU数 */
        /* Number of vcpu under dirtylimit */
        int limited_nvcpu;				/* 虚机使能DirtyLimit的vCPU数 */
    } *dirtylimit_state;
    
    /* protect dirtylimit_state */
    static QemuMutex dirtylimit_mutex;
    
    /* dirtylimit thread quit if dirtylimit_quit is true */
    static bool dirtylimit_quit;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    算法实现

    接口逻辑

    • DirtyLimit算法的核心逻辑主要在qmp_set_vcpu_dirty_limitqmp_cancel_vcpu_dirty_limit中实现,我们简单分析其逻辑
    qmp_set_vcpu_dirty_limit
    void qmp_set_vcpu_dirty_limit(bool has_cpu_index,	/* qmp是否传入*/
                                  int64_t cpu_index,             
                                  uint64_t dirty_rate,           
                                  Error **errp)                  
    {
    	/* dirty-limit依赖dirty-ring,首先检查是否配置 */
        if (!kvm_enabled() || !kvm_dirty_ring_enabled()) {
            error_setg(errp, "dirty page limit feature requires KVM with"
                       " accelerator property 'dirty-ring-size' set'");
            return;
        }  
    	/* dirty-limit可以不指定vCPU index,这是QEMU会限制所有vCPU,如果指定,检查vCPU index是否超出范围 */
        if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) {
            error_setg(errp, "incorrect cpu index specified");
            return;
        }  
    	/* 如果当前热迁移正在使用dirtylimit算法,不希望受用户设置的影响,因此热迁移期间不允许使能和取消dirtylimit */
        if (!dirtylimit_is_allowed()) {
            error_setg(errp, "can't set dirty page rate limit while"
                       " migration is running");      
            return;
        }
    	/* 如果dirty_rate传入0,表示取消dirty-limit */
        if (!dirty_rate) {
            qmp_cancel_vcpu_dirty_limit(has_cpu_index, cpu_index, errp);
            return;
        }
    	/* 为保证qmp_set_vcpu_dirty_limit接口线程安全,保护dirtylimit_state全局变量,加锁 */
        dirtylimit_state_lock();
        
    	/* 如果是第一次使能dirty-limit,完成初始化工作
    	 * 初始化中主要是初始化全局变量并启动脏页速率计算线程
    	 * 周期性计算其vCPU速率并更新到vcpu_dirty_rate_stat
    	 * 最后,使能DirtyLimit限制,周期性地为每个超过dirty-limit的vCPU计算睡眠时间 */
        if (!dirtylimit_in_service()) {
            dirtylimit_init();
        }
        
    	/* 设置用户配置的dirty-limit,核心工作就是更新全局变量dirtylimit_state */
        if (has_cpu_index) {
            dirtylimit_set_vcpu(cpu_index, dirty_rate, true);
        } else {
            dirtylimit_set_all(dirty_rate, true);
        }
    
        dirtylimit_state_unlock();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    qmp_cancel_vcpu_dirty_limit
    void qmp_cancel_vcpu_dirty_limit(bool has_cpu_index,
                                     int64_t cpu_index,
                                     Error **errp)
    {   
    	/* 检查依赖是否满足 */
        if (!kvm_enabled() || !kvm_dirty_ring_enabled()) {
            return;
        }
        /* 检查index是否在范围之内 */
        if (has_cpu_index && !dirtylimit_vcpu_index_valid(cpu_index)) {
            error_setg(errp, "incorrect cpu index specified");
            return;
        }
    	/* 检查是否与热迁移冲突 */
        if (!dirtylimit_is_allowed()) {
            error_setg(errp, "can't cancel dirty page rate limit while"
                       " migration is running");
            return;
        }   
        /* 如果当前dirty-limit已经停止,直接返回 */            
        if (!dirtylimit_in_service()) {
            return;
        }
        /* 更新dirtylimit_state全局变量前加锁  */
        dirtylimit_state_lock();
    
    	/* 更新dirtylimit_state */
        if (has_cpu_index) {
            dirtylimit_set_vcpu(cpu_index, 0, false);
        } else {
            dirtylimit_set_all(0, false);
        }
    	/* 如果最后一个使能dirty-limit的vCPU被取消,停止脏页速率计算线程,停止DirtyLimit限制逻辑 */
        if (!dirtylimit_state->limited_nvcpu) {
            dirtylimit_cleanup();
        }
    
        dirtylimit_state_unlock();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    限制算法

    算法框架
    • DirtyLimit算法框架示意图如下:
      main   --------------> throttle thread ------------> PREPARE(1) <--------
      thread  \                                                |              |
               \                                               |              |
                \                                              V              |
                 -\                                        CALCULATE(2)       |
                   \                                           |              |
                    \                                          |              |
                     \                                         V              |
                      \                                    SET PENALTY(3) -----
                       -\                                      |
                         \                                     |
                          \                                    V
                           -> virtual CPU thread -------> ACCEPT PENALTY(4)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 当qmp_set_vcpu_dirty_limit命令被调用时,QEMU主线程启动了throttle线程,其作用是实现DirtyLimit主要逻辑,主要包含以下阶段:
    1. PREPARE (1) - 准备阶段
      这个阶段主要为二阶段- CALCULATE(2)的计算准备输入,主要准备两个值:虚机当前vCPU脏页速率(dirty page rate),用户配置的虚机vCPU脏页速率上限(dirty page rate limit),其脏页速率通过调用现有的脏页速率计算接口得到,参考QEMU脏页速率计算,脏页速率上限通过用户配置得到。
    2. CALCULATE (2) - 计算阶段
      这个阶段主要判断vCPU的脏页速率是否低于用户配置的脏页速率上限,如果不满足,计算在三阶段-SET PENALTY (3)中用于惩罚虚机vCPU的睡眠时间。
    3. SET PENALTY (3) - 惩罚阶段
      这个阶段是具体让vCPU睡眠的阶段,其主要逻辑是在vCPU因为KVM_EXIT_DIRTY_RING_FULL而异常退出的代码路径上让vCPU睡眠。
    • 通过上面三个阶段的操作。QEMU期望让将vCPU的脏页速率限制在用户配置的阈值范围内。
    理想效果
    • 接口实现中我们提到了使能DirtyLimit限制,其核心逻辑就是计算超过DirtyLimit的vCPU的睡眠时间,假设vCPU当前脏页速率current=200MB/s,目标速率quota=40MB/s,速率计算和睡眠时间更新的周期(x_vcpu_dirty_limit_period)为1s,我们举例说明理想的限制算法对速率的限制曲线如下:
      在这里插入图片描述
    • 限制算法的理想行为是:
    1. 如果目标脏页速率与实际脏页速率相差很大,两者相减得到的差值比目标脏页速率一半还多,我们希望惩罚的力度大,让脏页速率在一个速率计算周期内(x_vcpu_dirty_limit_period)线性下降。如图中的第1秒,脏页速率从200MB/s减少到了70MB/s
    2. 如果目标脏页速率与实际脏页速率相差不大,两者相减比max(quota, current)的一半少,我们希望减小惩罚力度,让脏页速率在一个速率计算周期内下降固定值,这样可以避免实际脏页速率在quota值上下大幅的震荡。如图中的第2、3秒,脏页速率在1秒内下降10MB/s。
    3. 如果目标脏页速率与实际脏页速率相差在一个可接受的范围内(默认值25MB/s),保持惩罚力度,让vCPU的睡眠时间不变。如图中的3~9秒。
    具体实现
    • 上面是限制算法的理想效果,具体实现时没法完全达到预期,其核心函数是dirtylimit_adjust_throttle,我们进一步分析:
    static void dirtylimit_set_throttle(CPUState *cpu,
                                        uint64_t quota,
                                        uint64_t current)
    {
        int64_t ring_full_time_us = 0;
        uint64_t sleep_pct = 0;       
        uint64_t throttle_us = 0;
        
    	/* 如果当前vCPU的速率已经是0,取消惩罚,直接返回 */
        if (current == 0) {
            cpu->throttle_us_per_full = 0;
            return;
        }
    	/* 获取当前虚机vCPU的脏页速率和dirty-ring的size,
    	 * 计算理想情况下,vCPU以当前的脏页速率填满一个空的dirty-ring表需要多长时间 */        
        ring_full_time_us = dirtylimit_dirty_ring_full_time(current);
        
        /* 如果目标脏页速率和当前脏页速率相差过大,让vCPU速率线性下降 */   
        if (dirtylimit_need_linear_adjustment(quota, current)) {
            if (quota < current) {   
            	/* 根据目标脏页速率和当前脏页速率,计算一个睡眠时间占填满整个dirty-ring表时间的百分比
            	 * 根据百分比计算vCPU的睡眠时间,期望达到的效果是:
            	 * 当vCPU速率很大时,睡眠的时间会相对较短,反之,睡眠时间会相对长
            	 */   
                sleep_pct = (current - quota) * 100 / current;
                throttle_us =
                    ring_full_time_us * sleep_pct / (double)(100 - sleep_pct);
                cpu->throttle_us_per_full += throttle_us;
            } else {
                sleep_pct = (quota - current) * 100 / quota;
                throttle_us =
                    ring_full_time_us * sleep_pct / (double)(100 - sleep_pct);
                cpu->throttle_us_per_full -= throttle_us;
            }
    
            trace_dirtylimit_throttle_pct(cpu->cpu_index,
                                          sleep_pct,
                                          throttle_us);
        } else {
        	/*取一个测试效果最好的经验值作为固定的睡眠时间 */
            if (quota < current) {
                cpu->throttle_us_per_full += ring_full_time_us / 10;
            } else {
                cpu->throttle_us_per_full -= ring_full_time_us / 10;
            }
        }
        /* 为保证vCPU睡眠时间过长导致Guest内核线程softlockup,设置vCPU睡眠时间的上限 */
        cpu->throttle_us_per_full = MIN(cpu->throttle_us_per_full,
            ring_full_time_us * DIRTYLIMIT_THROTTLE_PCT_MAX);
    
        cpu->throttle_us_per_full = MAX(cpu->throttle_us_per_full, 0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 上面分析了睡眠时间计算,最终的数值被保存到了CPUState结构体的throttle_us_per_full字段中,限制算法的最后阶段就是让vCPU睡眠throttle_us_per_full指定的时间,这个逻辑在QEMU处理vCPU线程退出时完成,如下:
    kvm_cpu_exec
    	/* 执行vCPU线程,陷入内核 */
    	run_ret = kvm_vcpu_ioctl(cpu, KVM_RUN, 0);
    	/* 从内核exit到用户态空间 */
    	switch (run->exit_reason) {
    		/* 根据exit_reason做对应处理 */
    		case KVM_EXIT_IO:
    		......
    		/* 如果退出是由于Dirty-Ring满了,做对应的处理
    		 * 这里QEMU的主要工作就是清空Dirty-Ring,让内核可以继续填写
    		 */
            case KVM_EXIT_DIRTY_RING_FULL: 
                /*
                 * We shouldn't continue if the dirty ring of this vcpu is
                 * still full.  Got kicked by KVM_RESET_DIRTY_RINGS.
                 */
                trace_kvm_dirty_ring_full(cpu->cpu_index);
                qemu_mutex_lock_iothread();    
                /*
                 * We throttle vCPU by making it sleep once it exit from kernel
                 * due to dirty ring full. In the dirtylimit scenario, reaping
                 * all vCPUs after a single vCPU dirty ring get full result in
                 * the miss of sleep, so just reap the ring-fulled vCPU.
                 */
                if (dirtylimit_in_service()) { 
                	/* 当dirty-limit开启时,仅清空对应vCPU的Dirty-Ring
                	 * 这样可以保证每个vCPU满了之后都会走到该路径,保证其接受惩罚
                	 * 如果某个vCPU满了,但是这里我们把所有vCPU的Dirty-Ring都清空的话
                	 * 就会导致有些脏页速率较大的vCPU永远接收不到惩罚 */
                    kvm_dirty_ring_reap(kvm_state, cpu);
                } else {
                    kvm_dirty_ring_reap(kvm_state, NULL);
                }
                qemu_mutex_unlock_iothread();  
                /* 调用睡眠函数,实施最终的惩罚 */
                dirtylimit_vcpu_execute(cpu);  
                ret = 0;
                break;
                ......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    测试验证

    QEMU

    1. 源端
    • 通过下面方式启动虚机:
    #!/bin/bash
      
    /usr/bin/qemu-system-x86_64 \
        -display none -vga none \
        -name guest=migrate_src,debug-threads=on \
        -monitor stdio \
        -accel kvm,dirty-ring-size=65536 -cpu host \
        -kernel /home/work/fast_qemu/vmlinuz-6.1.19-7.0.0.17.oe2303.x86_64 \
        -initrd /home/work/fast_qemu/initrd-stress.img \
        -append "noapic edd=off printk.time=1 noreplace-smp cgroup_disable=memory pci=noearly console=ttyS0 debug ramsize=4" \
        -chardev file,id=charserial0,path=/var/log/mig_dst_console.log\
        -serial chardev:charserial0 \
        -D /var/log/mig_dst.log \
        -m 4096 -smp 2 \
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    1. 目的端
    • 通过下面方式启动虚机,其中initrd-stress.img是QEMU内存压测工具简介中介绍的引导镜像。其中192.168.31.155是目的端IP,9000是目的端QEMU监听迁入内存的端口:
    #!/bin/bash
      
    /usr/bin/qemu-system-x86_64 \
        -display none -vga none \
        -name guest=migrate_src,debug-threads=on \
        -monitor stdio \
        -accel kvm,dirty-ring-size=65536 -cpu host \
        -kernel /home/work/fast_qemu/vmlinuz-6.1.19-7.0.0.17.oe2303.x86_64 \
        -initrd /home/work/fast_qemu/initrd-stress.img \
        -append "noapic edd=off printk.time=1 noreplace-smp cgroup_disable=memory pci=noearly console=ttyS0 debug ramsize=4" \
        -chardev file,id=charserial0,path=/var/log/mig_dst_console.log\
        -serial chardev:charserial0 \
        -D /var/log/mig_dst.log \
        -m 4096 -smp 2 \
        -incoming tcp:192.168.31.155:9000
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    1. 迁移操作
    • 通过以下命令行将虚机从源端迁移到目的端:
    QEMU 8.1.50 monitor - type 'help' for more information
    (qemu) migrate_set_capability 
    auto-converge            background-snapshot      block                    
    compress                 dirty-bitmaps            dirty-limit              
    events                   late-block-activate      multifd                  
    pause-before-switchover  postcopy-blocktime       postcopy-preempt         
    postcopy-ram             rdma-pin-all             release-ram              
    return-path              switchover-ack           validate-uuid            
    x-colo                   x-ignore-shared          xbzrle                   
    zero-blocks              zero-copy-send            
    (qemu) migrate_set_capability dirty-limit on
    (qemu) migrate -d tcp:192.168.31.155:9000
    /* 查看迁移使用的capability,可以看到dirty-imit被开启 */
    (qemu) info migrate_capabilities
    xbzrle: off
    rdma-pin-all: off
    auto-converge: off
    zero-blocks: off
    compress: off
    events: off
    postcopy-ram: off
    x-colo: off
    release-ram: off
    block: off
    return-path: off
    pause-before-switchover: off
    multifd: off
    dirty-bitmaps: off
    postcopy-blocktime: off
    late-block-activate: off
    x-ignore-shared: off
    validate-uuid: off
    background-snapshot: off
    zero-copy-send: off
    postcopy-preempt: off
    switchover-ack: off
    dirty-limit: on
    /* 查看迁移过程中的实时数据,dirty-limit会在迁移迭代的第三轮开启 */
    (qemu) info migrate
    globals:
    store-global-state: on
    only-migratable: off
    send-configuration: on
    send-section-footer: on
    decompress-error-check: on
    clear-bitmap-shift: 18
    Migration status: active
    total time: 3433 ms
    expected downtime: 300 ms
    setup: 33 ms
    transferred ram: 23936 kbytes
    throughput: 26.16 mbps
    remaining ram: 1438576 kbytes
    total ram: 4195080 kbytes
    duplicate: 684655 pages
    skipped: 0 pages
    normal: 4471 pages
    normal bytes: 17884 kbytes
    dirty sync count: 1
    page size: 4 kbytes
    multifd bytes: 0 kbytes
    pages-per-second: 363313
    precopy ram: 23936 kbytes
    /* 再次查看迁移信息,dirty-limit有相关信息输出 */
    (qemu) info migrate 
    globals:
    store-global-state: on
    only-migratable: off
    send-configuration: on
    send-section-footer: on
    decompress-error-check: on
    clear-bitmap-shift: 18
    Migration status: active
    total time: 372685 ms
    expected downtime: 63130 ms
    setup: 19 ms
    transferred ram: 3598269 kbytes
    throughput: 99.79 mbps
    remaining ram: 386204 kbytes
    total ram: 4195080 kbytes
    duplicate: 822808 pages
    skipped: 0 pages
    normal: 895998 pages
    normal bytes: 3583992 kbytes
    dirty sync count: 5
    page size: 4 kbytes
    multifd bytes: 0 kbytes
    pages-per-second: 3039
    dirty pages rate: 2015 pages
    precopy ram: 3598269 kbytes
    dirty-limit throttle time: 23272722 us
    dirty-limit ring full time: 235078 us
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92

    Libvirt

    • TODO

    一个广子

    • 本人负责QEMU社区Dirty Limit和Dirty page rate模块的维护,欢迎虚拟化领域的同学提交patch,为社区贡献力量,模块包含以下文件:
    Migration dirty limit and dirty page rate
    F: system/dirtylimit.c
    F: include/sysemu/dirtylimit.h
    F: migration/dirtyrate.c
    F: migration/dirtyrate.h
    F: include/sysemu/dirtyrate.h
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    这份企业智能应用宝典,请收好~
    RTX3090+win10+CUDA11.6+cudnn8.5.0+pytorch1.12.1 环境——个人配置经验
    深度学习Week8-咖啡豆识别(Pytorch)
    浏览器运行机制
    免费的在线白板协作工具有哪些?
    Spring Boot对接RocketMQ示例
    如何实时计算日累计逐单资金流
    数据库治理利器:动态读写分离
    GPO:在 Start/Logon 中使用 PowerShell 脚本
    c++day5
  • 原文地址:https://blog.csdn.net/huang987246510/article/details/133684028