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.pitoi...@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 _______________________________________________ mesa-dev mailing list mesa-dev@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/mesa-dev