Query API: Re-enable Timestamp Query on Metal
Add timestamp query back in Metal supported extensions, and calculate the timestamp period based on CPU timestamps and GPU timestamps sampled on device. There is a crash issue (dawn:545) on macOS 10.15 on AMD devices, but cannot be reproduced on macOS 11.0+, we can just disable it on AMD with macOS 10.15 in the following CL. Bug: dawn:434 Change-Id: Icb4823e7c3115776e64c6a41fd0aea0f6536ccdf Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/51720 Commit-Queue: Hao Li <hao.x.li@intel.com> Reviewed-by: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
adc5cddde0
commit
84481bbb35
|
@ -221,10 +221,9 @@ namespace dawn_native { namespace metal {
|
|||
if ([*mDevice supportsFamily:MTLGPUFamilyMac2] ||
|
||||
[*mDevice supportsFamily:MTLGPUFamilyApple5]) {
|
||||
mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
|
||||
|
||||
// TODO(crbug.com/dawn/434): Not enable timestamp query here becuase it's not
|
||||
// clear how to convert timestamps to nanoseconds on Metal.
|
||||
// See https://github.com/gpuweb/gpuweb/issues/1325
|
||||
// TODO(crbug.com/dawn/545): Crash occurs if we only call WriteTimestamp in a
|
||||
// command encoder without any copy commands on Metal on AMD GPU.
|
||||
mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
|
||||
}
|
||||
}
|
||||
if (@available(macOS 10.11, iOS 11.0, *)) {
|
||||
|
|
|
@ -32,6 +32,10 @@
|
|||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
||||
namespace {
|
||||
struct KalmanInfo;
|
||||
}
|
||||
|
||||
class Device : public DeviceBase {
|
||||
public:
|
||||
static ResultOrError<Device*> Create(AdapterBase* adapter,
|
||||
|
@ -127,6 +131,15 @@ namespace dawn_native { namespace metal {
|
|||
// a different thread so we guard access to it with a mutex.
|
||||
std::mutex mLastSubmittedCommandsMutex;
|
||||
NSPRef<id<MTLCommandBuffer>> mLastSubmittedCommands;
|
||||
|
||||
// The current estimation of timestamp period
|
||||
float mTimestampPeriod = 1.0f;
|
||||
// The base of CPU timestamp and GPU timestamp to measure the linear regression between GPU
|
||||
// and CPU timestamps.
|
||||
MTLTimestamp mCpuTimestamp API_AVAILABLE(macos(10.15), ios(14.0)) = 0;
|
||||
MTLTimestamp mGpuTimestamp API_AVAILABLE(macos(10.15), ios(14.0)) = 0;
|
||||
// The parameters for kalman filter
|
||||
std::unique_ptr<KalmanInfo> mKalmanInfo;
|
||||
};
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -42,6 +42,69 @@
|
|||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
||||
namespace {
|
||||
|
||||
// The time interval for each round of kalman filter
|
||||
static constexpr uint64_t kFilterIntervalInMs = static_cast<uint64_t>(NSEC_PER_SEC / 10);
|
||||
|
||||
struct KalmanInfo {
|
||||
float filterValue; // The estimation value
|
||||
float kalmanGain; // The kalman gain
|
||||
float R; // The covariance of the observation noise
|
||||
float P; // The a posteriori estimate covariance
|
||||
};
|
||||
|
||||
// A simplified kalman filter for estimating timestamp period based on measured values
|
||||
float KalmanFilter(KalmanInfo* info, float measuredValue) {
|
||||
// Optimize kalman gain
|
||||
info->kalmanGain = info->P / (info->P + info->R);
|
||||
|
||||
// Correct filter value
|
||||
info->filterValue =
|
||||
info->kalmanGain * measuredValue + (1.0 - info->kalmanGain) * info->filterValue;
|
||||
// Update estimate covariance
|
||||
info->P = (1.0f - info->kalmanGain) * info->P;
|
||||
return info->filterValue;
|
||||
}
|
||||
|
||||
void API_AVAILABLE(macos(10.15), ios(14))
|
||||
UpdateTimestampPeriod(id<MTLDevice> device,
|
||||
KalmanInfo* info,
|
||||
MTLTimestamp* cpuTimestampStart,
|
||||
MTLTimestamp* gpuTimestampStart,
|
||||
float* timestampPeriod) {
|
||||
// The filter value is converged to an optimal value when the kalman gain is less than
|
||||
// 0.01. At this time, the weight of the measured value is too small to change the next
|
||||
// filter value, the sampling and calculations do not need to continue anymore.
|
||||
if (info->kalmanGain < 0.01f) {
|
||||
return;
|
||||
}
|
||||
|
||||
MTLTimestamp cpuTimestampEnd = 0, gpuTimestampEnd = 0;
|
||||
[device sampleTimestamps:&cpuTimestampEnd gpuTimestamp:&gpuTimestampEnd];
|
||||
|
||||
// Update the timestamp start values when timestamp reset happens
|
||||
if (cpuTimestampEnd < *cpuTimestampStart || gpuTimestampEnd < *gpuTimestampStart) {
|
||||
*cpuTimestampStart = cpuTimestampEnd;
|
||||
*gpuTimestampStart = gpuTimestampEnd;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cpuTimestampEnd - *cpuTimestampStart >= kFilterIntervalInMs) {
|
||||
// The measured timestamp period
|
||||
float measurement = (cpuTimestampEnd - *cpuTimestampStart) /
|
||||
static_cast<float>(gpuTimestampEnd - *gpuTimestampStart);
|
||||
|
||||
// Measurement update
|
||||
*timestampPeriod = KalmanFilter(info, measurement);
|
||||
|
||||
*cpuTimestampStart = cpuTimestampEnd;
|
||||
*gpuTimestampStart = gpuTimestampEnd;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
ResultOrError<Device*> Device::Create(AdapterBase* adapter,
|
||||
NSPRef<id<MTLDevice>> mtlDevice,
|
||||
|
@ -70,6 +133,27 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
mCommandQueue.Acquire([*mMtlDevice newCommandQueue]);
|
||||
|
||||
if (GetAdapter()->GetSupportedExtensions().IsEnabled(Extension::TimestampQuery)) {
|
||||
// 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()->GetPCIInfo().vendorId) ? 83.333f : 1.0f;
|
||||
|
||||
// Initialize kalman filter parameters
|
||||
mKalmanInfo = std::make_unique<KalmanInfo>();
|
||||
mKalmanInfo->filterValue = 0.0f;
|
||||
mKalmanInfo->kalmanGain = 0.5f;
|
||||
mKalmanInfo->R =
|
||||
0.0001f; // The smaller this value is, the smaller the error of measured value is,
|
||||
// the more we can trust the measured value.
|
||||
mKalmanInfo->P = 1.0f;
|
||||
|
||||
if (@available(macos 10.15, iOS 14.0, *)) {
|
||||
// Sample CPU timestamp and GPU timestamp for first time at device creation
|
||||
[*mMtlDevice sampleTimestamps:&mCpuTimestamp gpuTimestamp:&mGpuTimestamp];
|
||||
}
|
||||
}
|
||||
|
||||
return DeviceBase::Initialize(new Queue(this));
|
||||
}
|
||||
|
||||
|
@ -193,6 +277,14 @@ namespace dawn_native { namespace metal {
|
|||
SubmitPendingCommandBuffer();
|
||||
}
|
||||
|
||||
// Just run timestamp period calculation when timestamp extension is enabled.
|
||||
if (GetAdapter()->GetSupportedExtensions().IsEnabled(Extension::TimestampQuery)) {
|
||||
if (@available(macos 10.15, iOS 14.0, *)) {
|
||||
UpdateTimestampPeriod(GetMTLDevice(), mKalmanInfo.get(), &mCpuTimestamp,
|
||||
&mGpuTimestamp, &mTimestampPeriod);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -372,7 +464,7 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
float Device::GetTimestampPeriodInNS() const {
|
||||
return 1.0f;
|
||||
return mTimestampPeriod;
|
||||
}
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -534,8 +534,8 @@ TEST_P(TimestampQueryTests, QuerySetCreation) {
|
|||
|
||||
// Test calling timestamp query from command encoder
|
||||
TEST_P(TimestampQueryTests, TimestampOnCommandEncoder) {
|
||||
// TODO(hao.x.li@intel.com): Crash occurs if we only call WriteTimestamp in a command encoder
|
||||
// without any copy commands on Metal on AMD GPU. See https://crbug.com/dawn/545.
|
||||
// TODO(crbug.com/dawn/545): Crash occurs if we only call WriteTimestamp in a command encoder
|
||||
// without any copy commands on Metal on AMD GPU.
|
||||
DAWN_SUPPRESS_TEST_IF(IsMetal() && IsAMD());
|
||||
|
||||
constexpr uint32_t kQueryCount = 2;
|
||||
|
|
Loading…
Reference in New Issue