asahi: Fix agx_gpu_time_to_ns & implement DRM_ASAHI_GET_TIME

agx_gpu_time_to_ns() was broken since it was overflowing the u64
timestamp after just ~10 minutes. Fix that by automatically computing a
reduced conversion fraction, and add support for DRM_ASAHI_GET_TIME
where supported (replacing the CPU timer hack).

Signed-off-by: Asahi Lina <lina@asahilina.net>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/32434>
This commit is contained in:
Asahi Lina
2024-11-29 04:35:07 +09:00
committed by Marge Bot
parent 925eca02c4
commit 07e836b932
2 changed files with 39 additions and 1 deletions

View File

@@ -394,6 +394,27 @@ const agx_device_ops_t agx_device_drm_ops = {
.submit = agx_submit,
};
static uint64_t
gcd(uint64_t n, uint64_t m)
{
while (n != 0) {
uint64_t remainder = m % n;
m = n;
n = remainder;
}
return m;
}
static void
agx_init_timestamps(struct agx_device *dev)
{
uint64_t ts_gcd = gcd(dev->params.timer_frequency_hz, NSEC_PER_SEC);
dev->timestamp_to_ns.num = NSEC_PER_SEC / ts_gcd;
dev->timestamp_to_ns.den = dev->params.timer_frequency_hz / ts_gcd;
}
bool
agx_open_device(void *memctx, struct agx_device *dev)
{
@@ -534,6 +555,8 @@ agx_open_device(void *memctx, struct agx_device *dev)
dev->agxdecode = agxdecode_new_context(dev->shader_base);
agx_init_timestamps(dev);
util_sparse_array_init(&dev->bo_map, sizeof(struct agx_bo), 512);
pthread_mutex_init(&dev->bo_map_lock, NULL);
@@ -745,6 +768,16 @@ agx_debug_fault(struct agx_device *dev, uint64_t addr)
uint64_t
agx_get_gpu_timestamp(struct agx_device *dev)
{
if (dev->params.feat_compat & DRM_ASAHI_FEAT_GETTIME) {
struct drm_asahi_get_time get_time = {.flags = 0, .extensions = 0};
int ret = asahi_simple_ioctl(dev, DRM_IOCTL_ASAHI_GET_TIME, &get_time);
if (ret) {
fprintf(stderr, "DRM_IOCTL_ASAHI_GET_TIME failed: %m\n");
} else {
return get_time.gpu_timestamp;
}
}
#if DETECT_ARCH_AARCH64
uint64_t ret;
__asm__ volatile("mrs \t%0, cntvct_el0" : "=r"(ret));

View File

@@ -156,6 +156,11 @@ struct agx_device {
/* Simplified device selection */
enum agx_chip chip;
struct {
uint64_t num;
uint64_t den;
} timestamp_to_ns;
};
static inline bool
@@ -200,7 +205,7 @@ uint64_t agx_get_gpu_timestamp(struct agx_device *dev);
static inline uint64_t
agx_gpu_time_to_ns(struct agx_device *dev, uint64_t gpu_time)
{
return (gpu_time * NSEC_PER_SEC) / dev->params.timer_frequency_hz;
return (gpu_time * dev->timestamp_to_ns.num) / dev->timestamp_to_ns.den;
}
void agx_get_device_uuid(const struct agx_device *dev, void *uuid);