Add toggle to disable the tick->ns conversion of timestamp query

Although the error rate of timestamp tick->ns conversion is very small
(3e-5), some profiling scenarios, such as CPU/GPU timestamp calibration
on Windows, require absolutely accurate timestamps.

Add new toggle to resolve timestamps to ticks for those cases where zero
error is required.

Add an end2end test for GPU timestamp calibration on D3D12 backend.

Disable timestamp period calculation on Device when the
DisableTimestampQueryConversion is enabled.

Bug: dawn:1305
Change-Id: I31ee6b4c1686d5dd2ac29ccb0bd398e650481c26
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/81023
Reviewed-by: Shrek Shao <shrekshao@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Austin Eng <enga@chromium.org>
This commit is contained in:
Li Hao 2022-02-23 17:50:35 +00:00 committed by Dawn LUCI CQ
parent eb7ca59cbd
commit 7abcadfce6
8 changed files with 137 additions and 5 deletions

View File

@ -1140,7 +1140,8 @@ namespace dawn::native {
cmd->destinationOffset = destinationOffset;
// Encode internal compute pipeline for timestamp query
if (querySet->GetQueryType() == wgpu::QueryType::Timestamp) {
if (querySet->GetQueryType() == wgpu::QueryType::Timestamp &&
!GetDevice()->IsToggleEnabled(Toggle::DisableTimestampQueryConversion)) {
DAWN_TRY(EncodeTimestampsToNanosecondsConversion(
this, querySet, firstQuery, queryCount, destination, destinationOffset));
}

View File

@ -237,6 +237,10 @@ namespace dawn::native {
"command queue, and the information includes system time, CPU timestamp, GPU "
"timestamp, and their frequency.",
"https://crbug.com/dawn/1264"}},
{Toggle::DisableTimestampQueryConversion,
{"disable_timestamp_query_conversion",
"Resolve timestamp queries into ticks instead of nanoseconds.",
"https://crbug.com/dawn/1305"}},
// Dummy comment to separate the }} so it is clearer what to copy-paste to add a toggle.
}};

View File

