VMware Cloud Community
nicmac
Contributor
Contributor
Jump to solution

Get-stat cpu.avg.usage -- Define time window over a month

Is it possible to retrieve cpu stats for a peak time period per day over a month?

For example, I have VMs that are under peak load from 10am to 11pm every Monday through Friday, but do not experience significant load outside of those hours and not on the weekends. This seems very complicated to me and I'm unable to wrap my head around it.

I have tried setting the start and finish values to those specific times, which will work find for one day.

0 Kudos
1 Solution

Accepted Solutions
LucD
Leadership
Leadership
Jump to solution

Yes, that is the way to do it, you can include whatever you want in the loop.

Just add the properties to the object you create inside the loop.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

View solution in original post

0 Kudos
12 Replies
LucD
Leadership
Leadership
Jump to solution

You will have to filter the returned metrics.

There is an example in my PowerCLI & vSphere statistics – Part 2 – Come together post.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

Thanks, that was very helpful!

I have been trying to figure out how to combine statistics from different get-stat commands into one table, and one of Alan's scripts showed me the trick with using select and @{N="";E={}}. Is there a way to use groupings to pull multiple stats out of one get-stat using this method? Basically, I have this so far...

$todayMidnight = (Get-Date -Hour 0 -Minute 0 -Second 0).AddMinutes(-1)

$workingDays = "Monday","Tuesday","Wednesday","Thursday","Friday"

$dayStart = New-Object DateTime(1,1,1,9,0,0) 

$dayEnd = New-Object DateTime(1,1,1,23,59,0)

Get-VM $vm | Where {$_.PowerState -eq "PoweredOn"} |

Select Name, Host, NumCpu, MemoryMB, `

@{N="avgCPU%-20D";E={[Math]::Round((($_ | `

Get-Stat -Stat cpu.usage.average -Start $todayMidnight.AddDays(-20) -Finish $todayMidnight.AddDays(-1) | `

Where-Object {

  $workingDays -contains $_.Timestamp.DayOfWeek -and $_.Timestamp.TimeOfDay -gt $dayStart.TimeOfDay -and $_.Timestamp.TimeOfDay -lt $dayEnd.TimeOfDay} | `

  Measure-Object value -Average).average),2)}}, `

@{N="avgCPUmhz-20D";E={[Math]::Round((($_ | `

Get-Stat -Stat cpu.usagemhz.average -Start $todayMidnight.AddDays(-20) -Finish $todayMidnight.AddDays(-1) | `

Where-Object {

  $workingDays -contains $_.Timestamp.DayOfWeek -and $_.Timestamp.TimeOfDay -gt $dayStart.TimeOfDay -and $_.Timestamp.TimeOfDay -lt $dayEnd.TimeOfDay} | `

  Measure-Object value -Average).average),2)}} `

That will return this:

Name          : <vmname>

Host          : <hostname>

NumCpu        : 2

MemoryMB      : 8192

avgCPU%-20D   : 5.41

avgCPUmhz-20D : 237.12

First of all, are these averages likely accurate?

Second, I would like to also gather the max cpu % and mhz similarly to this command. Is it possible to do pull these values out using a similar "select" trick? I'm not sure if I would use group-object/new-object here or not.

get-stat -entity $vm -stat $metric -start $start.AddDays(-30) -finish $finish.AddDays(-1) | `

