JProfiler ヘルプ

非同期およびリモートリクエストトラッキング

呼び出しツリーの詳細機能

タスクの非同期実行は、プレーンなJavaコードでも、リアクティブフレームワークではさらに一般的な手法です。ソースファイル上で隣接しているコードが、実際には2つ以上の異なるスレッドで実行されることになります。デバッグやプロファイリングの際、これらのスレッド変更は2つの問題を引き起こします。1つは、呼び出された操作がどれほどコストがかかるのかが明確でないこと、もう1つは、コストの高い操作をその実行原因となったコードまで遡って追跡できないことです。

JProfilerは、この問題に対して、呼び出しが同じJVM内で完結するかどうかによって異なるソリューションを提供します。非同期実行が呼び出し元と同じJVMで行われる場合、「インライン非同期実行」 呼び出しツリー分析は、呼び出し元サイトと実行サイトの両方を含む単一の呼び出しツリーを計算します。リモートJVMへのリクエストが行われた場合、 呼び出しツリーには、呼び出し元サイトと実行サイトへのハイパーリンクが含まれ、関係するJProfilerのトップレベルウィンドウ間でプロファイリングセッションをシームレスに行き来できます。

非同期およびリモートリクエストトラッキングの有効化

非同期メカニズムは様々な方法で実装可能であり、別スレッドや異なるJVMでタスクを開始するセマンティクスは一般的な方法では検出できません。JProfilerは、いくつかの一般的な非同期およびリモートリクエスト技術を明示的にサポートしています。リクエストトラッキング設定で、それらを有効または無効にできます。 デフォルトでは、リクエストトラッキングは有効になっていません。また、セッション開始直前に表示されるセッション開始ダイアログでもリクエストトラッキングを設定できます。

JProfilerのメインウィンドウでは、ステータスバーにて非同期およびリモートリクエストトラッキングのいずれかのタイプが有効になっている場合、その状態が表示され、設定ダイアログへのショートカットも提供されます。

JProfilerは、プロファイルされたJVMで有効化されていない非同期リクエストトラッキングタイプが使用されている場合、  通知アイコンを非同期およびリモートリクエストトラッキングアイコンの横に表示します。通知アイコンをクリックすることで、検出されたトラッキングタイプを有効化できます。非同期およびリモートリクエストトラッキングは大きなオーバーヘッドを生じる可能性があるため、必要な場合のみ有効化してください。

非同期トラッキング

少なくとも1つの非同期トラッキングタイプが有効化されている場合、CPU・割り当て・プローブ記録の呼び出しツリーおよびホットスポットビューには、すべての有効なトラッキングタイプの情報と、「インライン非同期実行」呼び出しツリー分析を計算するボタンが表示されます。その分析結果ビューでは、すべての非同期実行の呼び出しツリーが、  「非同期実行」ノードを介して呼び出し元サイトと接続されます。 デフォルトでは、非同期実行の測定値は呼び出しツリーの祖先ノードには加算されません。 集約値を確認したい場合は、分析画面上部のチェックボックスで切り替え可能です。

別スレッドでタスクをオフロードする最も単純な方法は、新しいスレッドを開始することです。JProfilerでは、「Thread start」リクエストトラッキングタイプを有効にすることで、スレッドの生成から実行サイトまで追跡できます。ただし、スレッドは重いオブジェクトであり、通常は繰り返しの呼び出しで再利用されるため、このトラッキングタイプは主にデバッグ用途に適しています。

他のスレッドでタスクを開始する最も重要かつ汎用的な方法は、java.util.concurrentパッケージのexecutorを利用することです。executorは、非同期実行を扱う多くのサードパーティライブラリの基盤にもなっています。executorをサポートすることで、JProfilerはマルチスレッドや並列プログラミングを扱うライブラリ全体をカバーします。

