etnaviv: add perfmon query implementation
[mesa.git] / src / gallium / drivers / etnaviv / etnaviv_query_pm.c
1 /*
2 * Copyright (c) 2017 Etnaviv Project
3 * Copyright (C) 2017 Zodiac Inflight Innovations
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sub license,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial portions
14 * of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Christian Gmeiner <christian.gmeiner@gmail.com>
26 */
27
28 #include "util/u_inlines.h"
29 #include "util/u_memory.h"
30
31 #include "etnaviv_context.h"
32 #include "etnaviv_query_pm.h"
33 #include "etnaviv_screen.h"
34
35 struct etna_perfmon_source
36 {
37 const char *domain;
38 const char *signal;
39 };
40
41 struct etna_perfmon_config
42 {
43 const char *name;
44 unsigned type;
45 const struct etna_perfmon_source *source;
46 };
47
48 static const struct etna_perfmon_config query_config[] = {
49 };
50
51 static const struct etna_perfmon_config *
52 etna_pm_query_config(unsigned type)
53 {
54 for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++)
55 if (query_config[i].type == type)
56 return &query_config[i];
57
58 return NULL;
59 }
60
61 static struct etna_perfmon_signal *
62 etna_pm_query_signal(struct etna_perfmon *perfmon,
63 const struct etna_perfmon_source *source)
64 {
65 struct etna_perfmon_domain *domain;
66
67 domain = etna_perfmon_get_dom_by_name(perfmon, source->domain);
68 if (!domain)
69 return NULL;
70
71 return etna_perfmon_get_sig_by_name(domain, source->signal);
72 }
73
74 static inline bool
75 etna_pm_cfg_supported(struct etna_perfmon *perfmon,
76 const struct etna_perfmon_config *cfg)
77 {
78 struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
79
80 return !!signal;
81 }
82
83 static inline void
84 etna_pm_add_signal(struct etna_pm_query *pq, struct etna_perfmon *perfmon,
85 const struct etna_perfmon_config *cfg)
86 {
87 struct etna_perfmon_signal *signal = etna_pm_query_signal(perfmon, cfg->source);
88
89 pq->signal = signal;
90 }
91
92 static bool
93 realloc_query_bo(struct etna_context *ctx, struct etna_pm_query *pq)
94 {
95 if (pq->bo)
96 etna_bo_del(pq->bo);
97
98 pq->bo = etna_bo_new(ctx->screen->dev, 64, DRM_ETNA_GEM_CACHE_WC);
99 if (unlikely(!pq->bo))
100 return false;
101
102 pq->data = etna_bo_map(pq->bo);
103
104 return true;
105 }
106
107 static void
108 etna_pm_query_get(struct etna_cmd_stream *stream, struct etna_query *q,
109 unsigned flags)
110 {
111 struct etna_pm_query *pq = etna_pm_query(q);
112 unsigned offset;
113 assert(flags);
114
115 if (flags == ETNA_PM_PROCESS_PRE)
116 offset = 2;
117 else
118 offset = 3;
119
120 struct etna_perf p = {
121 .flags = flags,
122 .sequence = pq->sequence,
123 .bo = pq->bo,
124 .signal = pq->signal,
125 .offset = offset
126 };
127
128 etna_cmd_stream_perf(stream, &p);
129 }
130
131 static inline void
132 etna_pm_query_update(struct etna_query *q)
133 {
134 struct etna_pm_query *pq = etna_pm_query(q);
135
136 if (pq->data[0] == pq->sequence)
137 pq->ready = true;
138 }
139
140 static void
141 etna_pm_destroy_query(struct etna_context *ctx, struct etna_query *q)
142 {
143 struct etna_pm_query *pq = etna_pm_query(q);
144
145 etna_bo_del(pq->bo);
146 FREE(pq);
147 }
148
149 static boolean
150 etna_pm_begin_query(struct etna_context *ctx, struct etna_query *q)
151 {
152 struct etna_pm_query *pq = etna_pm_query(q);
153
154 pq->ready = false;
155 pq->sequence++;
156
157 etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_PRE);
158
159 return true;
160 }
161
162 static void
163 etna_pm_end_query(struct etna_context *ctx, struct etna_query *q)
164 {
165 etna_pm_query_get(ctx->stream, q, ETNA_PM_PROCESS_POST);
166 }
167
168 static boolean
169 etna_pm_get_query_result(struct etna_context *ctx, struct etna_query *q,
170 boolean wait, union pipe_query_result *result)
171 {
172 struct etna_pm_query *pq = etna_pm_query(q);
173
174 etna_pm_query_update(q);
175
176 if (!pq->ready) {
177 if (!wait)
178 return false;
179
180 if (!etna_bo_cpu_prep(pq->bo, DRM_ETNA_PREP_READ))
181 return false;
182
183 pq->ready = true;
184 etna_bo_cpu_fini(pq->bo);
185 }
186
187 result->u32 = pq->data[2] - pq->data[1];
188
189 return true;
190 }
191
192 static const struct etna_query_funcs hw_query_funcs = {
193 .destroy_query = etna_pm_destroy_query,
194 .begin_query = etna_pm_begin_query,
195 .end_query = etna_pm_end_query,
196 .get_query_result = etna_pm_get_query_result,
197 };
198
199 struct etna_query *
200 etna_pm_create_query(struct etna_context *ctx, unsigned query_type)
201 {
202 struct etna_perfmon *perfmon = ctx->screen->perfmon;
203 const struct etna_perfmon_config *cfg;
204 struct etna_pm_query *pq;
205 struct etna_query *q;
206
207 cfg = etna_pm_query_config(query_type);
208 if (!cfg)
209 return NULL;
210
211 if (!etna_pm_cfg_supported(perfmon, cfg))
212 return NULL;
213
214 pq = CALLOC_STRUCT(etna_pm_query);
215 if (!pq)
216 return NULL;
217
218 if (!realloc_query_bo(ctx, pq)) {
219 FREE(pq);
220 return NULL;
221 }
222
223 q = &pq->base;
224 q->funcs = &hw_query_funcs;
225 q->type = query_type;
226
227 etna_pm_add_signal(pq, perfmon, cfg);
228
229 return q;
230 }
231
232 void
233 etna_pm_query_setup(struct etna_screen *screen)
234 {
235 screen->perfmon = etna_perfmon_create(screen->pipe);
236
237 if (!screen->perfmon)
238 return;
239
240 for (unsigned i = 0; i < ARRAY_SIZE(query_config); i++) {
241 const struct etna_perfmon_config *cfg = &query_config[i];
242
243 if (!etna_pm_cfg_supported(screen->perfmon, cfg))
244 continue;
245
246 util_dynarray_append(&screen->supported_pm_queries, unsigned, i);
247 }
248 }
249
250 int
251 etna_pm_get_driver_query_info(struct pipe_screen *pscreen, unsigned index,
252 struct pipe_driver_query_info *info)
253 {
254 const struct etna_screen *screen = etna_screen(pscreen);
255 const unsigned num = screen->supported_pm_queries.size / sizeof(unsigned);
256 unsigned i;
257
258 if (!info)
259 return num;
260
261 if (index >= num)
262 return 0;
263
264 i = *util_dynarray_element(&screen->supported_pm_queries, unsigned, index);
265 assert(i < ARRAY_SIZE(query_config));
266
267 info->name = query_config[i].name;
268 info->query_type = query_config[i].type;
269 info->group_id = 0;
270
271 return 1;
272 }