2

この質問は、私の側でのより大きな取り組みのトラブルシューティングを試みるものであるため、以下の投稿に重要な背景と調査履歴を含めました. そのため、投稿を「背景」、「これまでの調査」、「問題」の 3 つのセクションに分けました。自分でさらに調査を行ったので、調査結果を拡大するために「追加の調査」セクションも追加しました。これにより、最終的に私は自分で問題を解決するようになり、同じことをしようとする開発者のためのガイドとして元の投稿を含めました. この問題は、最終的に v1 以降の Powershell バージョンで VSPerfCmd.exe が持つ制御の問題の復帰でした。

  1. バックグラウンド

TFS ビルド (開発 Web サーバー DEV への自動展開を含む) の一環として、コードのパフォーマンス テストを開始して実行し、新しい変更が API の速度に悪影響を与える時期を確認したいと考えています。そのために、テスト ランナー (SoapUI) と VS チーム ツールを DEV にインストールし、DEV でローカルに実行すると必要なレポートを生成するPowershell スクリプトを作成しました。ただし、そのスクリプトをトリガーして、他の場所から機能させることはまだできていません。つまり、サーバーにログオンし、.ps1 ファイルを見つけて Powershell で実行するだけで機能するということです。これがそのスクリプトです:

#script location+name \\DEV\C$\PerformanceTest\profile-tracing-SoapUI.ps1
$startPath = Get-Location
$siteUrl = "http://api.dev.com"
$sleepTime = 5
$logLocation = "C:\reports\api"
$websiteLocation = "W:\Sites\API\Code\API\_PublishedWebsites\API\bin"

try
{
    #Instrument the API dlls
    Write-Host "Instrumenting DLLs..."
    Get-ChildItem $websiteLocation "API*.dll" | ForEach-Object {
        Set-Location -Path $websiteLocation
        & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSInstr.exe" $_.Name
    }

    #set location back to start
    Set-Location -Path $startPath

    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCLREnv.cmd" /GlobalTraceOn
    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCLREnv.cmd" /GlobalInteractionOn

    #launch the profiler on the site
    Write-Host "Starting the trace..."

    #start:Trace - in tracing mode so we get timing data
    #output - the output vsp file
    #cs - cross session mode because we are profiling an IIS session
    #user - give permissions to profile to everyone
    #globaloff - start with capturing off so we don't get start up data.
    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /start:Trace /output:$logLocation"\API.vsp" /cs /User:Everyone /globaloff

    #restart IIS so the tracer can detect it
    Write-Host "Resetting IIS..."
    IISReset t80w103 /noforce
    IISReset t80w103 /status

    #output the status
    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /status

    #set up request for triggering api start up
    Write-Host "Starting app via untraced request..."
    $request = [System.Net.WebRequest]::Create("$siteUrl/api/v1/foo/1")
    $request.ContentType = "application/json"
    $request.Method = "GET" 

    #run an initial request to trigger api start up
    $response = $request.GetResponse()
    Write-Host $response.StatusCode

    #enable capturing
    Write-Host "Enabling capturing..."
    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /globalon

    #wait so everything can catch up
    Write-Host "Pausing for $sleepTime seconds to let processes catch up..."
    Start-Sleep -s $sleepTime

    #run the load tester
    Write-Host "Running SOAP UI load test"
    #e - the site to test against
    #s - the test suite name
    #c - the test cases
    #l - the loadtest to run
    #r - log reports
    #f - log location
    #<soap ui test suite location>
    $loadtestName = "LoadTest All API Methods"
    & "C:\Program Files (x86)\SmartBear\SoapUI-5.1.3\bin\loadtestrunner.bat" -e $siteUrl -s "Load Test" -c "Load Test Cases" -l $loadtestName -r -f $logLocation "Api Profiler Load Test.xml"


    #wait so everything can catch up
    Write-Host "Pausing for $sleepTime seconds to let processes catch up..."
    Start-Sleep -s $sleepTime

    #disable capturing
    Write-Host "Disabling capturing..."
    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /globaloff

    #shut down the profiler
    Write-Host "Shutting down profiler. This may take some time..." 

    #shut down IIS so the /shutdown command works
    IISReset t80w103 /noforce
    IISReset t80w103 /status
    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /shutdown
    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCLREnv.cmd" /off /globaloff

    #generate report summary
    $date = Get-Date -format "yyyy-dd-M--HH-mm-ss"
    $summaryReportLocation = "$logLocation\API $date"
    & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\VSPerfReport.exe" "$logLocation\Api.vsp" /SummaryFile /Output:"$summaryReportLocation"

    #move items to shared location
    $reportFolder = "\\shareDrive\API\Performance Reports\$date"
    $profilerReport = get-childitem "$summaryReportLocation.vsps"
    New-Item $reportFolder -type directory
    Copy-Item $profilerReport.FullName  $reportFolder

    #log success
    $logDate = Get-Date -format "yyyy-dd-mm HH-mm-ss"
    $output = "[$logDate]" + [System.Environment]::NewLine + "Completed successfully."
    $output | out-file "profiler-log.log" -append

    Write-Host "Completed successfully."
}
catch{
    #log error
    Write-Host $_
    $logDate = Get-Date -format "yyyy-dd-mm HH-mm-ss"
    $output = "[$logDate]" + [System.Environment]::NewLine + $_ + [System.Environment]::NewLine
    $output | out-file "profiler-log.log" -append
}
finally{
    Write-Output "Done"
}

