7-Mode Snapmirror Status and SnapVault Status -L Parser

This script can be used to parse either the “SnapMirror-Status” or “SnapVault-Status-L” files from AutoSupport. You might want to do this if you’re curious to know the transfer rate of your relations. One special feature, is that it uses computational mathematics to work out a transfer rate as if the SnapMirror/SnapVault wasn’t contending with other SnapMirrors/SnapVaults - i.e. was running independent and not concurrent with other jobs (where jobs conflict of course) - this metric is called “Transfer Rate Adjusted” or “T.Rate Adj” for short, and the script also works out the average and median of these values too. The output is a CSV.

Will be surprised if this script gets much use, but the code is possibly interesting.

########################
## SM_SV_analysis.ps1 ##
########################
# This tool is designed to analyze the following files from 7-Mode ASUPs:
# SNAPMIRROR-STATUS
# SNAPVAULT-STATUS-L

Param([parameter(Mandatory=$true)][String]$FileIn)
If(!(Test-Path $FileIn)){ Write-Host "Unable to find $FileIn"; EXIT}

## PROCESS THE SM/SV STATUS ##

$SVstatus = Get-Content $FileIn
[System.Object]$SVdata = @{}
[Boolean]$Recording = $FALSE
$Count = 0
[System.Array]$Starts = @()

$SVstatus | foreach {
  If($_.StartsWith("Source")){
    $Recording = $TRUE
    $Count++
    [System.Object]$SVdata.$Count = @{}
    [String]$Source = $_.Split(":")[1].Trim(" ","`t") + ":" + $_.Split(":")[2].Trim(" ","`t")
  }
  If($Recording){
    If($_.StartsWith("Destination")){
      [String]$Destination = $_.Split(":")[1].Trim(" ","`t") + ":" + $_.Split(":")[2].Trim(" ","`t")
    }
    If($_.StartsWith("Status")){ ## Drop if not idle at time of SM/SV status
      If( !($_ -Match ("Idle")) ){ $Recording = $FALSE; $Count--; Write-Host "DETECTED STATUS NOT IDLE!" }
    }
    If($_.StartsWith("Lag")){
      If($_ -Match ("-")){ ## Drop if Lag is "-"
        $Recording = $FALSE; $Count--; Write-Host 'DETECTED LAG = "-"'
      } else{
        [Int]$Hours   = [Int]($_.Split(":")[1].Trim(" ","`t"))
        [Int]$Minutes = [Int]($_.Split(":")[2].Trim(" ","`t"))
        [Int]$Seconds = [Int]($_.Split(":")[3].Trim(" ","`t"))
        [Int]$Lag     = $Seconds + (60*$Minutes) + (60*60*$Hours)
      }
    }
    If($_.StartsWith("Mirror Timestamp")){
      [String]$MirrorTS = $_.Substring(17).Trim(" ","`t")           
    }
    If($_.StartsWith("Last Transfer Size")){                 
      [Int]$Size  = [Int]($_.Split(":")[1].Trim(" ","`t").Split(" ")[0])
    }
    If($_.StartsWith("Last Transfer Duration")){
      [Int]$Hours    = [Int]($_.Split(":")[1].Trim(" ","`t"))
      [Int]$Minutes  = [Int]($_.Split(":")[2].Trim(" ","`t"))
      [Int]$Seconds  = [Int]($_.Split(":")[3].Trim(" ","`t"))
      [Int]$Duration = $Seconds + (60*$Minutes) + (60*60*$Hours)
      [Int]$StartSecond = $Lag + $Duration
      If($Duration -ne 0){ [Double]$TRate    = ($Size/$Duration) } else { [Double]$TRate = 0 }
      [String]$SVdata.$Count.Source      = $Source
      [String]$SVdata.$Count.Destination = $Destination
      [String]$SVdata.$Count.MirrorTS    = $MirrorTS
      [Int]$SVdata.$Count.Start          = $StartSecond
      [Int]$SVdata.$Count.Duration       = $Duration
      [Int]$SVdata.$Count.Size           = $Size
      [Double]$SVdata.$Count.TRate       = $TRate                   
      $Starts += $StartSecond
    }
  }
  If($_.StartsWith("Last Transfer From")){ $Recording = $FALSE }
}
[System.Array]$Starts = $Starts | Sort-Object -Descending

