这是indexloc提供的服务,不要输入任何密码
Skip to content

Query API: What is the GPU timestamp unit on Metal? #1325

@haoxli

Description

@haoxli

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions