i965: perf: add support for userspace configurations
authorLionel Landwerlin <lionel.g.landwerlin@intel.com>
Tue, 25 Jul 2017 16:22:58 +0000 (17:22 +0100)
committerLionel Landwerlin <lionel.g.landwerlin@intel.com>
Tue, 28 Nov 2017 13:34:04 +0000 (13:34 +0000)
This allows us to deploy new configurations without touching the
kernel.

v2: Detect loadable configs without creating one (Chris)

Signed-off-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
src/mesa/drivers/dri/i965/brw_performance_query.c

index 4b585c95b7d6cf781423240bffd9e4e110fc463b..cdae18c627538c131432069aa7845a34a38d1018 100644 (file)
@@ -1729,6 +1729,18 @@ read_file_uint64(const char *file, uint64_t *val)
     return true;
 }
 
+static void
+register_oa_config(struct brw_context *brw,
+                   const struct brw_perf_query_info *query,
+                   uint64_t config_id)
+{
+   struct brw_perf_query_info *registred_query = append_query_info(brw);
+   *registred_query = *query;
+   registred_query->oa_metrics_set_id = config_id;
+   DBG("metric set registred: id = %" PRIu64", guid = %s\n",
+       registred_query->oa_metrics_set_id, query->guid);
+}
+
 static void
 enumerate_sysfs_metrics(struct brw_context *brw, const char *sysfs_dev_dir)
 {
@@ -1761,7 +1773,6 @@ enumerate_sysfs_metrics(struct brw_context *brw, const char *sysfs_dev_dir)
       entry = _mesa_hash_table_search(brw->perfquery.oa_metrics_table,
                                       metric_entry->d_name);
       if (entry) {
-         struct brw_perf_query_info *query;
          uint64_t id;
 
          len = snprintf(buf, sizeof(buf), "%s/metrics/%s/id",
@@ -1776,12 +1787,7 @@ enumerate_sysfs_metrics(struct brw_context *brw, const char *sysfs_dev_dir)
             continue;
          }
 
-         query = append_query_info(brw);
-         *query = *(struct brw_perf_query_info *)entry->data;
-         query->oa_metrics_set_id = id;
-
-         DBG("metric set known by mesa: id = %" PRIu64"\n",
-             query->oa_metrics_set_id);
+         register_oa_config(brw, (const struct brw_perf_query_info *)entry->data, id);
       } else
          DBG("metric set not known by mesa (skipping)\n");
    }
@@ -1807,6 +1813,90 @@ read_sysfs_drm_device_file_uint64(struct brw_context *brw,
    return read_file_uint64(buf, value);
 }
 
+static bool
+kernel_has_dynamic_config_support(struct brw_context *brw,
+                                  const char *sysfs_dev_dir)
+{
+   __DRIscreen *screen = brw->screen->driScrnPriv;
+   struct hash_entry *entry;
+
+   hash_table_foreach(brw->perfquery.oa_metrics_table, entry) {
+      struct brw_perf_query_info *query = entry->data;
+      char config_path[256];
+      uint64_t config_id;
+
+      snprintf(config_path, sizeof(config_path),
+               "%s/metrics/%s/id", sysfs_dev_dir, query->guid);
+
+      /* Look for the test config, which we know we can't replace. */
+      if (read_file_uint64(config_path, &config_id) && config_id == 1) {
+         uint32_t mux_regs[] = { 0x9888 /* NOA_WRITE */, 0x0 };
+         struct drm_i915_perf_oa_config config;
+
+         memset(&config, 0, sizeof(config));
+
+         memcpy(config.uuid, query->guid, sizeof(config.uuid));
+
+         config.n_mux_regs = 1;
+         config.mux_regs_ptr = (uintptr_t) mux_regs;
+
+         if (ioctl(screen->fd, DRM_IOCTL_I915_PERF_REMOVE_CONFIG, &config_id) < 0 &&
+             errno == ENOENT)
+            return true;
+
+         break;
+      }
+   }
+
+   return false;
+}
+
+static void
+init_oa_configs(struct brw_context *brw, const char *sysfs_dev_dir)
+{
+   __DRIscreen *screen = brw->screen->driScrnPriv;
+   struct hash_entry *entry;
+
+   hash_table_foreach(brw->perfquery.oa_metrics_table, entry) {
+      const struct brw_perf_query_info *query = entry->data;
+      struct drm_i915_perf_oa_config config;
+      char config_path[256];
+      uint64_t config_id;
+      int ret;
+
+      snprintf(config_path, sizeof(config_path),
+               "%s/metrics/%s/id", sysfs_dev_dir, query->guid);
+
+      /* Don't recreate already loaded configs. */
+      if (read_file_uint64(config_path, &config_id)) {
+         register_oa_config(brw, query, config_id);
+         continue;
+      }
+
+      memset(&config, 0, sizeof(config));
+
+      memcpy(config.uuid, query->guid, sizeof(config.uuid));
+
+      config.n_mux_regs = query->n_mux_regs;
+      config.mux_regs_ptr = (uintptr_t) query->mux_regs;
+
+      config.n_boolean_regs = query->n_b_counter_regs;
+      config.boolean_regs_ptr = (uintptr_t) query->b_counter_regs;
+
+      config.n_flex_regs = query->n_flex_regs;
+      config.flex_regs_ptr = (uintptr_t) query->flex_regs;
+
+      ret = ioctl(screen->fd, DRM_IOCTL_I915_PERF_ADD_CONFIG, &config);
+      if (ret < 0) {
+         DBG("Failed to load \"%s\" (%s) metrics set in kernel: %s\n",
+             query->name, query->guid, strerror(errno));
+         continue;
+      }
+
+      register_oa_config(brw, query, config_id);
+   }
+}
+
 static bool
 init_oa_sys_vars(struct brw_context *brw, const char *sysfs_dev_dir)
 {
@@ -2054,7 +2144,10 @@ brw_init_perf_query_info(struct gl_context *ctx)
        */
       oa_register(brw);
 
-      enumerate_sysfs_metrics(brw, sysfs_dev_dir);
+      if (kernel_has_dynamic_config_support(brw, sysfs_dev_dir))
+         init_oa_configs(brw, sysfs_dev_dir);
+      else
+         enumerate_sysfs_metrics(brw, sysfs_dev_dir);
    }
 
    brw->perfquery.unaccumulated =