group-object -property entity | %{new-object PsObject -property @{

VMname = $_.Values[0]

"AvgCPU%" = [Math]::Round(($_.Group | `

measure-object -property value -average).average,1)

"MaxCPU%" = [Math]::Round(($_.Group | `

measure-object -property value -maximum).maximum,1)

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

I found this script in another post which was very helpful. I basically want to combine this information with static statistics like vCPU count and memory allocation to compare side by side.

$allvms = @()
$vms = Get-Vm
$start = (Get-Date).AddDays(-7)
$metrics = "cpu.usage.average","mem.usage.average"
$stats = Get-Stat -Entity $vms -Start $start -Stat $metrics  
$stats | Group-Object -Property {$_.Timestamp.Day},{$_.Entity.Name} | %{
 
$vmstat = "" | Select VmName, Day, MemMax, MemAvg, MemMin, CPUMax, CPUAvg, CPUMin
  $vmstat.VmName = $_.Values[1]
 
$vmstat.Day = $_.Group[0].Timestamp.Date
 
$cpu = $_.Group | where {$_.MetricId -eq "cpu.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum
 
$mem = $_.Group | where {$_.MetricId -eq "mem.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum
 
$vmstat.CPUMax = [int]$cpu.Maximum
  $vmstat.CPUAvg = [int]$cpu.Average
  $vmstat.CPUMin = [int]$cpu.Minimum
 
$vmstat.MemMax = [int]$mem.Maximum
  $vmstat.MemAvg = [int]$mem.Average
 
$vmstat.MemMin = [int]$mem.Minimum 
 
$allvms += $vmstat
}
$allvms

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

Ah, I think I got it now. I didn't realize I could just pile stuff into $vmstat from $vms, unless I'm missing something.

$allvms = @()

$vms = Get-Vm $vm

$stats = Get-Stat -Entity $vms -start (get-date).AddDays(-20) -Finish (Get-Date)-MaxSamples 10000 `

  -stat "cpu.usage.average", "cpu.usagemhz.average", "mem.usage.average", "cpu.ready.summation", "cpu.idle.summation", "cpu.costop.summation"

$stats | Group-Object -Property Entity | %{

  $vmstat = "" | Select VmName, vCPU, MemMB, "MemMax%", "MemAvg%", "MemMin%", "CPUMax%", "CPUAvg%", "CPUMin%", CPUMaxMhz, CPUAvgMhz, CPUMinMhz, `

  "CPURdyMax%", "CPURdyAvg%", "CPURdyMin%", "CPUctspMax%", "CPUctspAvg%"

  $vmstat.VmName = $_.name

  $cpu = $_.Group | where {$_.MetricId -eq "cpu.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum

  $cpuMhz = $_.Group | where {$_.MetricId -eq "cpu.usagemhz.average"} | Measure-Object -Property value -Average -Maximum -Minimum

  $mem = $_.Group | where {$_.MetricId -eq "mem.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum

  $cpuRdy = $_.Group | where {$_.MetricId -eq "cpu.ready.summation"}| Measure-Object -Property value -Average -Maximum -Minimum

  $cpuCtsp = $_.Group | where {$_.MetricId -eq "cpu.costop.summation"}| Measure-Object -Property value -Average -Maximum -Minimum

 

  $vmstat.vCPU = $vms.NumCPU

  $vmstat.MemMB = $vms.MemoryMB

  $vmstat.CPUMaxMhz = [int]$cpuMhz.Maximum

  $vmstat.CPUAvgMhz = [int]$cpuMhz.Average

  $vmstat.CPUMinMhz = [int]$cpuMhz.Minimum

  $vmstat."CPUMax%" = [int]$cpu.Maximum

  $vmstat."CPUAvg%" = [int]$cpu.Average

  $vmstat."CPUMin%" = [int]$cpu.Minimum

  $vmstat."CPURdyMax%" = [Math]::ROUND(($cpuRdy.Maximum/72000),2)

  $vmstat."CPURdyAvg%" = [Math]::ROUND(($cpuRdy.Average/72000),2)

  $vmstat."CPURdyMin%" = [Math]::ROUND(($cpuRdy.Minimum/72000),2)

  $vmstat."CPUctspMax%" = [Math]::ROUND(($cpuCtsp.Maximum/72000),2)

  $vmstat."CPUctspAvg%" = [Math]::ROUND(($cpuCtsp.Average/72000),2)

  $vmstat."MemMax%" = [int]$mem.Maximum

  $vmstat."MemAvg%" = [int]$mem.Average

  $vmstat."MemMin%" = [int]$mem.Minimum 

  $allvms += $vmstat

}

$allvms | Select VmName, vCPU, MemMB, "CPUMax%", "CPUAvg%", "CPUMin%", CPUMaxMHZ, CPUAvgMHZ, CPUMinMHZ, "MemMax%", "MemAvg%", "MemMin%", "CPURdyMax%", `

  "CPURdyAvg%", "CPURdyMin%", "CPUctspMax%", "CPUctspAvg%"

That returns:

VmName      : vmserver

vCPU        : 2

MemMB       : 8192

CPUMax%     : 38

CPUAvg%     : 4

CPUMin%     : 2

CPUMaxMhz   : 1654

CPUAvgMhz   : 192

CPUMinMhz   : 87

MemMax%     : 16

MemAvg%     : 5

MemMin%     : 3

CPURdyMax%  : 2.82

CPURdyAvg%  : 1.22

CPURdyMin%  : 0.7

CPUctspMax% : 0.01

CPUctspAvg% : 0

I hope this works, anyway. Will try against some clusters.

0 Kudos
LucD
Leadership
Leadership
Jump to solution

Yes, that is the way to do it, you can include whatever you want in the loop.

Just add the properties to the object you create inside the loop.


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

I am very close. Why can't I call properties from an array of VMs? This command shows them as available: "Get-VM -Location cluster01 | gm," but when I set that to a variable I cannot call them.

PS C:\_tools\vmware\scripts> $vms=Get-VM -Location cluster01

PS C:\_tools\vmware\scripts> $vms.Host

PS C:\_tools\vmware\scripts> Get-VM -Location lvg01-cluster02-intel | select host

Host

----

host01

host02

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

Ah, I see that I have to call the array members with brackets. Trying to find what the wildcard is to handle them all.

$vms[0].Host will return the first result, etc.

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

Looks like this is the way...

$vms | %{$_.numcpu}

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

Argh. This still does not work of course because it adds the entire $vms array of elements to a single $vmstat.vCPU element. What is the proper way to join elements like this?

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

Ok, I think I have it. This is not an easy task. I had to use PsCustomObject and a hash table to marry the stats. I've run this against 12 clusters and the data looks great.

##Usage: Use "connect-viserver <vcenter/esxhost>" first.

##Enter either one VM OR one Clustername.

##

#Get variable for single VM or arrary for all VMs in a cluster. Comment out to test with line 14.

Write-Host "Choose one: VM or Cluster name"

$readVM= Read-Host "Enter VM name [blank]"

$readClus= Read-Host "Enter Cluster name [blank]"

if ($readVM -ne "") {$vms=Get-VM -Name $readVM | Where {$_.PowerState -eq "PoweredOn"}}

  else {$vms=Get-VM -Location $readClus | Where {$_.PowerState -eq "PoweredOn"}}

#$vms = Get-VM | select -First 5 #Test

#Object to populate with stats elements.

$allmetrics = @()

#Set variables for peak load hours and days.

$todayMidnight = (Get-Date -Hour 0 -Minute 0 -Second 0).AddMinutes(-1) #Change start of day to midnight.

$workingDays = "Monday","Tuesday","Wednesday","Thursday","Friday"

$dayStart = New-Object DateTime(1,1,1,9,0,0)     # 9:00 AM

$dayEnd = New-Object DateTime(1,1,1,23,59,0)      # 11:59 PM

#Set variable for metrics found in get-stattype

$metrics="cpu.usage.average", "cpu.usagemhz.average", "mem.usage.average", `

  "cpu.ready.summation", "cpu.idle.summation", "cpu.costop.summation"

#Store desired metrics

$stats = Get-Stat -Entity $vms -start $todayMidnight.AddDays(-20) -Finish $todayMidnight.AddDays(-1) -MaxSamples 10000 `

  -stat $metrics

#Filter stats for peak hours

$stats | Where-Object {

  $workingDays -contains $_.Timestamp.DayOfWeek -and

  $_.Timestamp.TimeOfDay -gt $dayStart.TimeOfDay -and

  $_.Timestamp.TimeOfDay -lt $dayEnd.TimeOfDay} | `

#Put array of filtered stats on to pipeline and declare custom stats group object with desired field names

  Group-Object -Property Entity | %{

  $vmstat = "" | Select Name, "MemMax%", "MemAvg%", "MemMin%", "CPUMax%", "CPUAvg%", "CPUMin%", CPUMaxMhz, CPUAvgMhz, CPUMinMhz, `

  "CPURdyMax%", "CPURdyAvg%", "CPURdyMin%", "CPUctspMax%", "CPUctspAvg%"

#Define metrics arrays for various metric types with various value types

  $cpu = $_.Group | where {$_.MetricId -eq "cpu.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum

  $cpuMhz = $_.Group | where {$_.MetricId -eq "cpu.usagemhz.average"} | Measure-Object -Property value -Average -Maximum -Minimum

  $mem = $_.Group | where {$_.MetricId -eq "mem.usage.average"} | Measure-Object -Property value -Average -Maximum -Minimum

  $cpuRdy = $_.Group | where {$_.MetricId -eq "cpu.ready.summation"}| Measure-Object -Property value -Average -Maximum -Minimum

  $cpuCtsp = $_.Group | where {$_.MetricId -eq "cpu.costop.summation"}| Measure-Object -Property value -Average -Maximum -Minimum

#Define properties based on desired field names in custom stats object with input from stats arrays.

  $vmstat.Name = $_.name

  $vmstat.CPUMaxMhz = [int]$cpuMhz.Maximum

  $vmstat.CPUAvgMhz = [int]$cpuMhz.Average

  $vmstat.CPUMinMhz = [int]$cpuMhz.Minimum

  $vmstat."CPUMax%" = [int]$cpu.Maximum

  $vmstat."CPUAvg%" = [int]$cpu.Average

  $vmstat."CPUMin%" = [int]$cpu.Minimum

  $vmstat."CPURdyMax%" = [Math]::ROUND(($cpuRdy.Maximum/72000),2) #Calculation based on 2 hour sample size. Rounnd 2 decimal places.

  $vmstat."CPURdyAvg%" = [Math]::ROUND(($cpuRdy.Average/72000),2)

  $vmstat."CPURdyMin%" = [Math]::ROUND(($cpuRdy.Minimum/72000),2)

  $vmstat."CPUctspMax%" = [Math]::ROUND(($cpuCtsp.Maximum/72000),2)

  $vmstat."CPUctspAvg%" = [Math]::ROUND(($cpuCtsp.Average/72000),2)

  $vmstat."MemMax%" = [int]$mem.Maximum

  $vmstat."MemAvg%" = [int]$mem.Average

  $vmstat."MemMin%" = [int]$mem.Minimum

  #Append all properties to primary object

  $allmetrics += $vmstat

}

#Get vminfo

$vminfo = $vms | select Name, VMHost, NumCpu, MemoryMB, `

@{N="Cluster";E={get-cluster -vmhost $_.vmhost}},

@{N="Datastores";E={$_|Get-Datastore}}

#Set date for csv output.

$date=get-date -uformat %m-%d-%Y

#Add all values to hash table and join them

$allvalues = @{}

$vminfo | ForEach-Object { $allvalues.Add($_.Name, $_) }

$allmetrics | ForEach-Object {

  [PsCustomObject]@{

  Name = $allvalues[$_.Name].Name;

  VMHost = $allvalues[$_.Name].VMhost;

  NumCpu = $allvalues[$_.Name].NumCpu;

  MemoryMB = $allvalues[$_.Name].MemoryMB;

  Cluster = $allvalues[$_.Name].Cluster;

  Datastores = $allvalues[$_.Name].Datastores;

  "CPUMax%" = $_."CPUMax%";

  "CPUAvg%" = $_."CPUAvg%";

  "CPUMin%" = $_."CPUMin%";

  CPUMaxMHZ = $_.CPUMaxMHZ;

  CPUAvgMHZ = $_.CPUAvgMHZ;

  CPUMinMHZ = $_.CPUMinMHZ;

  "MemMax%" = $_."MemMax%";

  "MemAvg%" = $_."MemAvg%";

  "MemMin%" = $_."MemMin%";

  "CPURdyMax%" = $_."CPURdyMax%";

  "CPURdyAvg%" = $_."CPURdyAvg%";

  "CPURdyMin%" = $_."CPURdyMin%";

  "CPUctspMax%" = $_."CPUctspMax%";

  "CPUctspAvg%" = $_."CPUctspAvg%";

  }

} | `

#Export to CSV file.

Export-Csv .\vmstats.extended.20days.$readVM$readClus.$date.csv -NoTypeInformation -UseCulture

#Open CSV document when complete.

Invoke-item .\vmstats.extended.20days.$readVM$readClus.$date.csv

0 Kudos
LucD
Leadership
Leadership
Jump to solution

That works, great.

But isn't this a bit too circumstantial ?

You can get the cluster and datastore info for a VM inside the Group-Object loop as well ?


Blog: lucd.info  Twitter: @LucD22  Co-author PowerCLI Reference

0 Kudos
nicmac
Contributor
Contributor
Jump to solution

Haha, I had to use my own brain on this one so it's definitely pretty sloppy! :smileysilly:

I always forget why I like POSH until I remember why it's not like other scripting languages.

Did you ever get a chance to take a look at PASH? We talked about it for a few minutes at VMworld this year. It looks like the latest update was in April...

pash | Free System Administration software downloads at SourceForge.net

0 Kudos