上記の汎用的なケースに加え、JProfilerはJVM用の2つのGUIツールキット(AWTとSWT)もサポートしています。どちらのツールキットもシングルスレッドで動作し、GUIウィジェットの操作や描画処理を行う特別なイベントディスパッチスレッドが1つ存在します。GUIをブロックしないためには、長時間実行されるタスクはバックグラウンドスレッドで実行する必要があります。しかし、バックグラウンドスレッドは進捗や完了を示すためにGUIを更新する必要があることが多く、これは特別なメソッドを使ってRunnableをイベントディスパッチスレッド上で実行するようスケジューリングすることで実現します。

GUIプログラミングでは、原因と結果を結びつけるために複数回のスレッド変更を追跡する必要がよくあります。ユーザーがイベントディスパッチスレッド上でアクションを開始し、それがexecutor経由でバックグラウンド処理を開始します。完了後、そのexecutorがイベントディスパッチスレッドに操作を戻します。もし最後の操作でパフォーマンス問題が発生した場合、元のイベントから2回スレッドが切り替わっていることになります。

最後に、JProfilerはKotlinコルーチンもサポートしています。Kotlinのマルチスレッドソリューションであり、すべてのKotlinバックエンドで実装されています。非同期実行自体はコルーチンが起動されるポイントです。Kotlinコルーチンのディスパッチ機構は柔軟で、実際には現在のスレッドで開始される場合もあり、その場合「非同期実行」ノードにはインライン部分が含まれ、ノードのテキスト内で個別に報告されます。

サスペンド可能なメソッドは、実行を中断し、別のスレッドで再開される場合があります。サスペンドが検出されたメソッドには、追加で  「サスペンド」アイコンが表示され、ツールチップで実際の呼び出し回数とセマンティックな呼び出し回数が確認できます。 Kotlinコルーチンは意図的にサスペンドできますが、スレッドに紐付いていないため、待機時間は呼び出しツリー上には表示されません。コルーチン実行が完了するまでの合計時間を確認するには、「非同期実行」ノードの下に  「サスペンド時間」ノードが追加され、コルーチンの全サスペンド時間を記録します。 非同期実行のCPU時間とウォールクロック時間のどちらに関心があるかによって、分析画面上部の「サスペンド時間を表示」チェックボックスでこれらのノードを動的に表示・非表示できます。

プロファイルされていない呼び出し元サイトのトラッキング

デフォルトでは、executorおよびKotlinコルーチントラッキングは、呼び出し元サイトがプロファイルされたクラス内にある非同期実行のみを追跡します。これは、フレームワークやライブラリがこれらの非同期メカニズムを自分のコードとは直接関係のない形で使用する場合があり、追加された呼び出し元・実行サイトがオーバーヘッドやノイズとなるためです。しかし、プロファイルされていない呼び出し元サイトを追跡したい場合もあります。例えば、フレームワークがKotlinコルーチンを開始し、その上で自分のコードが実行される場合などです。

プロファイルされていないクラス内の呼び出し元サイトが検出された場合、呼び出しツリーやホットスポットビューのトラッキング情報に対応する通知メッセージが表示されます。ライブセッション中は、executorおよびKotlinコルーチントラッキングごとに、これらのビューから直接プロファイルされていない呼び出し元サイトのトラッキングを個別に有効化できます。 これらのオプションは、セッション設定ダイアログの「CPUプロファイリング」ステップでいつでも変更可能です。

Kotlinコルーチンは、起動時にCPU記録が有効になっていた場合のみトラッキングできることに注意してください。後からCPU記録を開始した場合、Kotlinコルーチンの非同期実行はインライン化できません。JProfilerは、プロファイルされていないクラス内の呼び出し元サイト検出時と同様に通知します。アプリケーション起動時に開始される長寿命コルーチンをプロファイルしたい場合、attachモードは利用できません。その場合、-agentpath VMパラメータを指定してJVMを起動し、起動時にCPU記録を開始してください。

リモートリクエストトラッキング

