Home | History | Annotate | Download | only in nv50
      1 /*
      2  * Copyright 2015 Samuel Pitoiset
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice shall be included in
     12  * all copies or substantial portions of the Software.
     13  *
     14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20  * OTHER DEALINGS IN THE SOFTWARE.
     21  */
     22 
     23 #include "nv50/nv50_context.h"
     24 #include "nv50/nv50_query_hw_metric.h"
     25 #include "nv50/nv50_query_hw_sm.h"
     26 
     27 /* === PERFORMANCE MONITORING METRICS for NV84+ === */
     28 static const char *nv50_hw_metric_names[] =
     29 {
     30    "metric-branch_efficiency",
     31 };
     32 
     33 struct nv50_hw_metric_query_cfg {
     34    uint32_t queries[4];
     35    uint32_t num_queries;
     36 };
     37 
     38 #define _SM(n) NV50_HW_SM_QUERY(NV50_HW_SM_QUERY_ ##n)
     39 #define _M(n, c) [NV50_HW_METRIC_QUERY_##n] = c
     40 
     41 /* ==== Compute capability 1.1 (G84+) ==== */
     42 static const struct nv50_hw_metric_query_cfg
     43 sm11_branch_efficiency =
     44 {
     45    .queries[0]  = _SM(BRANCH),
     46    .queries[1]  = _SM(DIVERGENT_BRANCH),
     47    .num_queries = 2,
     48 };
     49 
     50 static const struct nv50_hw_metric_query_cfg *sm11_hw_metric_queries[] =
     51 {
     52    _M(BRANCH_EFFICIENCY, &sm11_branch_efficiency),
     53 };
     54 
     55 #undef _SM
     56 #undef _M
     57 
     58 static const struct nv50_hw_metric_query_cfg *
     59 nv50_hw_metric_query_get_cfg(struct nv50_context *nv50,
     60                              struct nv50_hw_query *hq)
     61 {
     62    struct nv50_query *q = &hq->base;
     63    return sm11_hw_metric_queries[q->type - NV50_HW_METRIC_QUERY(0)];
     64 }
     65 
     66 static void
     67 nv50_hw_metric_destroy_query(struct nv50_context *nv50,
     68                              struct nv50_hw_query *hq)
     69 {
     70    struct nv50_hw_metric_query *hmq = nv50_hw_metric_query(hq);
     71    unsigned i;
     72 
     73    for (i = 0; i < hmq->num_queries; i++)
     74       if (hmq->queries[i]->funcs->destroy_query)
     75          hmq->queries[i]->funcs->destroy_query(nv50, hmq->queries[i]);
     76    FREE(hmq);
     77 }
     78 
     79 static boolean
     80 nv50_hw_metric_begin_query(struct nv50_context *nv50, struct nv50_hw_query *hq)
     81 {
     82    struct nv50_hw_metric_query *hmq = nv50_hw_metric_query(hq);
     83    boolean ret = false;
     84    unsigned i;
     85 
     86    for (i = 0; i < hmq->num_queries; i++) {
     87       ret = hmq->queries[i]->funcs->begin_query(nv50, hmq->queries[i]);
     88       if (!ret)
     89          return ret;
     90    }
     91    return ret;
     92 }
     93 
     94 static void
     95 nv50_hw_metric_end_query(struct nv50_context *nv50, struct nv50_hw_query *hq)
     96 {
     97    struct nv50_hw_metric_query *hmq = nv50_hw_metric_query(hq);
     98    unsigned i;
     99 
    100    for (i = 0; i < hmq->num_queries; i++)
    101       hmq->queries[i]->funcs->end_query(nv50, hmq->queries[i]);
    102 }
    103 
    104 static uint64_t
    105 sm11_hw_metric_calc_result(struct nv50_hw_query *hq, uint64_t res64[8])
    106 {
    107    switch (hq->base.type - NV50_HW_METRIC_QUERY(0)) {
    108    case NV50_HW_METRIC_QUERY_BRANCH_EFFICIENCY:
    109       /* (branch / (branch + divergent_branch)) * 100 */
    110       if (res64[0] + res64[1])
    111          return (res64[0] / (double)(res64[0] + res64[1])) * 100;
    112       break;
    113    default:
    114       debug_printf("invalid metric type: %d\n",
    115                    hq->base.type - NV50_HW_METRIC_QUERY(0));
    116       break;
    117    }
    118    return 0;
    119 }
    120 
    121 static boolean
    122 nv50_hw_metric_get_query_result(struct nv50_context *nv50,
    123                                 struct nv50_hw_query *hq, boolean wait,
    124                                 union pipe_query_result *result)
    125 {
    126    struct nv50_hw_metric_query *hmq = nv50_hw_metric_query(hq);
    127    union pipe_query_result results[4] = {};
    128    uint64_t res64[4] = {};
    129    boolean ret = false;
    130    unsigned i;
    131 
    132    for (i = 0; i < hmq->num_queries; i++) {
    133       ret = hmq->queries[i]->funcs->get_query_result(nv50, hmq->queries[i],
    134                                                      wait, &results[i]);
    135       if (!ret)
    136          return ret;
    137       res64[i] = *(uint64_t *)&results[i];
    138    }
    139 
    140    *(uint64_t *)result = sm11_hw_metric_calc_result(hq, res64);
    141    return ret;
    142 }
    143 
    144 static const struct nv50_hw_query_funcs hw_metric_query_funcs = {
    145    .destroy_query = nv50_hw_metric_destroy_query,
    146    .begin_query = nv50_hw_metric_begin_query,
    147    .end_query = nv50_hw_metric_end_query,
    148    .get_query_result = nv50_hw_metric_get_query_result,
    149 };
    150 
    151 struct nv50_hw_query *
    152 nv50_hw_metric_create_query(struct nv50_context *nv50, unsigned type)
    153 {
    154    const struct nv50_hw_metric_query_cfg *cfg;
    155    struct nv50_hw_metric_query *hmq;
    156    struct nv50_hw_query *hq;
    157    unsigned i;
    158 
    159    if (type < NV50_HW_METRIC_QUERY(0) || type > NV50_HW_METRIC_QUERY_LAST)
    160       return NULL;
    161 
    162    hmq = CALLOC_STRUCT(nv50_hw_metric_query);
    163    if (!hmq)
    164       return NULL;
    165 
    166    hq = &hmq->base;
    167    hq->funcs = &hw_metric_query_funcs;
    168    hq->base.type = type;
    169 
    170    cfg = nv50_hw_metric_query_get_cfg(nv50, hq);
    171 
    172    for (i = 0; i < cfg->num_queries; i++) {
    173       hmq->queries[i] = nv50_hw_sm_create_query(nv50, cfg->queries[i]);
    174       if (!hmq->queries[i]) {
    175          nv50_hw_metric_destroy_query(nv50, hq);
    176          return NULL;
    177       }
    178       hmq->num_queries++;
    179    }
    180 
    181    return hq;
    182 }
    183 
    184 int
    185 nv50_hw_metric_get_driver_query_info(struct nv50_screen *screen, unsigned id,
    186                                      struct pipe_driver_query_info *info)
    187 {
    188    int count = 0;
    189 
    190    if (screen->compute)
    191       if (screen->base.class_3d >= NV84_3D_CLASS)
    192          count += NV50_HW_METRIC_QUERY_COUNT;
    193 
    194    if (!info)
    195       return count;
    196 
    197    if (id < count) {
    198       if (screen->compute) {
    199          if (screen->base.class_3d >= NV84_3D_CLASS) {
    200             info->name = nv50_hw_metric_names[id];
    201             info->query_type = NV50_HW_METRIC_QUERY(id);
    202             info->group_id = NV50_HW_METRIC_QUERY_GROUP;
    203             return 1;
    204          }
    205       }
    206    }
    207    return 0;
    208 }
    209