@@ -120,6 +120,135 @@ switch($Command.ToLowerInvariant()){
120120 if ($LASTEXITCODE -ne 0 ){ throw ' Trace conversion failed' }
121121 Write-Host " Trace complete: $traceFile " - ForegroundColor Green
122122 Write-Host " Speedscope file: $speedFile " - ForegroundColor Green
123+ # Auto-open speedscope view
124+ try {
125+ if (Get-Command npx - ErrorAction SilentlyContinue){
126+ Write-Host ' Opening speedscope (npx)...' - ForegroundColor Cyan
127+ & npx speedscope $speedFile
128+ } else {
129+ Write-Host ' npx not available; opening speedscope.app and folder.' - ForegroundColor Yellow
130+ Start-Process ' https://www.speedscope.app'
131+ Start-Process explorer.exe (Split-Path $speedFile - Parent)
132+ }
133+ } catch { Write-Host " Speedscope auto-open failed: $ ( $_.Exception.Message ) " - ForegroundColor Yellow }
134+ }
135+ ' trace-cpu' {
136+ Ensure- Tool ' dotnet-trace' ' dotnet-trace'
137+ $script :DotNetOnly = $true
138+ # Duration selection (interactive)
139+ $durationsMap = [ordered ]@ { ' 10 sec' = ' 00:00:10' ; ' 30 sec' = ' 00:00:30' ; ' 1 min' = ' 00:01:00' ; ' 5 min' = ' 00:05:00' }
140+ $duration = $durationsMap [' 10 sec' ]
141+ try {
142+ Import-Module PwshSpectreConsole - ErrorAction Stop
143+ $choice = Read-SpectreSelection - Title ' Select trace duration' - Choices ($durationsMap.Keys + ' Cancel' ) - EnableSearch - PageSize 10
144+ if ($choice -and $choice -ne ' Cancel' ){ $duration = $durationsMap [$choice ] }
145+ if ($choice -eq ' Cancel' ){ Write-Host ' CPU trace cancelled.' - ForegroundColor Yellow; break }
146+ } catch { Write-Host ' Spectre selection unavailable; using default 10 sec.' - ForegroundColor Yellow }
147+ $procId = Select-Pid ' Select process for CPU trace'
148+ if (-not $procId ){ Write-Host ' No PID selected.' - ForegroundColor Yellow; break }
149+ $outDir = Join-Path $PSScriptRoot ' ..' ' .tmp' ' diagnostics'
150+ New-Item - ItemType Directory - Force - Path $outDir | Out-Null
151+ $fileBase = " cpu_${procId} _$ ( Get-Date - Format ' yyyyMMdd_HHmmss' ) "
152+ $traceFile = Join-Path $outDir " $fileBase .nettrace"
153+ $speedFile = Join-Path $outDir " $fileBase .speedscope.json"
154+ Write-Host " Collecting CPU trace (SampleProfiler, $duration ) for PID $procId ..." - ForegroundColor Cyan
155+ & dotnet- trace collect -- process- id $procId -- providers Microsoft- DotNETCore- SampleProfiler:1 -- duration $duration - o $traceFile
156+ if ($LASTEXITCODE -ne 0 ){ throw ' CPU trace collection failed' }
157+ Write-Host ' Converting to speedscope...' - ForegroundColor Cyan
158+ & dotnet- trace convert -- format SpeedScope $traceFile - o $speedFile
159+ if ($LASTEXITCODE -ne 0 ){ throw ' CPU trace conversion failed' }
160+ Write-Host " CPU trace complete: $traceFile " - ForegroundColor Green
161+ Write-Host " Speedscope file: $speedFile " - ForegroundColor Green
162+ try {
163+ if (Get-Command npx - ErrorAction SilentlyContinue){
164+ Write-Host ' Opening speedscope (npx)...' - ForegroundColor Cyan
165+ & npx speedscope $speedFile
166+ } else {
167+ Write-Host ' npx not available; opening speedscope.app and folder.' - ForegroundColor Yellow
168+ Start-Process ' https://www.speedscope.app'
169+ Start-Process explorer.exe (Split-Path $speedFile - Parent)
170+ }
171+ } catch { Write-Host " Speedscope auto-open failed: $ ( $_.Exception.Message ) " - ForegroundColor Yellow }
172+ }
173+ ' trace-gc' {
174+ Ensure- Tool ' dotnet-trace' ' dotnet-trace'
175+ $script :DotNetOnly = $true
176+ # Duration selection (interactive)
177+ $durationsMap = [ordered ]@ { ' 10 sec' = ' 00:00:10' ; ' 30 sec' = ' 00:00:30' ; ' 1 min' = ' 00:01:00' ; ' 5 min' = ' 00:05:00' }
178+ $duration = $durationsMap [' 10 sec' ]
179+ try {
180+ Import-Module PwshSpectreConsole - ErrorAction Stop
181+ $choice = Read-SpectreSelection - Title ' Select GC trace duration' - Choices ($durationsMap.Keys + ' Cancel' ) - EnableSearch - PageSize 10
182+ if ($choice -and $choice -ne ' Cancel' ){ $duration = $durationsMap [$choice ] }
183+ if ($choice -eq ' Cancel' ){ Write-Host ' GC trace cancelled.' - ForegroundColor Yellow; break }
184+ } catch { Write-Host ' Spectre selection unavailable; using default 10 sec.' - ForegroundColor Yellow }
185+ $procId = Select-Pid ' Select process for GC-focused trace'
186+ if (-not $procId ){ Write-Host ' No PID selected.' - ForegroundColor Yellow; break }
187+ $outDir = Join-Path $PSScriptRoot ' ..' ' .tmp' ' diagnostics'
188+ New-Item - ItemType Directory - Force - Path $outDir | Out-Null
189+ $fileBase = " gc_${procId} _$ ( Get-Date - Format ' yyyyMMdd_HHmmss' ) "
190+ $traceFile = Join-Path $outDir " $fileBase .nettrace"
191+ $speedFile = Join-Path $outDir " $fileBase .speedscope.json"
192+ Write-Host " Collecting GC-focused trace (SampleProfiler + System.Runtime, $duration ) for PID $procId ..." - ForegroundColor Cyan
193+ & dotnet- trace collect -- process- id $procId -- providers Microsoft- DotNETCore- SampleProfiler:1 , System.Runtime:4 -- duration $duration - o $traceFile
194+ if ($LASTEXITCODE -ne 0 ){ throw ' GC trace collection failed' }
195+ Write-Host ' Converting to speedscope...' - ForegroundColor Cyan
196+ & dotnet- trace convert -- format SpeedScope $traceFile - o $speedFile
197+ if ($LASTEXITCODE -ne 0 ){ throw ' GC trace conversion failed' }
198+ Write-Host " GC trace complete: $traceFile " - ForegroundColor Green
199+ Write-Host " Speedscope file: $speedFile " - ForegroundColor Green
200+ try {
201+ if (Get-Command npx - ErrorAction SilentlyContinue){
202+ Write-Host ' Opening speedscope (npx)...' - ForegroundColor Cyan
203+ & npx speedscope $speedFile
204+ } else {
205+ Write-Host ' npx not available; opening speedscope.app and folder.' - ForegroundColor Yellow
206+ Start-Process ' https://www.speedscope.app'
207+ Start-Process explorer.exe (Split-Path $speedFile - Parent)
208+ }
209+ } catch { Write-Host " Speedscope auto-open failed: $ ( $_.Exception.Message ) " - ForegroundColor Yellow }
210+ }
211+ ' speedscope-view' {
212+ # Select a speedscope json file and open visualization
213+ $diagDir = Join-Path $PSScriptRoot ' ..' ' .tmp' ' diagnostics'
214+ if (-not (Test-Path $diagDir )){ Write-Host " Diagnostics directory not found: $diagDir " - ForegroundColor Yellow; break }
215+ $profiles = Get-ChildItem $diagDir - Recurse - Filter ' *.speedscope.json'
216+ if (-not $profiles ){ Write-Host ' No speedscope profiles found.' - ForegroundColor Yellow; break }
217+ Import-Module PwshSpectreConsole - ErrorAction Stop
218+ $solutionRoot = (Resolve-Path (Join-Path $PSScriptRoot ' ..' )).Path
219+ $map = [ordered ]@ {}
220+ $labels = @ ()
221+ foreach ($p in ($profiles | Sort-Object LastWriteTime - Descending)){
222+ $full = (Resolve-Path $p.FullName ).Path
223+ $rel = $full.Substring ($solutionRoot.Length ).TrimStart(' \\' )
224+ $label = " $ ( $p.LastWriteTime.ToString (' HH:mm:ss' )) | $ ( $p.Name ) "
225+ $map [$label ] = $full
226+ $labels += $label
227+ }
228+ $sel = Read-SpectreSelection - Title ' Select Speedscope Profile' - Choices ($labels + ' Cancel' ) - EnableSearch - PageSize 20
229+ if (-not $sel -or $sel -eq ' Cancel' ){ Write-Host ' Speedscope view cancelled.' - ForegroundColor Yellow; break }
230+ if (-not $map.Contains ($sel )){ Write-Host ' Invalid selection.' - ForegroundColor Red; break }
231+ $profile = $map [$sel ]
232+ Write-Host " Selected profile: $profile " - ForegroundColor Cyan
233+ # Try npx speedscope first (requires node + speedscope)
234+ $opened = $false
235+ try {
236+ if (Get-Command npx - ErrorAction SilentlyContinue){
237+ Write-Host ' Launching speedscope via npx (local web UI)...' - ForegroundColor Cyan
238+ & npx speedscope $profile
239+ if ($LASTEXITCODE -eq 0 ){ $opened = $true }
240+ }
241+ } catch { Write-Host " npx speedscope failed: $ ( $_.Exception.Message ) " - ForegroundColor Yellow }
242+ if (-not $opened ){
243+ Write-Host ' Opening speedscope profile in default browser (https://www.speedscope.app)...' - ForegroundColor Cyan
244+ try {
245+ Start-Process ' https://www.speedscope.app' # user can manually load file
246+ # Also open folder in Explorer for convenience
247+ $folder = Split-Path $profile - Parent
248+ Start-Process explorer.exe $folder
249+ Write-Host ' Speedscope site and folder opened.' - ForegroundColor Green
250+ } catch { Write-Host " Browser/folder open failed: $ ( $_.Exception.Message ) " - ForegroundColor Yellow }
251+ }
123252 }
124253 ' dump-heap' {
125254 Ensure- Tool ' dotnet-dump' ' dotnet-dump'
0 commit comments