[Mesa-dev] [RFC PATCH 1/8] nouveau: implement the nvif hardware performance counters interface

Samuel Pitoiset samuel.pitoiset at gmail.com
Mon Jun 22 13:53:12 PDT 2015


This commit implements the base interface for hardware performance
counters that will be shared between nv50 and nvc0 drivers.

TODO: Bump libdrm version of mesa when nvif will be merged.

Signed-off-by: Samuel Pitoiset <samuel.pitoiset at gmail.com>
---
 src/gallium/drivers/nouveau/Makefile.sources  |   2 +
 src/gallium/drivers/nouveau/nouveau_perfmon.c | 302 ++++++++++++++++++++++++++
 src/gallium/drivers/nouveau/nouveau_perfmon.h |  59 +++++
 src/gallium/drivers/nouveau/nouveau_screen.c  |   5 +
 src/gallium/drivers/nouveau/nouveau_screen.h  |   1 +
 5 files changed, 369 insertions(+)
 create mode 100644 src/gallium/drivers/nouveau/nouveau_perfmon.c
 create mode 100644 src/gallium/drivers/nouveau/nouveau_perfmon.h

diff --git a/src/gallium/drivers/nouveau/Makefile.sources b/src/gallium/drivers/nouveau/Makefile.sources
index 3fae3bc..3da0bdc 100644
--- a/src/gallium/drivers/nouveau/Makefile.sources
+++ b/src/gallium/drivers/nouveau/Makefile.sources
@@ -10,6 +10,8 @@ C_SOURCES := \
 	nouveau_heap.h \
 	nouveau_mm.c \
 	nouveau_mm.h \
+	nouveau_perfmon.c \
+	nouveau_perfmon.h \
 	nouveau_screen.c \
 	nouveau_screen.h \
 	nouveau_statebuf.h \