@ -62,6 +62,7 @@ namespace dawn::native {
UseDummyFragmentInVertexOnlyPipeline,
FxcOptimizations,
RecordDetailedTimingInTraceEvents,
DisableTimestampQueryConversion,
EnumCount,
InvalidEnum = EnumCount,

View File

@ -78,7 +78,8 @@ namespace dawn::native::d3d12 {
CheckHRESULT(mD3d12Device->CreateCommandQueue(&queueDesc, IID_PPV_ARGS(&mCommandQueue)),
"D3D12 create command queue"));
if (IsFeatureEnabled(Feature::TimestampQuery)) {
if (IsFeatureEnabled(Feature::TimestampQuery) &&
!IsToggleEnabled(Toggle::DisableTimestampQueryConversion)) {
// Get GPU timestamp counter frequency (in ticks/second). This fails if the specified
// command queue doesn't support timestamps. D3D12_COMMAND_LIST_TYPE_DIRECT queues
// always support timestamps except where there are bugs in Windows container and vGPU

View File

@ -134,7 +134,8 @@ namespace dawn::native::metal {
DAWN_TRY(mCommandContext.PrepareNextCommandBuffer(*mCommandQueue));
if (IsFeatureEnabled(Feature::TimestampQuery)) {
if (IsFeatureEnabled(Feature::TimestampQuery) &&
!IsToggleEnabled(Toggle::DisableTimestampQueryConversion)) {
// Make a best guess of timestamp period based on device vendor info, and converge it to
// an accurate value by the following calculations.
mTimestampPeriod = gpu_info::IsIntel(GetAdapter()->GetVendorId()) ? 83.333f : 1.0f;

View File

@ -533,6 +533,7 @@ source_set("white_box_tests_sources") {
if (dawn_enable_d3d12) {
sources += [
"white_box/D3D12DescriptorHeapTests.cpp",
"white_box/D3D12GPUTimestampCalibrationTests.cpp",
"white_box/D3D12ResidencyTests.cpp",
"white_box/D3D12ResourceHeapTests.cpp",
]

View File

@ -0,0 +1,118 @@
// Copyright 2022 The Dawn Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dawn/tests/DawnTest.h"
#include "dawn/native/Buffer.h"
#include "dawn/native/CommandEncoder.h"
#include "dawn/native/d3d12/DeviceD3D12.h"
#include "dawn/utils/WGPUHelpers.h"
namespace {
class ExpectBetweenTimestamps : public detail::Expectation {
public:
~ExpectBetweenTimestamps() override = default;
ExpectBetweenTimestamps(uint64_t value0, uint64_t value1) {
mValue0 = value0;
mValue1 = value1;
}
// Expect the actual results are between mValue0 and mValue1.
testing::AssertionResult Check(const void* data, size_t size) override {
const uint64_t* actual = static_cast<const uint64_t*>(data);
for (size_t i = 0; i < size / sizeof(uint64_t); ++i) {
if (actual[i] < mValue0 || actual[i] > mValue1) {
return testing::AssertionFailure()
<< "Expected data[" << i << "] to be between " << mValue0 << " and "
<< mValue1 << ", actual " << actual[i] << std::endl;
}
}
return testing::AssertionSuccess();
}
private:
uint64_t mValue0;
uint64_t mValue1;
};
} // anonymous namespace
using namespace dawn::native::d3d12;
class D3D12GPUTimestampCalibrationTests : public DawnTest {
protected:
void SetUp() override {
DawnTest::SetUp();
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
// Requires that timestamp query feature is enabled and timestamp query conversion is
// disabled.
DAWN_TEST_UNSUPPORTED_IF(!SupportsFeatures({wgpu::FeatureName::TimestampQuery}) ||
!HasToggleEnabled("disable_timestamp_query_conversion"));
}
std::vector<wgpu::FeatureName> GetRequiredFeatures() override {
std::vector<wgpu::FeatureName> requiredFeatures = {};
if (SupportsFeatures({wgpu::FeatureName::TimestampQuery})) {
requiredFeatures.push_back(wgpu::FeatureName::TimestampQuery);
}
return requiredFeatures;
}
};
// Check that the timestamps got by timestamp query are between the two timestamps from
// GetClockCalibration() after the timestamp conversion is disabled.
TEST_P(D3D12GPUTimestampCalibrationTests, TimestampsInOrder) {
constexpr uint32_t kQueryCount = 2;
wgpu::QuerySetDescriptor querySetDescriptor;
querySetDescriptor.count = kQueryCount;
querySetDescriptor.type = wgpu::QueryType::Timestamp;
wgpu::QuerySet querySet = device.CreateQuerySet(&querySetDescriptor);
wgpu::BufferDescriptor bufferDescriptor;
bufferDescriptor.size = kQueryCount * sizeof(uint64_t);
bufferDescriptor.usage =
wgpu::BufferUsage::QueryResolve | wgpu::BufferUsage::CopySrc | wgpu::BufferUsage::CopyDst;
wgpu::Buffer destination = device.CreateBuffer(&bufferDescriptor);
wgpu::CommandEncoder encoder = device.CreateCommandEncoder();
encoder.WriteTimestamp(querySet, 0);
encoder.WriteTimestamp(querySet, 1);
wgpu::CommandBuffer commands = encoder.Finish();
Device* d3DDevice = reinterpret_cast<Device*>(device.Get());
uint64_t gpuTimestamp0, gpuTimestamp1;
uint64_t cpuTimestamp0, cpuTimestamp1;
d3DDevice->GetCommandQueue()->GetClockCalibration(&gpuTimestamp0, &cpuTimestamp0);
queue.Submit(1, &commands);
WaitForAllOperations();
d3DDevice->GetCommandQueue()->GetClockCalibration(&gpuTimestamp1, &cpuTimestamp1);
// Separate resolve queryset to reduce the execution time of the queue with WriteTimestamp,
// so that the timestamp in the querySet will be closer to both gpuTimestamps from
// GetClockCalibration.
wgpu::CommandEncoder resolveEncoder = device.CreateCommandEncoder();
resolveEncoder.ResolveQuerySet(querySet, 0, kQueryCount, destination, 0);
wgpu::CommandBuffer resolveCommands = resolveEncoder.Finish();
queue.Submit(1, &resolveCommands);
EXPECT_BUFFER(destination, 0, kQueryCount * sizeof(uint64_t),
new ExpectBetweenTimestamps(gpuTimestamp0, gpuTimestamp1));
}
DAWN_INSTANTIATE_TEST(D3D12GPUTimestampCalibrationTests,
D3D12Backend({"disable_timestamp_query_conversion"}));

View File

@ -84,6 +84,13 @@ constexpr static uint64_t kSentinelValue = ~uint64_t(0u);
class QueryInternalShaderTests : public DawnTest {
protected:
void SetUp() override {
DawnTest::SetUp();
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
DAWN_TEST_UNSUPPORTED_IF(HasToggleEnabled("disable_timestamp_query_conversion"));
}
// Original timestamp values in query set for testing
const std::vector<uint64_t> querySetValues = {
kSentinelValue, // garbage data which is not written at beginning
@ -190,8 +197,6 @@ TEST_P(QueryInternalShaderTests, TimestampComputeShader) {
// TODO(crbug.com/dawn/741): Test output is wrong with D3D12 + WARP.
DAWN_SUPPRESS_TEST_IF(IsD3D12() && IsWARP());
DAWN_TEST_UNSUPPORTED_IF(UsesWire());
constexpr std::array<float, 5> kPeriodsToTest = {
1,
7,