Mesa (main): v3d/simulator: implement performance counters

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Tue Aug 3 09:46:48 UTC 2021


Module: Mesa
Branch: main
Commit: 4f7043fc0ce158a5f555b6c0ec7f9818a60b8ce4
URL:    http://cgit.freedesktop.org/mesa/mesa/commit/?id=4f7043fc0ce158a5f555b6c0ec7f9818a60b8ce4

Author: Juan A. Suarez Romero <jasuarez at igalia.com>
Date:   Tue Apr 27 18:11:18 2021 +0200

v3d/simulator: implement performance counters

Add support for performance counters when using the simulator.

v2 (Iago):
 - Remove brackets from single-line conditionals
 - Rename channel to channels
 - Ensure perfmon start/stop function is implemented in all versions
 - Use an array for perfmons instead of hash table
 - Implement performance counters in CSD

v3 (Iago):
 - Rename PERFMON_CHUNKS to PERFMONS_ALLOC_SIZE.
 - Merge increasing lastid and ensuring space in a single function.

v4 (Iago):
 - Assert perfid <= perfmons_size.

v7 (Iago):
 - Do not stop perfmon on each submission

v8 (Iago):
 - Add comment about stopping the perfmon when retrieving values.

Reviewed-by: Iago Toral Quiroga <itoral at igalia.com>
Signed-off-by: Juan A. Suarez Romero <jasuarez at igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10666>

---

 src/broadcom/simulator/v3d_simulator.c  | 157 ++++++++++++++++++++++++++++++++
 src/broadcom/simulator/v3dx_simulator.c |  47 +++++++++-
 src/broadcom/simulator/v3dx_simulator.h |   6 ++
 3 files changed, 209 insertions(+), 1 deletion(-)

