リソースの読み込みとデプロイ時間の測定¶
Kanzi リソースプロファイリングを使用すると、Kanzi アプリケーションでリソースやプレハブをロードおよびデプロイするのにかかる時間を測定できます。
Kanzi では、リソースはアプリケーションの異なる部分で再利用できるアイテムです。例えば、Mesh Data リソースは Model ノードのジオメトリを定義し、異なるノードで同じ Color Brush を使用して Foreground Brush または Background Brush プロパティを設定できます。
ノードプレハブ(プレハブテンプレート)を使用して、アプリケーションを構築し、一貫性のあるインターフェースを作成します。プレハブを使用すると、アプリケーションの構成要素を作成し、アプリケーションの保守を容易にすることができます。
リソースプロファイリングを使用するには:
アプリケーション設定でリソースプロファイリングを有効にします。リソースプロファイリングの有効化 を参照してください。
アプリケーションコードにリソースプロファイリングデータのロギングを実装し、アプリケーションを実行してリソースプロファイリングデータを収集およびログします。リソースプロファイリングデータのログ記録 を参照してください。
Kanzi アプリケーションでのリソースのロードとデプロイのパフォーマンスを測定するには、リソースプロファイリングデータを分析します。リソースプロファイリングデータの分析 を参照してください。
リソースプロファイリングの有効化¶
リソースプロファイリングを開始するには、リソースプロファイリングカテゴリを有効にする必要があります。
アプリケーション構成でリソースプロファイリングを有効にするには、次のいずれかで ProfilingCategoryFilter 設定を使用します。
application.cfgファイル:ProfilingCategoryFilter = "ResourceLoading=on"
-
configuration.profilingCategoryFilter = "ResourceLoading=on";
アプリケーション実行中にリソースプロファイリングを有効または無効にするには、対応するプロファイリングカテゴリを有効または無効にします。
リソースプロファイリングを有効にするには:
kzProfilingCategorySetRuntimeState(KZ_PROFILING_RESOURCE_LOADING_CATEGORY, KZ_PROFILING_ENABLED_CATEGORY)
リソースプロファイリングを無効にするには:
kzProfilingCategorySetRuntimeState(KZ_PROFILING_RESOURCE_LOADING_CATEGORY, KZ_PROFILING_DISABLED_CATEGORY)
リソースプロファイリングを有効にした後、リソースプロファイリングデータを収集し、そのデータをファイルに書き込むことができます。詳細は、リソースプロファイリングデータのログ記録 を参照してください。
リソースプロファイリングデータのログ記録¶
Kanzi アプリケーションでのリソースのロードとデプロイを分析するために、リソースプロファイリングデータをログに記録します。リソースプロファイリングデータをログに記録する前に、リソースプロファイリングを有効にする必要があります。リソースプロファイリングの有効化 を参照してください。
リソースプロファイリングを有効にすると、Kanzi はアプリケーション内の各リソースのロードとデプロイメントをプロファイルし、プロファイリングデータをリソースプロファイラに保存します。収集されたプロファイリングデータのロギングをアプリケーションコードに実装してください。Kanzi は、リソースプロファイリングデータで Boost プロパティツリーを埋めるために使用できる ResourceProfilingPtreePopulator クラスを提供します。その後、Boost で利用可能な JSON フォーマッタを使用して、プロファイリングデータを JSON 形式でログに記録できます。
リソースプロファイリングデータを記録するには:
アプリケーションコードに、リソースプロファイリングデータを記録するために必要なヘッダーファイルを含めてください。
// Defines the standard input/output stream objects. #include <kanzi/core/cpp/iostream.hpp> // Provides classes that implement string stream input/output operations. #include <kanzi/core/cpp/sstream.hpp> // Provides the functionality for populating a Boost property tree with resource profiling data. #include <kanzi/core.ui/resource/resource_profiling_ptree_populator.hpp> // Provides the functionality for translating a Boost property tree to JSON and writing it to a file. #include <boost/property_tree/json_parser.hpp>
アプリケーションにリソースプロファイリングデータを出力するコードを追加します。
例えば、アプリケーション終了時に Kanzi が呼び出すコールバック
Application::onShutdownでプロファイリングデータをcoutにログするには、次のコードを追加します。void onShutdown() override { // Populate the Boost property tree with resource profiling data. ptree resourceProfilingDataTree = ResourceProfilingPtreePopulator::populatePropertyTree(getResourceManager()->getResourceProfiler()); // Write the property tree to string stream in JSON format. stringstream ss; boost::property_tree::json_parser::write_json(ss, resourceProfilingDataTree); // Boost json_writer considers "/" to be an escape character and adds "\" before each "/". // This affects how kzb URLs are displayed. // This code outputs json to cout replacing "\/" with "/". string str(ss.str()); string_view strView(str); while (!strView.empty()) { size_t backSlashPos = strView.find("\\/"); if (backSlashPos == string_view::npos) { cout << strView; strView = string_view(); continue; } cout << strView.substr(0, backSlashPos); strView = strView.substr(backSlashPos + 1); } cout << "\n"; }
Profiling build のいずれかの構成を使用してアプリケーションをビルドし、アプリケーションを実行します。アプリケーションを終了すると、コンソールウィンドウでプロファイリングデータを確認できます。
Windowsでアプリケーションをビルドして実行するには:
Visual Studioで、Profiling ビルド構成を使用してアプリケーションをビルドします。
Windowsで Kanzi Profiling build を実行しているとき、コンソールウィンドウは表示されません。リソースプロファイリングデータを記録するには、コンピュータのコマンドラインインターフェイスを開き、アプリケーションを実行して、アプリケーションの出力をリソースプロファイリング情報を保存したいファイルにリダイレクトしてください。
Application\build_vs<Version>\runtime\Profiling\My_application.exe > MyApplicationResourceProfiling.json
Kanzi は、リソースプロファイリングデータを出力ファイルに書き込みます。このデータには以下が含まれます:
Kanzi リソースマネージャーのメインスレッド (
"Resource manager main thread") とロードスレッド ("Resource manager loader thread N") のリソースプロファイリングコンテキスト。リソースプロファイリングコンテキスト を参照してください。リソースプロファイリングデータサンプル (
"ResourceProfilingDataSamples")。リソースプロファイリングデータサンプル を参照してください。
...
{
"ThreadContexts": {
"Resource manager loader thread 1": [
...
]
"Resource manager main thread": [
{ resource profiling context of resourceX },
{ resource profiling context of resourceY },
...
{ resource profiling context of resourceZ }
],
"Resource manager loader thread 0": [
...
{ resource profiling context of resourceY },
...
],
"Resource manager loader thread 2": [
...
...
{ resource profiling context of resourceZ },
...
]
},
"ResourceProfilingDataSamples": [
...
{ profiling data sample for resourceX },
{ profiling data sample for resourceY },
{ profiling data sample for resourceZ },
...
]
}
...
スクロールビューの例 についてログに記録されたリソースプロファイリングデータの例については、リソースプロファイリングデータの分析 を参照してください。
リソースプロファイリングデータの分析¶
リソースプロファイリングを有効にしてデータを収集した後、リソースプロファイラによって収集されたデータを分析します。
リソースプロファイリングデータには以下が含まれます:
Kanzi リソースマネージャーのメインスレッド (
"Resource manager main thread") とロードスレッド ("Resource manager loader thread N") のリソースプロファイリングコンテキスト。リソースプロファイリングコンテキスト を参照してください。リソースプロファイリングデータサンプル (
"ResourceProfilingDataSamples")。リソースプロファイリングデータサンプル を参照してください。
たとえば、スクロールビューの例 アプリケーションのリソースプロファイリングデータを収集して分析します。
リソースプロファイリングデータには、以下の情報が含まれています:
リソース取得 (Resource acquisition)¶
通常、アプリケーションの起動時に、Kanzi は StartupPrefab プレハブテンプレートを取得し、それを Screen ノードとしてインスタンス化します。リソースの読み込みパフォーマンスを最適化するために、起動プレハブを取得した後、Kanzi は Screen ノードの子孫ノードを反復処理し、それらのノードが使用するすべてのリソースのURLを収集します。その後、Kanzi はそれらのリソースを非同期で取得します。
例えば、スクロールビューのサンプルアプリケーションでは、City ノードが City メッシュを使用します。City ノードが Screen ノードの子孫ノードの一つであるため、Kanzi は City メッシュを非同期で取得します。
スクロールビューの例のアプリケーションで収集されたリソースプロファイリングデータでは、Resource manager main thread リソースプロファイリングコンテキストの中に、City メッシュの ResourceAcquire コンテキストを見つけることができます。このコンテキストの AcquireAsynchronously 属性は true に設定されており、Kanzi が期待通りに非同期で City メッシュを取得したことを示しています。
ResourceAcquire コンテキストの親は AcquireResourcesAsynchronously コンテキストであり、これは MainLoop コンテキストの依存コンテキストです。MainLoop コンテキストの MainLoopCounter 属性は "0" の値を持ち、これは Kanzi が最初のメインループのイテレーション中に非同期で City メッシュリソースを取得したことを意味します。
AcquireResourcesAsynchronously コンテキストには、Screen ノードの子孫ノードで使用される他のリソースを取得することに関連する依存コンテキストがあります。
"Resource manager main thread": [
{
"ContextID": "217960184",
"ContextName": "MainLoop",
"DependenciesDuration": "359408700",
"Duration": "389924400",
"MainLoopCounter": "0",
"TimeStamp": "200",
"DependencyContexts": [
{
...
},
{
"ContextID": "217470528",
"ContextName": "AcquireResourcesAsynchronously",
"DependenciesDuration": "0",
"Duration": "329800",
"TimeStamp": "3697300",
"DependencyContexts": [
...
{
"AcquireAsynchronously": "true",
"ContextID": "216087856",
"ContextName": "ResourceAcquire",
"DependenciesDuration": "0",
"Duration": "9000",
"ResourceUrl": "kzb://scroll_view/Mesh Data/City",
"TimeStamp": "3750800"
},
...
リソースローディング (Resource loading)¶
Kanzi ローディングスレッドは、非同期でロードするように設定されたリソースを並行してロードします。各非同期ロードリソースに対して、Kanzi はローディングタスクを作成し、そのタスクをローディングキューに配置します。ローディングスレッドはそのキューからローディングタスクを取り出して実行します。ローディングスレッドがローディングタスクを実行するたびに、リソースプロファイラはそのローディングスレッドのために ResourceLoading コンテキストを作成します。
ResourceLoading コンテキストの City メッシュは、"Resource manager loader thread 1" スレッドのリソース読み込みコンテキストの1つです。ResourceLoading コンテキストでは、
ResourceLoadingDurationは、リソースをロードするのにロードスレッドがかかった時間をナノ秒で示します。TimeStampはリソースの読み込みが開始された時を示します。LoadedResourceIDは、ロードされたリソースのユニークな識別子です。この識別子を使用して、アプリケーションがリソースを削除した後に同じリソースを再度ロードする際の異なる機会を区別することができます。
"Resource manager loader thread 1": [
...
{
"ContextID": "241268536",
"ContextName": "ResourceLoading",
"DependenciesDuration": "0",
"Duration": "1475600",
"LoadedResourceID": "217505936",
"LoadedResourceType": "Kanzi.Mesh",
"LoadedResourceUrl": "kzb://scroll_view/Mesh Data/City",
"ResourceLoadingDuration": "1473400",
"TimeStamp": "3764700"
}
...
ローディングスレッドが City メッシュリソースの読み込みを完了すると、リソースの読み込みタスクをリソースマネージャーの完了キューに配置し、Kanzi メインスレッドがさらに処理します。Kanzi メインスレッドは、ローディングスレッドが完了したタスクをキューに配置すると、完了キューを処理します。
デバッグ時には、Kanzi がスレッドを作成する際や、Kanzi が Domain::setOnThreadCreation および ResourceManager::setOnNewLoadingTask を使用してスレッドにローディングタスクを与える際に、独自のコールバックを提供することができます。
リソースのデプロイ¶
Kanzi メインスレッドが City メッシュリソースのロードタスクを処理する際、リソースプロファイラは FinishingQueue::processTask コンテキストを作成します。FinishingQueue::processTask コンテキストでは、Description 属性がロードタスクのタスクインデックスと、完了キュー内のタスク数を示します。ロードタスクの処理には、リソース取得の最終段階であるリソース展開が含まれます。ResourceDeployment コンテキストは FinishingQueue::processTask コンテキストの依存コンテキストです。
"Resource manager main thread": [
{
"ContextID": "217960184",
"ContextName": "MainLoop",
"DependenciesDuration": "359408700",
"Duration": "389924400",
"MainLoopCounter": "0",
"TimeStamp": "200",
"DependencyContexts": [
...
]
},
...
{
"ContextID": "242014232",
"ContextName": "FinishingQueue::processTask",
"DependenciesDuration": "43838400",
"Description": "Task index 1, queue size 2",
"Duration": "43914000",
"TimeStamp": "59703300",
"DependencyContexts": [
{
"ContextID": "241265456",
"ContextName": "ResourceDeployment",
"DependenciesDuration": "43118600",
"DeployedResourceID": "217505936",
"DeployedResourceType": "Kanzi.Mesh",
"DeployedResourceUrl": "kzb://scroll_view/Mesh Data/City",
"DeploymentDuration": "719800",
"Duration": "43839600",
"TimeStamp": "59705500",
"DependencyContexts": [
...
City メッシュは3Dアセットといくつかのマテリアルを使用します。Kanzi は、City メッシュのデプロイ時にこれらのリソースを取得します。City メッシュが依存するそれらのリソースの ResourceAcquire コンテキストは、依存コンテキストとして City メッシュの ResourceDeployment コンテキストに追加されます。
例えば、City メッシュの ResourceDeployment コンテキストの依存ツリーでは、City メッシュが Park2 マテリアルを使用し、それがさらに Phong マテリアルタイプを使用していることがわかります。City メッシュの ResourceDeployment コンテキストでは、DependenciesDuration 属性が、City メッシュが依存するリソースのロードとデプロイにかかった時間をナノ秒で示しています。
"ContextID": "241265456",
"ContextName": "ResourceDeployment",
"DependenciesDuration": "43118600",
"DeployedResourceID": "217505936",
"DeployedResourceType": "Kanzi.Mesh",
"DeployedResourceUrl": "kzb://scroll_view/Mesh Data/City",
"DeploymentDuration": "719800",
"Duration": "43839600",
"TimeStamp": "59705500",
"DependencyContexts": [
{
"AcquireAsynchronously": "false",
"ContextID": "216090208",
"ContextName": "ResourceAcquire",
"DependenciesDuration": "16896400",
"Duration": "16919600",
"ResourceUrl": "kzb://scroll_view/Materials/Park2",
"TimeStamp": "59706300",
"DependencyContexts": [
{
"ContextID": "241265368",
"ContextName": "ResourceLoading",
"DependenciesDuration": "0",
"Duration": "1200",
"LoadedResourceID": "241104440",
"LoadedResourceType": "Kanzi.Material",
"LoadedResourceUrl": "kzb://scroll_view/Materials/Park2",
"ResourceLoadingDuration": "200",
"TimeStamp": "59724500"
},
{
"ContextID": "241265280",
"ContextName": "ResourceDeployment",
"DependenciesDuration": "16864100",
"DeployedResourceID": "241104440",
"DeployedResourceType": "Kanzi.Material",
"DeployedResourceUrl": "kzb://scroll_view/Materials/Park2",
"DeploymentDuration": "32100",
"Duration": "16897400",
"TimeStamp": "59726400",
"DependencyContexts": [
{
"AcquireAsynchronously": "false",
"ContextID": "216092784",
"ContextName": "ResourceAcquire",
"DependenciesDuration": "16864100",
"Duration": "16882700",
"ResourceUrl": "kzb://scroll_view/Material Types/Phong",
"TimeStamp": "59731500",
"DependencyContexts": [
{
"ContextID": "241267480",
"ContextName": "ResourceLoading",
"DependenciesDuration": "0",
"Duration": "13800",
"LoadedResourceID": "241104544",
"LoadedResourceType": "Kanzi.ShaderProgram",
"LoadedResourceUrl": "kzb://scroll_view/Material Types/Phong",
"ResourceLoadingDuration": "13300",
"TimeStamp": "59740100"
},
{
"ContextID": "241265192",
"ContextName": "ResourceDeployment",
"DependenciesDuration": "0",
"DeployedResourceID": "241104544",
"DeployedResourceType": "Kanzi.ShaderProgram",
"DeployedResourceUrl": "kzb://scroll_view/Material Types/Phong",
"DeploymentDuration": "16850800",
"Duration": "16853300",
"TimeStamp": "59754300"
}
]
}
]
}
]
},