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 init_perf_monitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
71 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
72 struct pipe_screen
*screen
= st_context(ctx
)->pipe
->screen
;
73 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
76 st_flush_bitmap_cache(st_context(ctx
));
78 /* Create a query for each active counter. */
79 for (gid
= 0; gid
< ctx
->PerfMonitor
.NumGroups
; gid
++) {
80 const struct gl_perf_monitor_group
*g
= &ctx
->PerfMonitor
.Groups
[gid
];
82 if (m
->ActiveGroups
[gid
] > g
->MaxActiveCounters
) {
83 /* Maximum number of counters reached. Cannot start the session. */
84 if (ST_DEBUG
& DEBUG_MESA
) {
85 debug_printf("Maximum number of counters reached. "
86 "Cannot start the session!\n");
91 for (cid
= 0; cid
< g
->NumCounters
; cid
++) {
92 const struct gl_perf_monitor_counter
*c
= &g
->Counters
[cid
];
93 struct st_perf_counter_object
*cntr
;
96 if (!BITSET_TEST(m
->ActiveCounters
[gid
], cid
))
99 query_type
= find_query_type(screen
, c
->Name
);
100 assert(query_type
!= -1);
102 cntr
= CALLOC_STRUCT(st_perf_counter_object
);
106 cntr
->query
= pipe
->create_query(pipe
, query_type
, 0);
108 cntr
->group_id
= gid
;
110 list_addtail(&cntr
->list
, &stm
->active_counters
);
117 reset_perf_monitor(struct st_perf_monitor_object
*stm
,
118 struct pipe_context
*pipe
)
120 struct st_perf_counter_object
*cntr
, *tmp
;
122 LIST_FOR_EACH_ENTRY_SAFE(cntr
, tmp
, &stm
->active_counters
, list
) {
124 pipe
->destroy_query(pipe
, cntr
->query
);
125 list_del(&cntr
->list
);
130 static struct gl_perf_monitor_object
*
131 st_NewPerfMonitor(struct gl_context
*ctx
)
133 struct st_perf_monitor_object
*stq
= ST_CALLOC_STRUCT(st_perf_monitor_object
);
135 list_inithead(&stq
->active_counters
);
142 st_DeletePerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
144 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
145 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
147 reset_perf_monitor(stm
, pipe
);
152 st_BeginPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
154 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
155 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
156 struct st_perf_counter_object
*cntr
;
158 if (LIST_IS_EMPTY(&stm
->active_counters
)) {
159 /* Create a query for each active counter before starting
160 * a new monitoring session. */
161 if (!init_perf_monitor(ctx
, m
))
165 /* Start the query for each active counter. */
166 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
167 if (!pipe
->begin_query(pipe
, cntr
->query
))
173 /* Failed to start the monitoring session. */
174 reset_perf_monitor(stm
, pipe
);
179 st_EndPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
181 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
182 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
183 struct st_perf_counter_object
*cntr
;
185 /* Stop the query for each active counter. */
186 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
)
187 pipe
->end_query(pipe
, cntr
->query
);
191 st_ResetPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
193 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
194 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
197 st_EndPerfMonitor(ctx
, m
);
199 reset_perf_monitor(stm
, pipe
);
202 st_BeginPerfMonitor(ctx
, m
);
206 st_IsPerfMonitorResultAvailable(struct gl_context
*ctx
,
207 struct gl_perf_monitor_object
*m
)
209 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
210 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
211 struct st_perf_counter_object
*cntr
;
213 if (LIST_IS_EMPTY(&stm
->active_counters
))
216 /* The result of a monitoring session is only available if the query of
217 * each active counter is idle. */
218 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
219 union pipe_query_result result
;
220 if (!pipe
->get_query_result(pipe
, cntr
->query
, FALSE
, &result
)) {
221 /* The query is busy. */
229 st_GetPerfMonitorResult(struct gl_context
*ctx
,
230 struct gl_perf_monitor_object
*m
,
235 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
236 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
237 struct st_perf_counter_object
*cntr
;
239 /* Copy data to the supplied array (data).
241 * The output data format is: <group ID, counter ID, value> for each
242 * active counter. The API allows counters to appear in any order.
246 /* Read query results for each active counter. */
247 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
248 union pipe_query_result result
= { 0 };
253 gid
= cntr
->group_id
;
254 type
= ctx
->PerfMonitor
.Groups
[gid
].Counters
[cid
].Type
;
256 if (!pipe
->get_query_result(pipe
, cntr
->query
, TRUE
, &result
))
259 data
[offset
++] = gid
;
260 data
[offset
++] = cid
;
262 case GL_UNSIGNED_INT64_AMD
:
263 *(uint64_t *)&data
[offset
] = result
.u64
;
264 offset
+= sizeof(uint64_t) / sizeof(GLuint
);
266 case GL_UNSIGNED_INT
:
267 *(uint32_t *)&data
[offset
] = result
.u32
;
268 offset
+= sizeof(uint32_t) / sizeof(GLuint
);
271 case GL_PERCENTAGE_AMD
:
272 *(GLfloat
*)&data
[offset
] = result
.f
;
273 offset
+= sizeof(GLfloat
) / sizeof(GLuint
);
279 *bytesWritten
= offset
* sizeof(GLuint
);
284 st_init_perfmon(struct st_context
*st
)
286 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
287 struct pipe_screen
*screen
= st
->pipe
->screen
;
288 struct gl_perf_monitor_group
*groups
= NULL
;
289 int num_counters
, num_groups
;
292 if (!screen
->get_driver_query_info
|| !screen
->get_driver_query_group_info
)
295 /* Get the number of available queries. */
296 num_counters
= screen
->get_driver_query_info(screen
, 0, NULL
);
300 /* Get the number of available groups. */
301 num_groups
= screen
->get_driver_query_group_info(screen
, 0, NULL
);
303 groups
= CALLOC(num_groups
, sizeof(*groups
));
307 for (gid
= 0; gid
< num_groups
; gid
++) {
308 struct gl_perf_monitor_group
*g
= &groups
[perfmon
->NumGroups
];
309 struct pipe_driver_query_group_info group_info
;
310 struct gl_perf_monitor_counter
*counters
= NULL
;
312 if (!screen
->get_driver_query_group_info(screen
, gid
, &group_info
))
315 g
->Name
= group_info
.name
;
316 g
->MaxActiveCounters
= group_info
.max_active_queries
;
320 if (group_info
.num_queries
)
321 counters
= CALLOC(group_info
.num_queries
, sizeof(*counters
));
325 for (cid
= 0; cid
< num_counters
; cid
++) {
326 struct gl_perf_monitor_counter
*c
= &counters
[g
->NumCounters
];
327 struct pipe_driver_query_info info
;
329 if (!screen
->get_driver_query_info(screen
, cid
, &info
))
331 if (info
.group_id
!= gid
)
336 case PIPE_DRIVER_QUERY_TYPE_UINT64
:
338 c
->Maximum
.u64
= info
.max_value
.u64
? info
.max_value
.u64
: -1;
339 c
->Type
= GL_UNSIGNED_INT64_AMD
;
341 case PIPE_DRIVER_QUERY_TYPE_UINT
:
343 c
->Maximum
.u32
= info
.max_value
.u32
? info
.max_value
.u32
: -1;
344 c
->Type
= GL_UNSIGNED_INT
;
346 case PIPE_DRIVER_QUERY_TYPE_FLOAT
:
348 c
->Maximum
.f
= info
.max_value
.f
? info
.max_value
.f
: -1;
351 case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE
:
353 c
->Maximum
.f
= 100.0f
;
354 c
->Type
= GL_PERCENTAGE_AMD
;
357 unreachable("Invalid driver query type!");
361 g
->Counters
= counters
;
362 perfmon
->NumGroups
++;
364 perfmon
->Groups
= groups
;
369 for (gid
= 0; gid
< num_groups
; gid
++)
370 FREE((void *)groups
[gid
].Counters
);
376 st_destroy_perfmon(struct st_context
*st
)
378 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
381 for (gid
= 0; gid
< perfmon
->NumGroups
; gid
++)
382 FREE((void *)perfmon
->Groups
[gid
].Counters
);
383 FREE((void *)perfmon
->Groups
);
386 void st_init_perfmon_functions(struct dd_function_table
*functions
)
388 functions
->NewPerfMonitor
= st_NewPerfMonitor
;
389 functions
->DeletePerfMonitor
= st_DeletePerfMonitor
;
390 functions
->BeginPerfMonitor
= st_BeginPerfMonitor
;
391 functions
->EndPerfMonitor
= st_EndPerfMonitor
;
392 functions
->ResetPerfMonitor
= st_ResetPerfMonitor
;
393 functions
->IsPerfMonitorResultAvailable
= st_IsPerfMonitorResultAvailable
;
394 functions
->GetPerfMonitorResult
= st_GetPerfMonitorResult
;