2 * Copyright (C) 2013 Christoph Bumiller
3 * Copyright (C) 2015 Samuel Pitoiset
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, sublicense,
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:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 * OTHER DEALINGS IN THE SOFTWARE.
25 * Performance monitoring counters interface to gallium.
29 #include "st_context.h"
30 #include "st_cb_bitmap.h"
31 #include "st_cb_perfmon.h"
33 #include "util/bitset.h"
35 #include "pipe/p_context.h"
36 #include "pipe/p_screen.h"
37 #include "util/u_memory.h"
40 * Return a PIPE_QUERY_x type >= PIPE_QUERY_DRIVER_SPECIFIC, or -1 if
41 * the driver-specific query doesn't exist.
44 find_query_type(struct pipe_screen
*screen
, const char *name
)
50 num_queries
= screen
->get_driver_query_info(screen
, 0, NULL
);
54 for (i
= 0; i
< num_queries
; i
++) {
55 struct pipe_driver_query_info info
;
57 if (!screen
->get_driver_query_info(screen
, i
, &info
))
60 if (!strncmp(info
.name
, name
, strlen(name
))) {
61 type
= info
.query_type
;
69 * Return TRUE if the underlying driver expose GPU counters.
72 has_gpu_counters(struct pipe_screen
*screen
)
76 num_groups
= screen
->get_driver_query_group_info(screen
, 0, NULL
);
77 for (gid
= 0; gid
< num_groups
; gid
++) {
78 struct pipe_driver_query_group_info group_info
;
80 if (!screen
->get_driver_query_group_info(screen
, gid
, &group_info
))
83 if (group_info
.type
== PIPE_DRIVER_QUERY_GROUP_TYPE_GPU
)
90 init_perf_monitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
92 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
93 struct pipe_screen
*screen
= st_context(ctx
)->pipe
->screen
;
94 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
97 st_flush_bitmap_cache(st_context(ctx
));
99 /* Create a query for each active counter. */
100 for (gid
= 0; gid
< ctx
->PerfMonitor
.NumGroups
; gid
++) {
101 const struct gl_perf_monitor_group
*g
= &ctx
->PerfMonitor
.Groups
[gid
];
103 if (m
->ActiveGroups
[gid
] > g
->MaxActiveCounters
) {
104 /* Maximum number of counters reached. Cannot start the session. */
105 if (ST_DEBUG
& DEBUG_MESA
) {
106 debug_printf("Maximum number of counters reached. "
107 "Cannot start the session!\n");
112 for (cid
= 0; cid
< g
->NumCounters
; cid
++) {
113 const struct gl_perf_monitor_counter
*c
= &g
->Counters
[cid
];
114 struct st_perf_counter_object
*cntr
;
117 if (!BITSET_TEST(m
->ActiveCounters
[gid
], cid
))
120 query_type
= find_query_type(screen
, c
->Name
);
121 assert(query_type
!= -1);
123 cntr
= CALLOC_STRUCT(st_perf_counter_object
);
127 cntr
->query
= pipe
->create_query(pipe
, query_type
, 0);
129 cntr
->group_id
= gid
;
131 list_addtail(&cntr
->list
, &stm
->active_counters
);
138 reset_perf_monitor(struct st_perf_monitor_object
*stm
,
139 struct pipe_context
*pipe
)
141 struct st_perf_counter_object
*cntr
, *tmp
;
143 LIST_FOR_EACH_ENTRY_SAFE(cntr
, tmp
, &stm
->active_counters
, list
) {
145 pipe
->destroy_query(pipe
, cntr
->query
);
146 list_del(&cntr
->list
);
151 static struct gl_perf_monitor_object
*
152 st_NewPerfMonitor(struct gl_context
*ctx
)
154 struct st_perf_monitor_object
*stq
= ST_CALLOC_STRUCT(st_perf_monitor_object
);
156 list_inithead(&stq
->active_counters
);
163 st_DeletePerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
165 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
166 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
168 reset_perf_monitor(stm
, pipe
);
173 st_BeginPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
175 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
176 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
177 struct st_perf_counter_object
*cntr
;
179 if (LIST_IS_EMPTY(&stm
->active_counters
)) {
180 /* Create a query for each active counter before starting
181 * a new monitoring session. */
182 if (!init_perf_monitor(ctx
, m
))
186 /* Start the query for each active counter. */
187 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
188 if (!pipe
->begin_query(pipe
, cntr
->query
))
194 /* Failed to start the monitoring session. */
195 reset_perf_monitor(stm
, pipe
);
200 st_EndPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
202 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
203 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
204 struct st_perf_counter_object
*cntr
;
206 /* Stop the query for each active counter. */
207 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
)
208 pipe
->end_query(pipe
, cntr
->query
);
212 st_ResetPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
214 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
215 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
218 st_EndPerfMonitor(ctx
, m
);
220 reset_perf_monitor(stm
, pipe
);
223 st_BeginPerfMonitor(ctx
, m
);
227 st_IsPerfMonitorResultAvailable(struct gl_context
*ctx
,
228 struct gl_perf_monitor_object
*m
)
230 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
231 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
232 struct st_perf_counter_object
*cntr
;
234 if (LIST_IS_EMPTY(&stm
->active_counters
))
237 /* The result of a monitoring session is only available if the query of
238 * each active counter is idle. */
239 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
240 union pipe_query_result result
;
241 if (!pipe
->get_query_result(pipe
, cntr
->query
, FALSE
, &result
)) {
242 /* The query is busy. */
250 st_GetPerfMonitorResult(struct gl_context
*ctx
,
251 struct gl_perf_monitor_object
*m
,
256 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
257 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
258 struct st_perf_counter_object
*cntr
;
260 /* Copy data to the supplied array (data).
262 * The output data format is: <group ID, counter ID, value> for each
263 * active counter. The API allows counters to appear in any order.
267 /* Read query results for each active counter. */
268 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
269 union pipe_query_result result
= { 0 };
274 gid
= cntr
->group_id
;
275 type
= ctx
->PerfMonitor
.Groups
[gid
].Counters
[cid
].Type
;
277 if (!pipe
->get_query_result(pipe
, cntr
->query
, TRUE
, &result
))
280 data
[offset
++] = gid
;
281 data
[offset
++] = cid
;
283 case GL_UNSIGNED_INT64_AMD
:
284 *(uint64_t *)&data
[offset
] = result
.u64
;
285 offset
+= sizeof(uint64_t) / sizeof(GLuint
);
287 case GL_UNSIGNED_INT
:
288 *(uint32_t *)&data
[offset
] = result
.u32
;
289 offset
+= sizeof(uint32_t) / sizeof(GLuint
);
292 case GL_PERCENTAGE_AMD
:
293 *(GLfloat
*)&data
[offset
] = result
.f
;
294 offset
+= sizeof(GLfloat
) / sizeof(GLuint
);
300 *bytesWritten
= offset
* sizeof(GLuint
);
305 st_init_perfmon(struct st_context
*st
)
307 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
308 struct pipe_screen
*screen
= st
->pipe
->screen
;
309 struct gl_perf_monitor_group
*groups
= NULL
;
310 int num_counters
, num_groups
;
313 if (!screen
->get_driver_query_info
|| !screen
->get_driver_query_group_info
)
316 if (!has_gpu_counters(screen
)) {
317 /* According to the spec, GL_AMD_performance_monitor must only
318 * expose GPU counters. */
322 /* Get the number of available queries. */
323 num_counters
= screen
->get_driver_query_info(screen
, 0, NULL
);
327 /* Get the number of available groups. */
328 num_groups
= screen
->get_driver_query_group_info(screen
, 0, NULL
);
330 groups
= CALLOC(num_groups
, sizeof(*groups
));
334 for (gid
= 0; gid
< num_groups
; gid
++) {
335 struct gl_perf_monitor_group
*g
= &groups
[perfmon
->NumGroups
];
336 struct pipe_driver_query_group_info group_info
;
337 struct gl_perf_monitor_counter
*counters
= NULL
;
339 if (!screen
->get_driver_query_group_info(screen
, gid
, &group_info
))
342 if (group_info
.type
!= PIPE_DRIVER_QUERY_GROUP_TYPE_GPU
)
345 g
->Name
= group_info
.name
;
346 g
->MaxActiveCounters
= group_info
.max_active_queries
;
350 if (group_info
.num_queries
)
351 counters
= CALLOC(group_info
.num_queries
, sizeof(*counters
));
355 for (cid
= 0; cid
< num_counters
; cid
++) {
356 struct gl_perf_monitor_counter
*c
= &counters
[g
->NumCounters
];
357 struct pipe_driver_query_info info
;
359 if (!screen
->get_driver_query_info(screen
, cid
, &info
))
361 if (info
.group_id
!= gid
)
366 case PIPE_DRIVER_QUERY_TYPE_UINT64
:
368 c
->Maximum
.u64
= info
.max_value
.u64
? info
.max_value
.u64
: -1;
369 c
->Type
= GL_UNSIGNED_INT64_AMD
;
371 case PIPE_DRIVER_QUERY_TYPE_UINT
:
373 c
->Maximum
.u32
= info
.max_value
.u32
? info
.max_value
.u32
: -1;
374 c
->Type
= GL_UNSIGNED_INT
;
376 case PIPE_DRIVER_QUERY_TYPE_FLOAT
:
378 c
->Maximum
.f
= info
.max_value
.f
? info
.max_value
.f
: -1;
381 case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE
:
383 c
->Maximum
.f
= 100.0f
;
384 c
->Type
= GL_PERCENTAGE_AMD
;
387 unreachable("Invalid driver query type!");
391 g
->Counters
= counters
;
392 perfmon
->NumGroups
++;
394 perfmon
->Groups
= groups
;
399 for (gid
= 0; gid
< num_groups
; gid
++)
400 FREE((void *)groups
[gid
].Counters
);
406 st_destroy_perfmon(struct st_context
*st
)
408 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
411 for (gid
= 0; gid
< perfmon
->NumGroups
; gid
++)
412 FREE((void *)perfmon
->Groups
[gid
].Counters
);
413 FREE((void *)perfmon
->Groups
);
416 void st_init_perfmon_functions(struct dd_function_table
*functions
)
418 functions
->NewPerfMonitor
= st_NewPerfMonitor
;
419 functions
->DeletePerfMonitor
= st_DeletePerfMonitor
;
420 functions
->BeginPerfMonitor
= st_BeginPerfMonitor
;
421 functions
->EndPerfMonitor
= st_EndPerfMonitor
;
422 functions
->ResetPerfMonitor
= st_ResetPerfMonitor
;
423 functions
->IsPerfMonitorResultAvailable
= st_IsPerfMonitorResultAvailable
;
424 functions
->GetPerfMonitorResult
= st_GetPerfMonitorResult
;