## WORK OUT NUMBER OF TRANSFERS RUNNING AT SECOND %J ##

[Int]$MaxGoBack = 7 * 24 * 60 * 60 ## Go back no longer than 7 days
[System.Object]$RunningTs = @{} ## Running Transfers per second
Write-Host "Processing $Count items for transfers running at second X ... "
For($i=1; $i -le $Count; $i++){
  Write-Host "$i " -NoNewLine
  [Int]$Start = $SVdata.$i.Start
  If($Start -le $MaxGoBack){
    [Int]$End = $Start - $SVdata.$i.Duration
    For($j = $Start; $j -gt $End; $j--){
      If(!$RunningTs.$j){ [Int]$RunningTs.$j = 0 }
      $RunningTs.$j ++ ## Recording number of transfers running at second $j
    }
  }
}; Write-Host; Write-Host

## WORK OUT AN ADJUSTED TRANSTER RATE FOR IF THE TRANSFER WAS RUNNING ALONE ##

Write-Host "Processing $Count items for adjusted Transfer Rate ... "
For($i=1; $i -le $Count; $i++){
  Write-Host "$i " -NoNewLine
  [Double]$UnitDenominator = 0
  [Int]$Start = $SVdata.$i.Start
  If($Start -le $MaxGoBack){
    [Int]$End = $Start - $SVdata.$i.Duration
    For($j = $Start; $j -gt $End; $j--){
      $UnitDenominator += 1 / $RunningTs.$j
    }        
  }
  If($UnitDenominator -ne 0){ [Double]$TRateAdj = $SVdata.$i.Size / $UnitDenominator } else { [Double]$TRateAdj = 0 }
  [Double]$SVdata.$i.TRateAdj = $TRateAdj
}; Write-Host; Write-Host

## GENERATE OUTPUT ##

[System.Array]$AllTRateAdj = @()
[System.Array]$Output = "Start (s),Size (KB),Duration (s),T.Rate (KB/s),T.Rate Adj (KB/s),Mirror Timestamp,Source,Destination"
$Starts | Foreach {
  For($i=1;$i -le $Count;$i++){
    If($SVdata.$i.Start -eq $_){
      If($SVdata.$i.TRateAdj -ne 0){ $AllTRateAdj += $SVdata.$i.TRateAdj }
      $Output += ([String]$_ + "," + [String]$SVdata.$i.Size + "," + [String]$SVdata.$i.Duration + "," + [String]$SVdata.$i.TRate + "," + [String]$SVdata.$i.TRateAdj + "," + $SVdata.$i.MirrorTS + "," + $SVdata.$i.Source + "," + $SVdata.$i.Destination)
    } 
  }
}

## FIND THE AVERAGEand MEDIAN OF of T.Rate Adj ##

$Average = ($AllTRateAdj | measure -average).Average
$AllTRateAdj = $AllTRateAdj | sort
If ($AllTRateAdj.count%2) { $MedianValue = $AllTRateAdj[[math]::Floor($AllTRateAdj.count/2)] } # ODD
else { $MedianValue = ($AllTRateAdj[$AllTRateAdj.Count/2],$AllTRateAdj[$AllTRateAdj.count/2-1] |measure -Average).average }
Write-Host ("Transfer Rate Adjusted (KB/s) Average = " + [String]$Average)
Write-Host ("Transfer Rate Adjusted (KB/s) Median = " + [String]$MedianValue)
$Output += (",,,AVERAGE =," + [String]$Average)
$Output += (",,,MEDIAN =," + [String]$MedianValue)

## OUTPUT TO CSV ##

$Output | Out-File ($FileIn + ".CSV") -Encoding Default
Write-Host ("Output file $FileIn" + ".CSV created!"); Write-Host

## THE END ##


Comments