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