特定の通信プロトコルに対して、JProfilerはメタデータを挿入し、JVM間をまたいでリクエストをトラッキングできます。サポートされている技術は以下の通りです。

  • HTTP: HttpURLConnection, java.net.http.HttpClient, Apache Http Client 4.x, Apache Async Http Client 4.x, OkHttp 3.9+ クライアント側、サーバー側は任意のServlet-API実装またはJetty(Servletなし)
    HTTP: HttpURLConnection、java.net.http.HttpClient、Apache Http Client 4.x、Apache Async Http Client 4.x、OkHttp 3.9+(クライアント側)、サーバー側は任意のServlet-API実装またはServletなしのJetty
  • Jersey Async Client 2.x, RestEasy Async Client 3.x, Cxf Async Client 3.1.1+ の非同期JAX-RS呼び出しの追加サポート
    Jersey Async Client 2.x、RestEasy Async Client 3.x、Cxf Async Client 3.1.1+ の非同期JAX-RS呼び出しの追加サポート
  • Webサービス: JAX-WS-RI, Apache Axis2, Apache CXF
    Webサービス: JAX-WS-RI、Apache Axis2、Apache CXF
  • RMI
  • gRPC
  • リモートEJB呼び出し: JBoss 7.1+、Weblogic 11+
    リモートEJB呼び出し: JBoss 7.1+、Weblogic 11+

JProfilerでリクエストを追跡するには、両方のVMをプロファイルし、それぞれを別々のJProfilerトップレベルウィンドウで同時に開く必要があります。これはライブセッションでもスナップショットでも動作します。 対象JVMが現在開かれていない場合や、リモート呼び出し時にCPU記録が有効でなかった場合、呼び出し元サイトのハイパーリンクをクリックするとエラーメッセージが表示されます。

リモートリクエストをトラッキングする際、JProfilerは関係するJVMの呼び出しツリー上で呼び出し元サイトと実行サイトを明示的に表示します。JProfilerにおける呼び出し元サイトは、記録されたリモートリクエストが実行される直前の最後のプロファイル済みメソッドコールです。これは、異なるVM上にある実行サイトでタスクを開始します。 JProfilerでは、呼び出しツリービューに表示されるハイパーリンクを使って、呼び出し元サイトと実行サイト間をジャンプできます。

呼び出し元サイトは、すべてのスレッドに対してリモートリクエストトラッキング上同一のIDを持ちます。つまり、呼び出し元サイトと実行サイト間をジャンプする際、スレッド解決は行われず、常に「すべてのスレッドグループ」および「すべてのスレッド状態」が選択され、対象が必ず表示ツリー内に含まれるようになります。

呼び出し元サイトと実行サイトは1対多(1:n)の関係です。呼び出し元サイトは、複数の実行サイト(特に異なるリモートVM上)でリモートタスクを開始できます。同じVM内で1つの呼び出し元サイトに対して複数の実行サイトが存在するのは稀で、異なる呼び出しスタックで発生する場合のみです。 1つの呼び出し元サイトが複数の実行サイトを呼び出す場合、ダイアログでその中から1つを選択できます。

実行サイトは、呼び出しツリー内において、1つの呼び出し元サイトから開始されたすべての実行を含む合成ノードです。実行サイトノード内のハイパーリンクをクリックすると、その呼び出し元サイトに戻ることができます。

同じ呼び出し元サイトが同じ実行サイトを繰り返し呼び出す場合、実行サイトにはすべての呼び出しのマージされた呼び出しツリーが表示されます。これを望まない場合は、 例外的なメソッド機能を使って呼び出しツリーをさらに分割できます(下記スクリーンショット参照)。

実行サイトは単一の呼び出し元サイトからのみ参照されるのに対し、呼び出し元サイト自体は複数の実行サイトにリンクできます。呼び出し元サイトの数値IDを使えば、異なる実行サイトから参照されている場合でも同じ呼び出し元サイトであることが分かります。さらに、呼び出し元サイトにはリモートVMのIDも表示されます。プロファイルされたVMのIDはステータスバーで確認でき、これはJProfilerが内部的に管理するユニークIDではなく、JProfilerで新しく開かれたプロファイル済みVMごとに1から増加する表示用IDです。