GPU performance調べ
ID3D11Query
ID3D11Queryで、GPUが処理した様々な情報を取得できるようです。 time stampを取得して、処理にかかった時間を計測できるようにしました。
StartProfileでは、
- QUERY_TIMESTAMP_DISJOINT を ID3D11DeviceContext::Begin
- start time用の QUERY_TIMESTAMP を ID3D11DeviceContext::End
EndProfileでは、
- end time用の QUERY_TIMESTAMP を ID11DeviceContext::End
- QUERY_TIMESTAMP_DISJOINT を ID3D11DeviceContext::End
Profileの結果取得では、
- ID11DeviceContext::GetData で、結果を取得
上記の呼び出しで、time stampを取得でき、その差分で時間を計測することができました。 ID11DeviceContext::GetDataは、データが取得できるまで待たなければならない為、別のスレッドで取得するか。 取得自体を遅らせて、数フレーム前の情報を取得しなければ、CPU側の待ちが大きくなってしまうようです。 数フレーム前の情報を取得するには、 Queryをリングバッファで作成して、遅延フレームを設定して数フレーム前の情報を取得するようにしました。
コードは以下の感じ、
void Profiler::StartProfile(const std::string& name)
{
ProfileData& profileData = m_profiles[name];
if (profileData.DisjointQuery[m_currFrame] == nullptr)
{
// Create the queries
D3D11_QUERY_DESC desc;
desc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT;
desc.MiscFlags = 0;
device->CreateQuery(&desc, &profileData.DisjointQuery[m_currFrame]);
desc.Query = D3D11_QUERY_TIMESTAMP;
device->CreateQuery(&desc, &profileData.TimestampStartQuery[m_currFrame]);
device->CreateQuery(&desc, &profileData.TimestampEndQuery[m_currFrame]);
}
// Start a disjoint query first
context->Begin(profileData.DisjointQuery[m_currFrame]);
// Insert the start timestamp
context->End(profileData.TimestampStartQuery[m_currFrame]);
}
void Profiler::EndProfile(const std::string& name)
{
ProfileData& profileData = m_profiles[name];
// Insert the end timestamp
context->End(profileData.TimestampEndQuery[m_currFrame]);
// End the disjoint query
context->End(profileData.DisjointQuery[m_currFrame]);
profileData.QueryStarted = false;
profileData.QueryFinished = true;
}
void Profiler::EndFrame()
{
m_currFrame = (m_currFrame + 1) % QueryLatency;
// Iterate over all of the profiles
for (auto& iter : m_profiles)
{
ProfileData& profile = iter.second;
if (profile.QueryFinished == false) {
continue;
}
profile.QueryFinished = false;
if (profile.DisjointQuery[m_currFrame] == nullptr)
continue;
// Get the query data
uint64_t startTime = 0;
while (context->GetData(profile.TimestampStartQuery[m_currFrame], &startTime, sizeof(startTime), 0) != S_OK);
uint64_t endTime = 0;
while (context->GetData(profile.TimestampEndQuery[m_currFrame], &endTime, sizeof(endTime), 0) != S_OK);
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT disjointData;
while (context->GetData(profile.DisjointQuery[m_currFrame], &disjointData, sizeof(disjointData), 0) != S_OK);
if (disjointData.Disjoint == false)
{
UINT64 delta = endTime - startTime;
float frequency = static_cast<float>(disjointData.Frequency);
profile.time = (delta / frequency) * 1000.0f; // msec
}
}
}
結果
その他
EndFrameのCPU処理時間は、0.02msec程度でした。
0 件のコメント:
コメントを投稿