function p4top {param([string]$sortBy = "time",[switch]$nice) $servercheck = p4get-server #retrieve state of if ($servercheck.pingsuccess.equals($true)) { clear-host #clear screen first thing so we have a nice presentation surface $whitespace = " " #terrible hacky way of making the text appear cleaner. 100 characters of space bar. $consoleCharCount = 0 #init the console character count. This is used to clean the screen of debris occasionally. $maxOpsTime = 3 #maximum ops time in seconds before an operation is flagged as being "long" and operation is flagged with a solid color. $bg = $host.ui.rawui.backgroundcolor #save the original background color $fg = $host.ui.rawui.foregroundcolor #save the original foreground color $i=0 #init elapsed time counter $averageQuery=0 #init the average query counter $consoleLastCharCount = 0 #init the console character count. This is used to clear the screen occasionally of debris. $swLoop = [Diagnostics.Stopwatch]::StartNew() #start the average query stopwatch $swTotal = [Diagnostics.Stopwatch]::StartNew() #start the total elapsed time run stopwatch $p4ServerInfo = unchunk-psobject (p4get info) #get information from perforce session. This is used to identify what user is running the monitor query (and remove from the list) and identify the server in the display ui. $columnsArray = @() #init the display array for the data columns. We display as an array so the total character count can be stored. $columnsArray += @{time="Time";status="S";command="Command";user="User";id="ID";client="Client";prog="Program"} #hash array displaying the names of the commands $columnsArray += @{time="----";status="-";command="-------";user="----";id="--";client="------";prog="-------"} #hash array referenced the same to make underscores. while ($true) #infinite loop of the main program. { if ($Host.UI.RawUI.KeyAvailable -and ("q" -eq $Host.UI.RawUI.ReadKey("IncludeKeyUp,NoEcho").Character)) #how we exit from infinite loop. Q exits. { Write-Host "Stopping." -Background DarkRed #note that we are stopping $host.ui.rawui.foregroundcolor = $fg #reset foreground to original $host.ui.rawui.backgroundcolor = $bg #reset background to original clear-host break; #break from infiniloop. } if ((($consoleCharCount - $consoleLastCharCount)/100) -gt 90000) #die if for some reason the console character count math is out of bounds. { throw "Console character count out of bounds!" } $wipe = 0 While ($wipe -le (($consoleCharCount - $consoleLastCharCount)/10)) { $whitespace $wipe++ } $consoleLastCharCount = $consoleCharCount #clear the console last char count. if ($nice) #if we select nicing the process, we only query one time a second. { sleep 1 } $headerArray = @() #init the header array (the part about the warning and the server, qps, elapsed, etc) $contentArray = @() #init the content array $result = $null #clear result after every loop. Result is the monitor results from p4. PutCursor #put the cursor to 0,0. $result = p4get-monitor | ?{$_.user -ne $p4ServerInfo.userName} #query the perforce server for the process monitor. Remove the monitor entry from ourselves. We still want to see others monitoring so we strip out the username. Subject to change without notice. :) $perfMetrics = @{Server = ("Server:[" + $p4ServerInfo.serverAddress + "]");Sorting = ("Sorting:[" + $sortBy + "]");QPS = ("QueriesPerSecond:["+ $avergeQuery +"]");ET = ("ElapsedTime:[" + ("{0:N2}" -f $swTotal.Elapsed.TotalSeconds) + "]")} $host.ui.rawui.foregroundcolor = "white" #set foreground to white. $headerArray += "WARNING: This tool consumes resources on the targeted Perforce Server. Press Q exit." $headerArray += $perfMetrics | %{ '{0,15} {1,20} {2,19} {3,48}' -f $_.Sorting,$_.QPS,$_.ET,$_.Server } $headerArray += $columnsArray | %{ '{0,5} {1,1} {2,10} {3,20} {4,7} {5,30} {6,25}' -f $_.time,$_.status,$_.command,$_.user,$_.id,$_.client,$_.prog } #format the column display text and store in header. $host.ui.rawui.foregroundcolor = "yellow" $host.ui.rawui.backgroundcolor = "darkred" $headerArray[0] #print the warning label $host.ui.rawui.foregroundcolor = $fg $host.ui.rawui.backgroundcolor = $bg $headerArray[1] $headerArray[2] #print the status header row $headerArray[3] #print the status header row lines foreach ($process in ($result|sort-object -descending -property $sortBy)) #iterate through each monitor object returned from p4. { #trim some long strings so it fits in the grid. if ($process.prog.length -gt 24) { $process.prog = $process.prog.Remove(24) + "+" } if ($process.client.length -gt 29) { $process.client = $process.client.Remove(29) + "+" } if ($process.user.length -gt 19) { $process.user = $process.user.Remove(19) + "+" } #case statement coloring switch ($process.command) #case switch for objects. This is used to perform console color coding on each type of operation. { fstat { $host.ui.rawui.foregroundcolor = "red" if ($process.time.TotalSeconds -gt $maxOpsTime) #if the maxopstime is exceeded, highlight this process. { $host.ui.rawui.foregroundcolor = "black" $host.ui.rawui.backgroundcolor = "darkRed" } } sync { $host.ui.rawui.foregroundcolor = "blue" if ($process.time.TotalSeconds -gt $maxOpsTime) #if the maxopstime is exceeded, highlight this process. { $host.ui.rawui.foregroundcolor = "black" $host.ui.rawui.backgroundcolor = "blue" } } where { $host.ui.rawui.foregroundcolor = "green" if ($process.time.TotalSeconds -gt $maxOpsTime) #if the maxopstime is exceeded, highlight this process. { $host.ui.rawui.foregroundcolor = "black" $host.ui.rawui.backgroundcolor = "green" } } revert { $host.ui.rawui.foregroundcolor = "yellow" if ($process.time.TotalSeconds -gt $maxOpsTime) #if the maxopstime is exceeded, highlight this process. { $host.ui.rawui.foregroundcolor = "black" $host.ui.rawui.backgroundcolor = "yellow" } } edit { $host.ui.rawui.foregroundcolor = "magenta" if ($process.time.TotalSeconds -gt $maxOpsTime) #if the maxopstime is exceeded, highlight this process. { $host.ui.rawui.foregroundcolor = "black" $host.ui.rawui.backgroundcolor = "magenta" } } submit { $host.ui.rawui.foregroundcolor = "cyan" if ($process.time.TotalSeconds -gt $maxOpsTime) #if the maxopstime is exceeded, highlight this process. { $host.ui.rawui.foregroundcolor = "black" $host.ui.rawui.backgroundcolor = "cyan" } } dm-CommitSubmit { $host.ui.rawui.foregroundcolor = "cyan" if ($process.time.TotalSeconds -gt $maxOpsTime) #if the maxopstime is exceeded, highlight this process. { $host.ui.rawui.foregroundcolor = "black" $host.ui.rawui.backgroundcolor = "cyan" } } } $process | %{ '{0,5} {1,1} {2,10} {3,20} {4,7} {5,30} {6,25}' -f $_.time.TotalSeconds,$_.status,$_.command,$_.user,$_.id,$_.client,$_.prog } #print the process with the nice formatting. (format-table has various issues so we have to do it manually) $contentArray += $process | %{ '{0,5} {1,1} {2,10} {3,20} {4,7} {5,30} {6,25}' -f $_.time.TotalSeconds,$_.status,$_.command,$_.user,$_.id,$_.client,$_.prog } #add to counting array. Note that this array isn't actually displayed, it's just for counting up to perform console cleaning. $host.ui.rawui.foregroundcolor = $fg #set the color up for the next screen paint $host.ui.rawui.backgroundcolor = $bg #set the color up for the next screen paint [int]$consoleCharCount = ($headerArray | out-string).length + ($contentArray | out-string).length #do some math to figure out how many characters were written to the screen. if ($swLoop.elapsed.totalSeconds -ge 1) #poll results from the average query stopwatch. we are counting queries per second. { $avergeQuery=$i #averagequery is then stored for the next pass in the statistics header. $swLoop.Restart() #reset the stopwatch back to zero. $i=0 #reset the query counter back to zero, and we'll wait for the next full second to elapse before doing this again. } } $i++ } } }