私が言ったように、DEV で自分で手動で実行すると、上記は正常に動作しますが、トリガーしようとしましたが、正しく動作しません。

Enter-PSSession DEV
Invoke-Command -ComputerName DEV -FilePath "C:\PerformanceTest\profile-tracing-SoapUI.ps1"
Exit-PSSession
  1. これまでの調査

上記はスクリプトをトリガーするようですが、奇妙な問題に遭遇しました。まず、スクリプトを実行するマシン (テスト用のマシン、自動展開用の TFS ビルド サーバー) でスクリプトが呼び出されますが、期待どおりに DEV では呼び出されません。これはおそらく私のPowerShellの誤解であり、十分に簡単な修正です-スクリプトをテストしているネットワークマシン(自分自身またはTFSビルドサーバーのいずれか)にコピーしない限り、powershellはディレクトリが見つからないというエラーを単にバーフしますスクリプトを実行する前に。第二に、トリガーしようとしているマシンにスクリプトが配置されていても(スクリプトを見つけて実行を開始します)、「トレースを開始しています...」という出力にしか到達しません。 vsperfcmd に関する情報。

Starting the trace...
Microsoft (R) VSPerf Command Version 12.0.30723 x64
Copyright (C) Microsoft Corp. All rights reserved.


Global logging control
------------------------------------------------------------
Setting global profile state to OFF.

そこにハングアップし、ブレークアウトする必要があるため、呼び出しが完全に実行されていないと思います。かなりの時間実行したままにしました (20 分以上、ローカルではこのポイントを通過するのに数秒かかります) が、このポイントを超えて継続したことはありません。その場所でスクリプトの出力をローカルで実行すると、次のようになります。

Starting the trace...
Microsoft (R) VSPerf Command Version 12.0.30723 x64
Copyright (C) Microsoft Corp. All rights reserved.


Global logging control
------------------------------------------------------------
Setting global profile state to OFF.

Resetting IIS...
  1. 問題

これにより、問題の行は

& "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /start:Trace /output:$logLocation"\API.vsp" /cs /User:Everyone /globaloff

実際、この仮説をテストするためにはるかに短縮されたスクリプトを実行すると、そのコマンドを実行した後に制御がシェルに返されないことを確認できました。以下は、これとその出力を確認するために実行したスクリプトです。

Enter-PSSession t80w103
Invoke-Command -ComputerName t80w103 -ScriptBlock{
    try{
        & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /start:Trace /output:$logLocation"\API.vsp" /cs /User:Everyone /globaloff
        Write-Host "No Error and Control Returned"
    }
    catch{
        Write-Host "Error!"
    }
    finally{
        Write-Output "Done.."
    }
}
Exit-PSSession

OUTPUT:
Microsoft (R) VSPerf Command Version 12.0.30723 x64
Copyright (C) Microsoft Corp. All rights reserved.


Global logging control
------------------------------------------------------------
Setting global profile state to OFF.

