From 848fa3101d5077b1aecfb0886c69a7d0dd7f75bc Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Thu, 12 Nov 2015 00:59:00 +0100 Subject: [PATCH] nv50: add support for performance metrics on G84+ Currently only one metric is exposed but more will be added later. Signed-off-by: Samuel Pitoiset Tested-by: Pierre Moreau Acked-by: Ilia Mirkin --- src/gallium/drivers/nouveau/Makefile.sources | 2 + .../drivers/nouveau/nv50/nv50_query_hw.c | 19 +- .../nouveau/nv50/nv50_query_hw_metric.c | 207 ++++++++++++++++++ .../nouveau/nv50/nv50_query_hw_metric.h | 34 +++ 4 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 src/gallium/drivers/nouveau/nv50/nv50_query_hw_metric.c create mode 100644 src/gallium/drivers/nouveau/nv50/nv50_query_hw_metric.h diff --git a/src/gallium/drivers/nouveau/Makefile.sources b/src/gallium/drivers/nouveau/Makefile.sources index a1aa13587a1..12821a670cd 100644 --- a/src/gallium/drivers/nouveau/Makefile.sources +++ b/src/gallium/drivers/nouveau/Makefile.sources @@ -77,6 +77,8 @@ NV50_C_SOURCES := \ nv50/nv50_query.h \ nv50/nv50_query_hw.c \ nv50/nv50_query_hw.h \ + nv50/nv50_query_hw_metric.c \ + nv50/nv50_query_hw_metric.h \ nv50/nv50_query_hw_sm.c \ nv50/nv50_query_hw_sm.h \ nv50/nv50_resource.c \ diff --git a/src/gallium/drivers/nouveau/nv50/nv50_query_hw.c b/src/gallium/drivers/nouveau/nv50/nv50_query_hw.c index 23108acbef5..b6ebbbf1010 100644 --- a/src/gallium/drivers/nouveau/nv50/nv50_query_hw.c +++ b/src/gallium/drivers/nouveau/nv50/nv50_query_hw.c @@ -25,6 +25,7 @@ #include "nv50/nv50_context.h" #include "nv50/nv50_query_hw.h" +#include "nv50/nv50_query_hw_metric.h" #include "nv50/nv50_query_hw_sm.h" #include "nv_object.xml.h" @@ -349,6 +350,12 @@ nv50_hw_create_query(struct nv50_context *nv50, unsigned type, unsigned index) return (struct nv50_query *)hq; } + hq = nv50_hw_metric_create_query(nv50, type); + if (hq) { + hq->base.funcs = &hw_query_funcs; + return (struct nv50_query *)hq; + } + hq = CALLOC_STRUCT(nv50_hw_query); if (!hq) return NULL; @@ -397,14 +404,20 @@ int nv50_hw_get_driver_query_info(struct nv50_screen *screen, unsigned id, struct pipe_driver_query_info *info) { - int num_hw_sm_queries = 0; + int num_hw_sm_queries = 0, num_hw_metric_queries = 0; num_hw_sm_queries = nv50_hw_sm_get_driver_query_info(screen, 0, NULL); + num_hw_metric_queries = + nv50_hw_metric_get_driver_query_info(screen, 0, NULL); if (!info) - return num_hw_sm_queries; + return num_hw_sm_queries + num_hw_metric_queries; + + if (id < num_hw_sm_queries) + return nv50_hw_sm_get_driver_query_info(screen, id, info); - return nv50_hw_sm_get_driver_query_info(screen, id, info); + return nv50_hw_metric_get_driver_query_info(screen, + id - num_hw_sm_queries, info); } void diff --git a/src/gallium/drivers/nouveau/nv50/nv50_query_hw_metric.c b/src/gallium/drivers/nouveau/nv50/nv50_query_hw_metric.c new file mode 100644 index 00000000000..13dad30f113 --- /dev/null +++ b/src/gallium/drivers/nouveau/nv50/nv50_query_hw_metric.c @@ -0,0 +1,207 @@ +/* + * 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 "nv50/nv50_context.h" +#include "nv50/nv50_query_hw_metric.h" +#include "nv50/nv50_query_hw_sm.h" + +/* === PERFORMANCE MONITORING METRICS for NV84+ === */ +static const char *nv50_hw_metric_names[] = +{ + "metric-branch_efficiency", +}; + +struct nv50_hw_metric_query_cfg { + uint32_t queries[4]; + uint32_t num_queries; +}; + +#define _SM(n) NV50_HW_SM_QUERY(NV50_HW_SM_QUERY_ ##n) +#define _M(n, c) [NV50_HW_METRIC_QUERY_##n] = c + +/* ==== Compute capability 1.1 (G84+) ==== */ +static const struct nv50_hw_metric_query_cfg +sm11_branch_efficiency = +{ + .queries[0] = _SM(BRANCH), + .queries[1] = _SM(DIVERGENT_BRANCH), + .num_queries = 2, +}; + +static const struct nv50_hw_metric_query_cfg *sm11_hw_metric_queries[] = +{ + _M(BRANCH_EFFICIENCY, &sm11_branch_efficiency), +}; + +#undef _SM +#undef _M + +static const struct nv50_hw_metric_query_cfg * +nv50_hw_metric_query_get_cfg(struct nv50_context *nv50, + struct nv50_hw_query *hq) +{ + struct nv50_query *q = &hq->base; + return sm11_hw_metric_queries[q->type - NV50_HW_METRIC_QUERY(0)]; +} + +static void +nv50_hw_metric_destroy_query(struct nv50_context *nv50, + struct nv50_hw_query *hq) +{ + struct nv50_hw_metric_query *hmq = nv50_hw_metric_query(hq); + unsigned i; + + for (i = 0; i < hmq->num_queries; i++) + hmq->queries[i]->funcs->destroy_query(nv50, hmq->queries[i]); + FREE(hmq); +} + +static boolean +nv50_hw_metric_begin_query(struct nv50_context *nv50, struct nv50_hw_query *hq) +{ + struct nv50_hw_metric_query *hmq = nv50_hw_metric_query(hq); + boolean ret = false; + unsigned i; + + for (i = 0; i < hmq->num_queries; i++) { + ret = hmq->queries[i]->funcs->begin_query(nv50, hmq->queries[i]); + if (!ret) + return ret; + } + return ret; +} + +static void +nv50_hw_metric_end_query(struct nv50_context *nv50, struct nv50_hw_query *hq) +{ + struct nv50_hw_metric_query *hmq = nv50_hw_metric_query(hq); + unsigned i; + + for (i = 0; i < hmq->num_queries; i++) + hmq->queries[i]->funcs->end_query(nv50, hmq->queries[i]); +} + +static uint64_t +sm11_hw_metric_calc_result(struct nv50_hw_query *hq, uint64_t res64[8]) +{ + switch (hq->base.type - NV50_HW_METRIC_QUERY(0)) { + case NV50_HW_METRIC_QUERY_BRANCH_EFFICIENCY: + /* (branch / (branch + divergent_branch)) * 100 */ + if (res64[0] + res64[1]) + return (res64[0] / (double)(res64[0] + res64[1])) * 100; + break; + default: + debug_printf("invalid metric type: %d\n", + hq->base.type - NV50_HW_METRIC_QUERY(0)); + break; + } + return 0; +} + +static boolean +nv50_hw_metric_get_query_result(struct nv50_context *nv50, + struct nv50_hw_query *hq, boolean wait, + union pipe_query_result *result) +{ + struct nv50_hw_metric_query *hmq = nv50_hw_metric_query(hq); + union pipe_query_result results[4] = {}; + uint64_t res64[4] = {}; + boolean ret = false; + unsigned i; + + for (i = 0; i < hmq->num_queries; i++) { + ret = hmq->queries[i]->funcs->get_query_result(nv50, hmq->queries[i], + wait, &results[i]); + if (!ret) + return ret; + res64[i] = *(uint64_t *)&results[i]; + } + + *(uint64_t *)result = sm11_hw_metric_calc_result(hq, res64); + return ret; +} + +static const struct nv50_hw_query_funcs hw_metric_query_funcs = { + .destroy_query = nv50_hw_metric_destroy_query, + .begin_query = nv50_hw_metric_begin_query, + .end_query = nv50_hw_metric_end_query, + .get_query_result = nv50_hw_metric_get_query_result, +}; + +struct nv50_hw_query * +nv50_hw_metric_create_query(struct nv50_context *nv50, unsigned type) +{ + const struct nv50_hw_metric_query_cfg *cfg; + struct nv50_hw_metric_query *hmq; + struct nv50_hw_query *hq; + unsigned i; + + if (type < NV50_HW_METRIC_QUERY(0) || type > NV50_HW_METRIC_QUERY_LAST) + return NULL; + + hmq = CALLOC_STRUCT(nv50_hw_metric_query); + if (!hmq) + return NULL; + + hq = &hmq->base; + hq->funcs = &hw_metric_query_funcs; + hq->base.type = type; + + cfg = nv50_hw_metric_query_get_cfg(nv50, hq); + + for (i = 0; i < cfg->num_queries; i++) { + hmq->queries[i] = nv50_hw_sm_create_query(nv50, cfg->queries[i]); + if (!hmq->queries[i]) { + nv50_hw_metric_destroy_query(nv50, hq); + return NULL; + } + hmq->num_queries++; + } + + return hq; +} + +int +nv50_hw_metric_get_driver_query_info(struct nv50_screen *screen, unsigned id, + struct pipe_driver_query_info *info) +{ + int count = 0; + + if (screen->compute) + if (screen->base.class_3d >= NV84_3D_CLASS) + count += NV50_HW_METRIC_QUERY_COUNT; + + if (!info) + return count; + + if (id < count) { + if (screen->compute) { + if (screen->base.class_3d >= NV84_3D_CLASS) { + info->name = nv50_hw_metric_names[id]; + info->query_type = NV50_HW_METRIC_QUERY(id); + info->group_id = -1; + return 1; + } + } + } + return 0; +} diff --git a/src/gallium/drivers/nouveau/nv50/nv50_query_hw_metric.h b/src/gallium/drivers/nouveau/nv50/nv50_query_hw_metric.h new file mode 100644 index 00000000000..f8cfc04084f --- /dev/null +++ b/src/gallium/drivers/nouveau/nv50/nv50_query_hw_metric.h @@ -0,0 +1,34 @@ +#ifndef __NV50_QUERY_HW_METRIC_H__ +#define __NV50_QUERY_HW_METRIC_H__ + +#include "nv50_query_hw.h" + +struct nv50_hw_metric_query { + struct nv50_hw_query base; + struct nv50_hw_query *queries[4]; + unsigned num_queries; +}; + +static inline struct nv50_hw_metric_query * +nv50_hw_metric_query(struct nv50_hw_query *hq) +{ + return (struct nv50_hw_metric_query *)hq; +} + +/* + * Driver metrics queries: + */ +#define NV50_HW_METRIC_QUERY(i) (PIPE_QUERY_DRIVER_SPECIFIC + 1024 + (i)) +#define NV50_HW_METRIC_QUERY_LAST NV50_HW_METRIC_QUERY(NV50_HW_METRIC_QUERY_COUNT - 1) +enum nv50_hw_metric_queries +{ + NV50_HW_METRIC_QUERY_BRANCH_EFFICIENCY = 0, + NV50_HW_METRIC_QUERY_COUNT +}; + +struct nv50_hw_query * +nv50_hw_metric_create_query(struct nv50_context *, unsigned); +int +nv50_hw_metric_get_driver_query_info(struct nv50_screen *, unsigned, + struct pipe_driver_query_info *); +#endif -- 2.30.2