diff --git a/src/gallium/drivers/nouveau/nouveau_perfmon.c b/src/gallium/drivers/nouveau/nouveau_perfmon.c
new file mode 100644
index 0000000..3798612
--- /dev/null
+++ b/src/gallium/drivers/nouveau/nouveau_perfmon.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright 2015 Samuel Pitoiset
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <errno.h>
+
+#include "util/u_memory.h"
+
+#include "nouveau_debug.h"
+#include "nouveau_winsys.h"
+#include "nouveau_perfmon.h"
+
+static int
+nouveau_perfmon_query_sources(struct nouveau_perfmon *pm,
+                              struct nouveau_perfmon_dom *dom,
+                              struct nouveau_perfmon_sig *sig)
+{
+	struct nvif_perfmon_query_source_v0 args = {};
+
+	args.domain = dom->id;
+	args.signal = sig->signal;
+	do {
+		uint8_t prev_iter = args.iter;
+		struct nouveau_perfmon_src *src;
+		int ret;
+
+		ret = nouveau_object_mthd(pm->object, NVIF_PERFMON_V0_QUERY_SOURCE,
+				                    &args, sizeof(args));
+		if (ret)
+			return ret;
+
+		if (prev_iter) {
+			args.iter = prev_iter;
+			ret = nouveau_object_mthd(pm->object, NVIF_PERFMON_V0_QUERY_SOURCE,
+					                    &args, sizeof(args));
+			if (ret)
+				return ret;
+
+			src = CALLOC_STRUCT(nouveau_perfmon_src);
+			if (!src)
+				return -ENOMEM;
+
+#if 0
+			debug_printf("id   = %d\n", args.source);
+			debug_printf("name = %s\n", args.name);
+			debug_printf("mask = %08x\n", args.mask);
+			debug_printf("\n");
+#endif
+
+		   src->id = args.source;
+         strncpy(src->name, args.name, sizeof(src->name));
+			list_addtail(&src->head, &sig->sources);
+		}
+	} while (args.iter != 0xff);
+
+	return 0;
+}
+
+static int
+nouveau_perfmon_query_signals(struct nouveau_perfmon *pm,
+                              struct nouveau_perfmon_dom *dom)
+{
+   struct nvif_perfmon_query_signal_v0 args = {};
+
+   args.domain = dom->id;
+   do {
+      uint16_t prev_iter = args.iter;
+      struct nouveau_perfmon_sig *sig;
+      int ret;
+
+      ret = nouveau_object_mthd(pm->object, NVIF_PERFMON_V0_QUERY_SIGNAL,
+                                &args, sizeof(args));
+      if (ret)
+         return ret;
+
+      if (prev_iter) {
+         args.iter = prev_iter;
+         ret = nouveau_object_mthd(pm->object, NVIF_PERFMON_V0_QUERY_SIGNAL,
+                                   &args, sizeof(args));
+         if (ret)
+            return ret;
+
+         sig = CALLOC_STRUCT(nouveau_perfmon_sig);
+         if (!sig)
+            return -ENOMEM;
+         list_inithead(&sig->sources);
+
+#if 0
+         debug_printf("name      = %s\n", args.name);
+         debug_printf("signal    = 0x%02x\n", args.signal);
+         debug_printf("source_nr = %d\n", args.source_nr);
+         debug_printf("\n");
+#endif
+
+         sig->signal = args.signal;
+         strncpy(sig->name, args.name, sizeof(sig->name));
+         list_addtail(&sig->head, &dom->signals);
+
+         /* Query all available sources for this signal. */
+         if (args.source_nr > 0) {
+            ret = nouveau_perfmon_query_sources(pm, dom, sig);
+            if (ret)
+               return ret;
+         }
+      }
+   } while (args.iter != 0xffff);
+
+   return 0;
+}
+
+static int
+nouveau_perfmon_query_domains(struct nouveau_perfmon *pm)
+{
+   struct nvif_perfmon_query_domain_v0 args = {};
+
+   do {
+      uint8_t prev_iter = args.iter;
+      struct nouveau_perfmon_dom *dom;
+      int ret;
+
+      ret = nouveau_object_mthd(pm->object, NVIF_PERFMON_V0_QUERY_DOMAIN,
+                                &args, sizeof(args));
+      if (ret)
+         return ret;
+
+      if (prev_iter) {
+         args.iter = prev_iter;
+         ret = nouveau_object_mthd(pm->object, NVIF_PERFMON_V0_QUERY_DOMAIN,
+                                   &args, sizeof(args));
+         if (ret)
+            return ret;
+
+         dom = CALLOC_STRUCT(nouveau_perfmon_dom);
+         if (!dom)
+            return -ENOMEM;
+         list_inithead(&dom->signals);
+
+#if 0
+         debug_printf("id         = %d\n", args.id);
+         debug_printf("name       = %s\n", args.name);
+         debug_printf("counter_nr = %d\n", args.counter_nr);
+         debug_printf("signal_nr  = %d\n", args.signal_nr);
+         debug_printf("\n");
+#endif
+
+         dom->id              = args.id;
+         dom->max_active_cntr = args.counter_nr;
+         strncpy(dom->name, args.name, sizeof(dom->name));
+         list_addtail(&dom->head, &pm->domains);
+
+         /* Query all available signals for this domain. */
+         if (args.signal_nr > 0) {
+            ret = nouveau_perfmon_query_signals(pm, dom);
+            if (ret)
+               return ret;
+         }
+      }
+   } while (args.iter != 0xff);
+
+   return 0;
+}
+
+static void
+nouveau_perfmon_free_sources(struct nouveau_perfmon_sig *sig)
+{
+   struct nouveau_perfmon_src *src, *next;
+
+   LIST_FOR_EACH_ENTRY_SAFE(src, next, &sig->sources, head) {
+      list_del(&src->head);
+      free(src);
+   }
+}
+
+static void
+nouveau_perfmon_free_signals(struct nouveau_perfmon_dom *dom)
+{
+   struct nouveau_perfmon_sig *sig, *next;
+
+   LIST_FOR_EACH_ENTRY_SAFE(sig, next, &dom->signals, head) {
+      nouveau_perfmon_free_sources(sig);
+      list_del(&sig->head);
+      free(sig);
+   }
+}
+
+static void
+nouveau_perfmon_free_domains(struct nouveau_perfmon *pm)
+{
+   struct nouveau_perfmon_dom *dom, *next;
+
+   LIST_FOR_EACH_ENTRY_SAFE(dom, next, &pm->domains, head) {
+      nouveau_perfmon_free_signals(dom);
+      list_del(&dom->head);
+      free(dom);
+   }
+}
+
+struct nouveau_perfmon *
+nouveau_perfmon_create(struct nouveau_device *dev)
+{
+   struct nouveau_perfmon *pm = NULL;
+   int ret;
+
+   pm = CALLOC_STRUCT(nouveau_perfmon);
+   if (!pm) {
+       NOUVEAU_ERR("Failed to allocate pm struct!\n");
+       return NULL;
+   }
+   list_inithead(&pm->domains);
+
+   /* init handle for perfdom objects */
+   pm->handle = 0xbeef9751;
+
+   ret = nouveau_object_new(&dev->object, 0xbeef9750,
+                            NVIF_IOCTL_NEW_V0_PERFMON, NULL, 0, &pm->object);
+   if (ret)
+      goto fail;
+
+   /* Query all available domains, signals and sources for this device. */
+   ret = nouveau_perfmon_query_domains(pm);
+   if (ret)
+      goto fail;
+
+   return pm;
+
+fail:
+   nouveau_perfmon_destroy(pm);
+   return NULL;
+}
+
+void
+nouveau_perfmon_destroy(struct nouveau_perfmon *pm)
+{
+   if (!pm)
+      return;
+
+   nouveau_perfmon_free_domains(pm);
+   nouveau_object_del(&pm->object);
+   FREE(pm);
+}
+
+struct nouveau_perfmon_dom *
+nouveau_perfmon_get_dom_by_id(struct nouveau_perfmon *pm, uint8_t dom_id)
+{
+   struct nouveau_perfmon_dom *dom;
+
+   if (pm) {
+      LIST_FOR_EACH_ENTRY(dom, &pm->domains, head) {
+         if (dom->id == dom_id)
+            return dom;
+      }
+   }
+   return NULL;
+}
+
+struct nouveau_perfmon_sig *
+nouveau_perfmon_get_sig_by_name(struct nouveau_perfmon_dom *dom,
+                                const char *name)
+{
+   struct nouveau_perfmon_sig *sig;
+
+   if (dom) {
+      LIST_FOR_EACH_ENTRY(sig, &dom->signals, head) {
+         if (!strcmp(sig->name, name))
+            return sig;
+      }
+   }
+   return NULL;
+}
+
+struct nouveau_perfmon_src *
+nouveau_perfmon_get_src_by_name(struct nouveau_perfmon_sig *sig,
+                                const char *name)
+{
+   struct nouveau_perfmon_src *src;
+
+   if (sig) {
+      LIST_FOR_EACH_ENTRY(src, &sig->sources, head) {
+         if (!strcmp(src->name, name))
+            return src;
+      }
+   }
+   return NULL;
+}
diff --git a/src/gallium/drivers/nouveau/nouveau_perfmon.h b/src/gallium/drivers/nouveau/nouveau_perfmon.h
new file mode 100644
index 0000000..49dcad3
--- /dev/null
+++ b/src/gallium/drivers/nouveau/nouveau_perfmon.h
@@ -0,0 +1,59 @@
+#ifndef __NOUVEAU_PERFMON_H__
+#define __NOUVEAU_PERFMON_H__
+
+#include <drm.h>
+#include <nouveau_class.h>
+#include <nouveau_ioctl.h>
+
+#include "util/list.h"
+
+struct nouveau_perfmon
+{
+   struct nouveau_object *object;
+   struct list_head domains;
+   uint64_t handle;
+};
+
+struct nouveau_perfmon_dom
+{
+   struct list_head head;
+   struct list_head signals;
+   uint8_t id;
+   char name[64];
+   uint8_t max_active_cntr;
+   uint8_t num_active_cntr;
+};
+
+struct nouveau_perfmon_sig
+{
+   struct list_head head;
+   struct list_head sources;
+   uint8_t signal;
+   char name[64];
+};
+
+struct nouveau_perfmon_src
+{
+   struct list_head head;
+   uint8_t id;
+   char name[64];
+};
+
+struct nouveau_perfmon *
+nouveau_perfmon_create(struct nouveau_device *dev);
+
+void
+nouveau_perfmon_destroy(struct nouveau_perfmon *pm);
+
+struct nouveau_perfmon_dom *
+nouveau_perfmon_get_dom_by_id(struct nouveau_perfmon *pm, uint8_t dom_id);
+
+struct nouveau_perfmon_sig *
+nouveau_perfmon_get_sig_by_name(struct nouveau_perfmon_dom *dom,
+                                const char *name);
+
+struct nouveau_perfmon_src *
+nouveau_perfmon_get_src_by_name(struct nouveau_perfmon_sig *sig,
+                                const char *name);
+
+#endif /* __NOUVEAU_PERFMON_H__ */
diff --git a/src/gallium/drivers/nouveau/nouveau_screen.c b/src/gallium/drivers/nouveau/nouveau_screen.c
index c6e5074..3c14a77 100644
--- a/src/gallium/drivers/nouveau/nouveau_screen.c
+++ b/src/gallium/drivers/nouveau/nouveau_screen.c
@@ -21,6 +21,7 @@
 #include "nouveau_fence.h"
 #include "nouveau_mm.h"
 #include "nouveau_buffer.h"
