Get Hyper-V VM IOPS statistics


If you enabled VMResourceMetering, you can view statistics about those :

Get-VM | Measure-VM

If you have a look at this with Get-Member, you’ll see a lot more properties :


So, if you want to focus on IOPS, you can use :

Get-VM | Measure-VM | select VMName,
    @{Label='TotalIO';Expression = {$_.AggregatedDiskDataRead + $_.AggregatedDiskDataWritten}},
    @{Label='%Read';Expression={"{0:P2}" -f ($_.AggregatedDiskDataRead/($_.AggregatedDiskDataRead + $_.AggregatedDiskDataWritten))}},
    @{Label='%Write';Expression={"{0:P2}" -f ($_.AggregatedDiskDataWritten/($_.AggregatedDiskDataRead + $_.AggregatedDiskDataWritten))}},
    @{Label='TotalIOPS';Expression = {"{0:N2}" -f (($_.AggregatedDiskDataRead + $_.AggregatedDiskDataWritten)/$_.MeteringDuration.Seconds)}}


This can be useful if you want to setup some QoS on storage, or if you have to find the VM’s that is causing storage performances issues !



0 thoughts on “Get Hyper-V VM IOPS statistics

  1. I read that MeteringDuration was only the last 20 secondes whereas AggregatedDiskData is a sum so what about this :
    – TotalIO= AggregatedDiskDataRead+AggregatedDiskWritten
    – TimeDuration = time (secondes) between Enable-VMResourceMetering and measure-vm
    – averageIOPS = TotalIO / TimeDuration
    – VM_IOPS = (averageIOPS* %Read) + (averageIOPS * %Write * RAID_Penalty)

    • Stef, \”AggregatedAverageNormalizedIOPS\” is based on last 20 seconds, but \”AggregatedDiskDataRead\” and \”AggregatedDiskDataWritten\” is the sum from last Reset-VMResourceMetering.
      The property \”MeteringDuration\” is the TimeSpan since last reset.
      So, if i sum up \”AggregatedDiskDataRead\” and \”AggregatedDiskDataWritten\”, then divide by the number of seconds since last metering reset, I got an average based on the total metering timespan, no ?

      Source : (Hyper-V MVP)

      • Yes, I have seen this link but I think that\’s it\’s ok if you take mesure over a short period but if you take mesure for instance between 08h00 to 18h, it\’s better to divide par the average on the period (10hours*3600sec) rather than AggregatedAverageNormalizedIOPS because this mesure will be take at 18h00 and will not be representive for the day (it will be lower because less people work at 18h)

        • Have an other look at the formula. I am addind read and write IO, and then divide by the number of seconds since last reset ($_.MeteringDuration.seconds).
          I think we\’re saying the same thing ?

  2. you\’re right, effectively I try to use an other formula because my hyper-v cluster didn\’t give me this information : MeteringDuration is blank while the other data are displayed. So I used AggregatedAverageNormalizedIOPS but you don\’t tell about this, it\’s a mistake. I will try again with this formula to mesure IOPS.

    But for a VM I find on Internet that we have to complete it with this formula :
    VM_IOPS = (TotalIOPS * %Read) + (TotalIOPS * %Write * RAID_Penalty)
    %Read = ReadIOPS/TotalIOPS
    %Write = WriteIOPS/TotalIOPS
    RAID_Penalty = 2 (RAID 10) or 4 (RAID50)
    and TotalIOPS with your formula 🙂

    • If you use Hyper-V metrics, you don\’t need to calculate RAID Penalty. You need to use that when you are desining a storage infrastructure. Indeed, Hyper-V displays real IO handled by the storage array, but hardware vendor tells about single disk performances, so, when you aggregate them in a RAID, you need to know what performances you\’ll loose (RAID Penalty) in profit of data resiliency.

      You can use this too :
      Get-VM | Measure-VM | select VMName,
      @{Label=\’TotalIO\’;Expression = {$_.AggregatedDiskDataRead + $_.AggregatedDiskDataWritten}},
      @{Label=\’%Read\’;Expression={\”{0:P2}\” -f ($_.AggregatedDiskDataRead/($_.AggregatedDiskDataRead + $_.AggregatedDiskDataWritten))}},
      @{Label=\’%Write\’;Expression={\”{0:P2}\” -f ($_.AggregatedDiskDataWritten/($_.AggregatedDiskDataRead + $_.AggregatedDiskDataWritten))}},
      @{Label=\’TotalIOPS\’;Expression = {\”{0:N2}\” -f (($_.AggregatedDiskDataRead + $_.AggregatedDiskDataWritten)/$_.MeteringDuration.Seconds)}},
      @{Label=\’IOPS (Last 20s)\’;Expression={$_.AggregatedAverageNormalizedIOPS}}

      • GREAT !!!
        En fact, I have performance probleme with my storage (SAN with 24 hdisk SAS 10K) an I try to calculate how many disks I should have to obtain better performances. I use hyper-v metric and perfmon metric and excel calculator with penalty so I have a lot of difficulty with measures that are between 1 disk and 35 disk 🙂

        If I understand your comment, if I try to calcultate my total IOs on my SAN, i will use \”Get-VM * | Measure-VM\” on my 2 hyper-v servers to measure IO, I divide byMeteringDuration and I sum the 2 measures (on each hyper-v) and I don\’t use read_penalty.
        OK but if i want to size my SAN, do i measure between a loaded period (10h-11h30 for instance) or during a low period (08h-10h) or during a day (08h-18h) considering hight IO (on 5 minutes for instance) are taken by cache ?
        When I have the period to take measure and if I considere that SAS 10 KE has 130 IOPS, then the number of disks needed is TotalIOPS/130 or do I have to consider raid-penalty ?

        thanks a lot for your help

        • If you\’re desining your SAN, you need to take care of RAID PENALTY when calculating the number of disks :
          TotalIOPS*Raid_Penalty/130, I think.

          You need to handle the worst case senario, so, you need to measure the needed IOPS when you have the heavier load on the workload. If you have only few peaks, please consider SSD caching. Windows Server 2012R2 offer that feature in SOFS for free.

  3. why my MeteringDuration is blank? I reset the metering and I get MeteringDuration but as soon as I ran a different command it goes back to being blank.

Leave a Reply