そのコマンドの後、何も出力されません。しばらくの間、これはアプリケーションまたは DEV サーバーに問題があり、vsperfcmd に適切にアクセスできないことを意味しているのではないかと考えていましたが、DEV タスク マネージャーを確認したところ、VSPerfMon.exe プロセス リストに表示されることがわかりました。コマンドを実行し、ctrl + ブレークアウトすると停止します。したがって、コマンド機能しているように見えますが、少なくとも部分的には、スクリプトの次の部分を実行できるように制御を返さないだけです。

それで、私の質問は、どうすればこれを機能させることができますか? プロファイル モニタを開始するコマンドを実行した後、コントロールが返らないのはなぜですか? また、TFS からビルドを自動展開した後にパフォーマンス プロファイリングを行うには、これが最善の方法ですか? (更新については以下を参照してください)

  1. 追加調査

投稿以来、私はこれを自分で調査し続け、いくつかの興味深いことを学びました. 最初に、DEV サーバー上の PowerShell のバージョンが古かったので (これは認識していませんでした)、バージョン 3 に更新したことに注意してください。PowerShell ISE の powershellV3 でスクリプトをローカルで実行しようとすると、スクリプトをリモートで実行しようとしたときとまったく同じようにハングしていることに気付きました。右クリックコマンド「powershellで実行」を介してスクリプトを実行した場合にのみ、powershellV1を呼び出すスクリプトが機能します。異なるバージョンの powershell がスクリプトを処理する方法には明確な違いがあるようです。

改訂された質問: スクリプトが powershellV1 では機能するのに V3 では機能しないのはなぜですか? \start:trace の後に V3 がハングするのに、V1 がハングしないのはなぜですか? PowerShell セッションが V2 まで導入されなかった場合、V1 を使用してスクリプトを実行するためのネットワーク実行を取得するにはどうすればよいですか?

4

1 に答える 1

0

改訂された質問に答えると、この問題を解決できました。V1以降のバージョンのPowershellでは、起動時にVSPerfCMD.exeがシェルに制御を返さないことが判明しました(ソースコードが表示されないため、理由はわかりません)。これは、

VSPerfCmd.exe /Start

別のシェルで実行する必要があります。そうしないと、スクリプトがハングします。別のシェルが shutdown コマンドを呼び出した場合にのみ、制御が返されます。この問題を解決するために、次のコードを使用してプロファイラーを開始し、スクリプトが実行されるまで待ってから続行します。

Write-Host "Starting the trace..."

#start:Trace - in tracing mode so we get timing data
#output - the output vsp file
#cs - cross session mode because we are profiling an IIS session
#user - give permissions to profile to everyone
#globaloff - start with capturing off so we don't get start up data. > is this the problem?

start powershell -ArgumentList "-ExecutionPolicy Bypass -command & 'C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe' /start:Trace /output:$logLocation\CatalogAPI.vsp /cs /User:Everyone /GlobalOff"

#wait for VSPerfCmd to start up
Write-Host "Waiting 15s for VSPerfCmd to start up..."
Start-Sleep -s 15

$counter = 0
while($counter -lt 6)
{
    $e = & "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /status
    if ($LASTEXITCODE -eq 0){
        Write-Host $e
        break       
    }

    if ($LASTEXITCODE -eq 1 -and $counter -lt 5){
        Write-Host "Still waiting. Give it 10s more ($counter)..."
        Start-Sleep -s 10
        $counter++
        continue
    }

    throw "VSPerfCmd Error: $e"                 
}

最初のスクリプトの元のトレース開始の代わりに上記のコードを使用すると、powershell スクリプトで自動パフォーマンス プロファイリングを実行できるはずですが、最初にこれを投稿してからスクリプトが少し変更されているため、結果を保証することはできません (さまざまな調査とコードの改善)。それを機能させるには、代わりに上記を使用してください

#enable capturing
Write-Host "Enabling capturing..."
& "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Team Tools\Performance Tools\x64\VSPerfCmd.exe" /globalon

tl;dr VSPerfCmd.exe /Start は、powershell v1 以降のバージョンの powershell でプロファイリング サービスが停止されるまで、コマンドを呼び出したシェルに制御を返しません。パフォーマンス プロファイリングを自動化する場合は、別のシェルでパフォーマンス プロファイラーを起動し、プロファイラーのステータスがアクティブであることを示すまで待ってから続行する必要があります。

于 2015-07-30T18:48:48.957 に答える