diff --git a/src/broadcom/simulator/v3d_simulator.c b/src/broadcom/simulator/v3d_simulator.c
index a6a057d80f0..494e5bb4475 100644
--- a/src/broadcom/simulator/v3d_simulator.c
+++ b/src/broadcom/simulator/v3d_simulator.c
@@ -87,6 +87,9 @@ static struct v3d_simulator_state {
         /** Mapping from GEM fd to struct v3d_simulator_file * */
         struct hash_table *fd_map;
 
+        /** Last performance monitor ID. */
+        uint32_t last_perfid;
+
         struct util_dynarray bin_oom;
         int refcount;
 } sim_state = {
@@ -100,6 +103,11 @@ struct v3d_simulator_file {
         /** Mapping from GEM handle to struct v3d_simulator_bo * */
         struct hash_table *bo_map;
 
+        /** Dynamic array with performance monitors */
+        struct v3d_simulator_perfmon **perfmons;
+        uint32_t perfmons_size;
+        uint32_t active_perfid;
+
         struct mem_block *gmp;
         void *gmp_vaddr;
 
@@ -121,12 +129,34 @@ struct v3d_simulator_bo {
         int handle;
 };
 
+struct v3d_simulator_perfmon {
+        uint32_t ncounters;
+        uint8_t counters[DRM_V3D_MAX_PERF_COUNTERS];
+        uint64_t values[DRM_V3D_MAX_PERF_COUNTERS];
+};
+
 static void *
 int_to_key(int key)
 {
         return (void *)(uintptr_t)key;
 }
 
+#define PERFMONS_ALLOC_SIZE 100
+
+static uint32_t
+perfmons_next_id(struct v3d_simulator_file *sim_file) {
+        sim_state.last_perfid++;
+        if (sim_state.last_perfid > sim_file->perfmons_size) {
+                sim_file->perfmons_size += PERFMONS_ALLOC_SIZE;
+                sim_file->perfmons = reralloc(sim_file,
+                                              sim_file->perfmons,
+                                              struct v3d_simulator_perfmon *,
+                                              sim_file->perfmons_size);
+        }
+
+        return sim_state.last_perfid;
+}
+
 static struct v3d_simulator_file *
 v3d_get_simulator_file_for_fd(int fd)
 {
@@ -357,6 +387,46 @@ v3d_simulator_unpin_bos(struct v3d_simulator_file *file,
         return 0;
 }
 
+static struct v3d_simulator_perfmon *
+v3d_get_simulator_perfmon(int fd, uint32_t perfid)
+{
+        if (!perfid || perfid > sim_state.last_perfid)
+                return NULL;
+
+        struct v3d_simulator_file *file = v3d_get_simulator_file_for_fd(fd);
+
+        mtx_lock(&sim_state.mutex);
+        assert(perfid <= file->perfmons_size);
+        struct v3d_simulator_perfmon *perfmon = file->perfmons[perfid - 1];
+        mtx_unlock(&sim_state.mutex);
+
+        return perfmon;
+}
+
+static void
+v3d_simulator_perfmon_switch(int fd, uint32_t perfid)
+{
+        struct v3d_simulator_file *file = v3d_get_simulator_file_for_fd(fd);
+        struct v3d_simulator_perfmon *perfmon;
+
+        if (perfid == file->active_perfid)
+                return;
+
+        perfmon = v3d_get_simulator_perfmon(fd, file->active_perfid);
+        if (perfmon)
+                v3d41_simulator_perfmon_stop(sim_state.v3d,
+                                             perfmon->ncounters,
+                                             perfmon->values);
+
+        perfmon = v3d_get_simulator_perfmon(fd, perfid);
+        if (perfmon)
+                v3d41_simulator_perfmon_start(sim_state.v3d,
+                                              perfmon->ncounters,
+                                              perfmon->counters);
+
+        file->active_perfid = perfid;
+}
+
 static int
 v3d_simulator_submit_cl_ioctl(int fd, struct drm_v3d_submit_cl *submit)
 {
@@ -369,6 +439,9 @@ v3d_simulator_submit_cl_ioctl(int fd, struct drm_v3d_submit_cl *submit)
 
         mtx_lock(&sim_state.submit_lock);
         bin_fd = fd;
+
+        v3d_simulator_perfmon_switch(fd, submit->perfmon_id);
+
         if (sim_state.ver >= 41)
                 v3d41_simulator_submit_cl_ioctl(sim_state.v3d, submit, file->gmp->ofs);
         else
@@ -530,6 +603,8 @@ v3d_simulator_submit_csd_ioctl(int fd, struct drm_v3d_submit_csd *args)
         for (int i = 0; i < args->bo_handle_count; i++)
                 v3d_simulator_copy_in_handle(file, bo_handles[i]);
 
+        v3d_simulator_perfmon_switch(fd, args->perfmon_id);
+
         if (sim_state.ver >= 41)
                 ret = v3d41_simulator_submit_csd_ioctl(sim_state.v3d, args,
                                                        file->gmp->ofs);
@@ -542,6 +617,79 @@ v3d_simulator_submit_csd_ioctl(int fd, struct drm_v3d_submit_csd *args)
         return ret;
 }
 
+static int
+v3d_simulator_perfmon_create_ioctl(int fd, struct drm_v3d_perfmon_create *args)
+{
+        struct v3d_simulator_file *file = v3d_get_simulator_file_for_fd(fd);
+
+        if (args->ncounters == 0 ||
+            args->ncounters > DRM_V3D_MAX_PERF_COUNTERS)
+                return -EINVAL;
+
+        struct v3d_simulator_perfmon *perfmon = rzalloc(file,
+                                                        struct v3d_simulator_perfmon);
+
+        perfmon->ncounters = args->ncounters;
+        for (int i = 0; i < args->ncounters; i++) {
+                if (args->counters[i] >= V3D_PERFCNT_NUM) {
+                        ralloc_free(perfmon);
+                        return -EINVAL;
+                } else {
+                        perfmon->counters[i] = args->counters[i];
+                }
+        }
+
+        mtx_lock(&sim_state.mutex);
+        args->id = perfmons_next_id(file);
+        file->perfmons[args->id - 1] = perfmon;
+        mtx_unlock(&sim_state.mutex);
+
+        return 0;
+}
+
+static int
+v3d_simulator_perfmon_destroy_ioctl(int fd, struct drm_v3d_perfmon_destroy *args)
+{
+        struct v3d_simulator_file *file = v3d_get_simulator_file_for_fd(fd);
+        struct v3d_simulator_perfmon *perfmon =
+                v3d_get_simulator_perfmon(fd, args->id);
+
+        if (!perfmon)
+                return -EINVAL;
+
+        mtx_lock(&sim_state.mutex);
+        file->perfmons[args->id - 1] = NULL;
+        mtx_unlock(&sim_state.mutex);
+
+        ralloc_free(perfmon);
+
+        return 0;
+}
+
+static int
+v3d_simulator_perfmon_get_values_ioctl(int fd, struct drm_v3d_perfmon_get_values *args)
+{
+        struct v3d_simulator_file *file = v3d_get_simulator_file_for_fd(fd);
+
+        mtx_lock(&sim_state.submit_lock);
+
+        /* Stop the perfmon if it is still active */
+        if (args->id == file->active_perfid)
+                v3d_simulator_perfmon_switch(fd, 0);
+
+        mtx_unlock(&sim_state.submit_lock);
+
+        struct v3d_simulator_perfmon *perfmon =
+                v3d_get_simulator_perfmon(fd, args->id);
+
+        if (!perfmon)
+                return -EINVAL;
+
+        memcpy((void *)args->values_ptr, perfmon->values, perfmon->ncounters * sizeof(uint64_t));
+
+        return 0;
+}
+
 int
 v3d_simulator_ioctl(int fd, unsigned long request, void *args)
 {
@@ -575,6 +723,15 @@ v3d_simulator_ioctl(int fd, unsigned long request, void *args)
         case DRM_IOCTL_V3D_SUBMIT_CSD:
                 return v3d_simulator_submit_csd_ioctl(fd, args);
 
+        case DRM_IOCTL_V3D_PERFMON_CREATE:
+                return v3d_simulator_perfmon_create_ioctl(fd, args);
+
+        case DRM_IOCTL_V3D_PERFMON_DESTROY:
+                return v3d_simulator_perfmon_destroy_ioctl(fd, args);
+
+        case DRM_IOCTL_V3D_PERFMON_GET_VALUES:
+                return v3d_simulator_perfmon_get_values_ioctl(fd, args);
+
         case DRM_IOCTL_GEM_OPEN:
         case DRM_IOCTL_GEM_FLINK:
                 return drmIoctl(fd, request, args);
diff --git a/src/broadcom/simulator/v3dx_simulator.c b/src/broadcom/simulator/v3dx_simulator.c
index 0fd090d5788..07bbbe2f8c9 100644
--- a/src/broadcom/simulator/v3dx_simulator.c
+++ b/src/broadcom/simulator/v3dx_simulator.c
@@ -267,7 +267,7 @@ v3dX(simulator_get_param_ioctl)(struct v3d_hw *v3d,
                 args->value = 1;
                 return 0;
         case DRM_V3D_PARAM_SUPPORTS_PERFMON:
-                args->value = 0;
+                args->value = V3D_VERSION >= 41;
                 return 0;
         }
 
@@ -501,4 +501,49 @@ v3dX(simulator_submit_cl_ioctl)(struct v3d_hw *v3d,
         }
 }
 
+#if V3D_VERSION >= 41
+#define V3D_PCTR_0_PCTR_N(x) (V3D_PCTR_0_PCTR0 + 4 * (x))
+#define V3D_PCTR_0_SRC_N(x) (V3D_PCTR_0_SRC_0_3 + 4 * (x))
+#define V3D_PCTR_0_SRC_N_SHIFT(x) ((x) * 8)
+#define V3D_PCTR_0_SRC_N_MASK(x) (BITFIELD_RANGE(V3D_PCTR_0_SRC_N_SHIFT(x), \
+                                                 V3D_PCTR_0_SRC_N_SHIFT(x) + 6))
+#endif
+
+void
+v3dX(simulator_perfmon_start)(struct v3d_hw *v3d,
+                              uint32_t ncounters,
+                              uint8_t *events)
+{
+#if V3D_VERSION >= 41
+        int i, j;
+        uint32_t source;
+        uint32_t mask = BITFIELD_RANGE(0, ncounters);
+
+        for (i = 0; i < ncounters; i+=4) {
+                source = i / 4;
+                uint32_t channels = 0;
+                for (j = 0; j < 4 && (i + j) < ncounters; j++)
+                        channels |= events[i + j] << V3D_PCTR_0_SRC_N_SHIFT(j);
+                V3D_WRITE(V3D_PCTR_0_SRC_N(source), channels);
+        }
+        V3D_WRITE(V3D_PCTR_0_CLR, mask);
+        V3D_WRITE(V3D_PCTR_0_OVERFLOW, mask);
+        V3D_WRITE(V3D_PCTR_0_EN, mask);
+#endif
+}
+
+void v3dX(simulator_perfmon_stop)(struct v3d_hw *v3d,
+                                  uint32_t ncounters,
+                                  uint64_t *values)
+{
+#if V3D_VERSION >= 41
+        int i;
+
+        for (i = 0; i < ncounters; i++)
+                values[i] += V3D_READ(V3D_PCTR_0_PCTR_N(i));
+
+        V3D_WRITE(V3D_PCTR_0_EN, 0);
+#endif
+}
+
 #endif /* USE_V3D_SIMULATOR */
diff --git a/src/broadcom/simulator/v3dx_simulator.h b/src/broadcom/simulator/v3dx_simulator.h
index 2c623d79a83..145ae59c21e 100644
--- a/src/broadcom/simulator/v3dx_simulator.h
+++ b/src/broadcom/simulator/v3dx_simulator.h
@@ -44,3 +44,9 @@ int v3dX(simulator_submit_tfu_ioctl)(struct v3d_hw *v3d,
 int v3dX(simulator_submit_csd_ioctl)(struct v3d_hw *v3d,
                                      struct drm_v3d_submit_csd *args,
                                      uint32_t gmp_offset);
+void v3dX(simulator_perfmon_start)(struct v3d_hw *v3d,
+                                   uint32_t ncounters,
+                                   uint8_t *events);
+void v3dX(simulator_perfmon_stop)(struct v3d_hw *v3d,
+                                  uint32_t ncounters,
+                                  uint64_t *values);



More information about the mesa-commit mailing list