-
Notifications
You must be signed in to change notification settings - Fork 345
Description
The documentation for [MTLCounterResultTimestamp timestamp] says it's "A timestamp.", but does not specify its unit.
When this feature was first supported in macOS 10.15, I saw there was a message said the timestamp is in nanoseconds if we printed the [MTLCounterResultTimestamp timestamp] in XCode, in the latest macOS, the message is gone. I suppose it's still in nanoseconds but it doesn't match with the perf I'm seeing (expect close to 48ms but get 0.8ms).
I think Metal should have a factor to declare how much time passes for a timestamp value to be incremented by 1 like Vulkan and D3D12. Unfortunately, nowhere in the documentation does this.
I did some searching about Metal GPU timers, someone also encountered the same problem and gave a solution at here. To put it simply, call [MTLDevice sampleTimestamps:gpuTimestamp:] twice to sample the timestamps from both the CPU and GPU, in order to derive the GPU timestamp period calibrated against the CPU period. Because CPU timestamps are also in some unit, we also need to use mach_timebase_info() to get the factor to convert to nanoseconds. Example code:
MTLTimestamp m_cpu_timestamp, m_gpu_timestamp;
MTLTimestamp cpu_timestamp, gpu_timestamp;
double m_gpu_cpu_timestamp_factor;
[m_device sampleTimestamps:&m_cpu_timestamp gpuTimestamp:&m_gpu_timestamp];
[m_device sampleTimestamps:&cpu_timestamp gpuTimestamp:&gpu_timestamp];
if(cpu_timestamp > m_cpu_timestamp && gpu_timestamp > m_gpu_timestamp)
{
const double cpu_delta = cpu_timestamp - m_cpu_timestamp;
const double gpu_delta = gpu_timestamp - m_gpu_timestamp;
m_gpu_cpu_timestamp_factor = cpu_delta / gpu_delta;
}
Assuming that begin and end are the timestamps retrieved from [MTLCounterSampleBuffer resolveCounterRange:]
const uint64_t delta = (end - begin) * m_gpu_cpu_timestamp_factor;
mach_timebase_info_data_t time_info;
mach_timebase_info(&time_info);
const uint64_t nanoseconds = delta * time_info.numer / time_info.denom;
The m_gpu_cpu_timestamp_factor is in the range of 51.978622 to 52.294118, the time_info.numer and time_info.denom are 1 on my device. Using the above perf data , the 0.8 * m_gpu_cpu_timestamp_factor * time_info.numer / time_info.denom is about 42ms, close to the value we expected.
Is this the correct way to resolve timestamps to nanoseconds? If not, what is the official one?