+#include "nouveau_perfmon.h"
 
 /* XXX this should go away */
 #include "state_tracker/drm_driver.h"
@@ -226,6 +227,8 @@ nouveau_screen_init(struct nouveau_screen *screen, struct nouveau_device *dev)
 					    NOUVEAU_BO_GART | NOUVEAU_BO_MAP,
 					    &mm_config);
 	screen->mm_VRAM = nouveau_mm_create(dev, NOUVEAU_BO_VRAM, &mm_config);
+
+	screen->perfmon = nouveau_perfmon_create(dev);
 	return 0;
 }
 
@@ -235,6 +238,8 @@ nouveau_screen_fini(struct nouveau_screen *screen)
 	nouveau_mm_destroy(screen->mm_GART);
 	nouveau_mm_destroy(screen->mm_VRAM);
 
+	nouveau_perfmon_destroy(screen->perfmon);
+
 	nouveau_pushbuf_del(&screen->pushbuf);
 
 	nouveau_client_del(&screen->client);
diff --git a/src/gallium/drivers/nouveau/nouveau_screen.h b/src/gallium/drivers/nouveau/nouveau_screen.h
index 30041b2..fd7ecdb 100644
--- a/src/gallium/drivers/nouveau/nouveau_screen.h
+++ b/src/gallium/drivers/nouveau/nouveau_screen.h
@@ -21,6 +21,7 @@ struct nouveau_screen {
 	struct nouveau_object *channel;
 	struct nouveau_client *client;
 	struct nouveau_pushbuf *pushbuf;
+	struct nouveau_perfmon *perfmon;
 
 	int refcount;
 
-- 
2.4.4



More information about the mesa-dev mailing list