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 init_perf_monitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
42 struct st_context
*st
= st_context(ctx
);
43 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
44 struct pipe_context
*pipe
= st
->pipe
;
47 st_flush_bitmap_cache(st
);
49 /* Create a query for each active counter. */
50 for (gid
= 0; gid
< ctx
->PerfMonitor
.NumGroups
; gid
++) {
51 const struct gl_perf_monitor_group
*g
= &ctx
->PerfMonitor
.Groups
[gid
];
52 const struct st_perf_monitor_group
*stg
= &st
->perfmon
[gid
];
55 if (m
->ActiveGroups
[gid
] > g
->MaxActiveCounters
) {
56 /* Maximum number of counters reached. Cannot start the session. */
57 if (ST_DEBUG
& DEBUG_MESA
) {
58 debug_printf("Maximum number of counters reached. "
59 "Cannot start the session!\n");
64 BITSET_FOREACH_SET(cid
, tmp
, m
->ActiveCounters
[gid
], g
->NumCounters
) {
65 const struct st_perf_monitor_counter
*stc
= &stg
->counters
[cid
];
66 struct st_perf_counter_object
*cntr
;
68 cntr
= CALLOC_STRUCT(st_perf_counter_object
);
72 cntr
->query
= pipe
->create_query(pipe
, stc
->query_type
, 0);
76 list_addtail(&cntr
->list
, &stm
->active_counters
);
83 reset_perf_monitor(struct st_perf_monitor_object
*stm
,
84 struct pipe_context
*pipe
)
86 struct st_perf_counter_object
*cntr
, *tmp
;
88 LIST_FOR_EACH_ENTRY_SAFE(cntr
, tmp
, &stm
->active_counters
, list
) {
90 pipe
->destroy_query(pipe
, cntr
->query
);
91 list_del(&cntr
->list
);
96 static struct gl_perf_monitor_object
*
97 st_NewPerfMonitor(struct gl_context
*ctx
)
99 struct st_perf_monitor_object
*stq
= ST_CALLOC_STRUCT(st_perf_monitor_object
);
101 list_inithead(&stq
->active_counters
);
108 st_DeletePerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
110 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
111 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
113 reset_perf_monitor(stm
, pipe
);
118 st_BeginPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
120 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
121 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
122 struct st_perf_counter_object
*cntr
;
124 if (LIST_IS_EMPTY(&stm
->active_counters
)) {
125 /* Create a query for each active counter before starting
126 * a new monitoring session. */
127 if (!init_perf_monitor(ctx
, m
))
131 /* Start the query for each active counter. */
132 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
133 if (!pipe
->begin_query(pipe
, cntr
->query
))
139 /* Failed to start the monitoring session. */
140 reset_perf_monitor(stm
, pipe
);
145 st_EndPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
147 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
148 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
149 struct st_perf_counter_object
*cntr
;
151 /* Stop the query for each active counter. */
152 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
)
153 pipe
->end_query(pipe
, cntr
->query
);
157 st_ResetPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
159 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
160 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
163 st_EndPerfMonitor(ctx
, m
);
165 reset_perf_monitor(stm
, pipe
);
168 st_BeginPerfMonitor(ctx
, m
);
172 st_IsPerfMonitorResultAvailable(struct gl_context
*ctx
,
173 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
))
182 /* The result of a monitoring session is only available if the query of
183 * each active counter is idle. */
184 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
185 union pipe_query_result result
;
186 if (!pipe
->get_query_result(pipe
, cntr
->query
, FALSE
, &result
)) {
187 /* The query is busy. */
195 st_GetPerfMonitorResult(struct gl_context
*ctx
,
196 struct gl_perf_monitor_object
*m
,
201 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
202 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
203 struct st_perf_counter_object
*cntr
;
205 /* Copy data to the supplied array (data).
207 * The output data format is: <group ID, counter ID, value> for each
208 * active counter. The API allows counters to appear in any order.
212 /* Read query results for each active counter. */
213 LIST_FOR_EACH_ENTRY(cntr
, &stm
->active_counters
, list
) {
214 union pipe_query_result result
= { 0 };
219 gid
= cntr
->group_id
;
220 type
= ctx
->PerfMonitor
.Groups
[gid
].Counters
[cid
].Type
;
222 if (!pipe
->get_query_result(pipe
, cntr
->query
, TRUE
, &result
))
225 data
[offset
++] = gid
;
226 data
[offset
++] = cid
;
228 case GL_UNSIGNED_INT64_AMD
:
229 *(uint64_t *)&data
[offset
] = result
.u64
;
230 offset
+= sizeof(uint64_t) / sizeof(GLuint
);
232 case GL_UNSIGNED_INT
:
233 *(uint32_t *)&data
[offset
] = result
.u32
;
234 offset
+= sizeof(uint32_t) / sizeof(GLuint
);
237 case GL_PERCENTAGE_AMD
:
238 *(GLfloat
*)&data
[offset
] = result
.f
;
239 offset
+= sizeof(GLfloat
) / sizeof(GLuint
);
245 *bytesWritten
= offset
* sizeof(GLuint
);
250 st_init_perfmon(struct st_context
*st
)
252 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
253 struct pipe_screen
*screen
= st
->pipe
->screen
;
254 struct gl_perf_monitor_group
*groups
= NULL
;
255 struct st_perf_monitor_group
*stgroups
= NULL
;
256 int num_counters
, num_groups
;
259 if (!screen
->get_driver_query_info
|| !screen
->get_driver_query_group_info
)
262 /* Get the number of available queries. */
263 num_counters
= screen
->get_driver_query_info(screen
, 0, NULL
);
267 /* Get the number of available groups. */
268 num_groups
= screen
->get_driver_query_group_info(screen
, 0, NULL
);
270 groups
= CALLOC(num_groups
, sizeof(*groups
));
274 stgroups
= CALLOC(num_groups
, sizeof(*stgroups
));
276 goto fail_only_groups
;
278 for (gid
= 0; gid
< num_groups
; gid
++) {
279 struct gl_perf_monitor_group
*g
= &groups
[perfmon
->NumGroups
];
280 struct pipe_driver_query_group_info group_info
;
281 struct gl_perf_monitor_counter
*counters
= NULL
;
282 struct st_perf_monitor_counter
*stcounters
= NULL
;
284 if (!screen
->get_driver_query_group_info(screen
, gid
, &group_info
))
287 g
->Name
= group_info
.name
;
288 g
->MaxActiveCounters
= group_info
.max_active_queries
;
290 if (group_info
.num_queries
)
291 counters
= CALLOC(group_info
.num_queries
, sizeof(*counters
));
294 g
->Counters
= counters
;
296 stcounters
= CALLOC(group_info
.num_queries
, sizeof(*stcounters
));
299 stgroups
[perfmon
->NumGroups
].counters
= stcounters
;
301 for (cid
= 0; cid
< num_counters
; cid
++) {
302 struct gl_perf_monitor_counter
*c
= &counters
[g
->NumCounters
];
303 struct st_perf_monitor_counter
*stc
= &stcounters
[g
->NumCounters
];
304 struct pipe_driver_query_info info
;
306 if (!screen
->get_driver_query_info(screen
, cid
, &info
))
308 if (info
.group_id
!= gid
)
313 case PIPE_DRIVER_QUERY_TYPE_UINT64
:
314 case PIPE_DRIVER_QUERY_TYPE_BYTES
:
315 case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS
:
316 case PIPE_DRIVER_QUERY_TYPE_HZ
:
318 c
->Maximum
.u64
= info
.max_value
.u64
? info
.max_value
.u64
: -1;
319 c
->Type
= GL_UNSIGNED_INT64_AMD
;
321 case PIPE_DRIVER_QUERY_TYPE_UINT
:
323 c
->Maximum
.u32
= info
.max_value
.u32
? info
.max_value
.u32
: -1;
324 c
->Type
= GL_UNSIGNED_INT
;
326 case PIPE_DRIVER_QUERY_TYPE_FLOAT
:
328 c
->Maximum
.f
= info
.max_value
.f
? info
.max_value
.f
: -1;
331 case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE
:
333 c
->Maximum
.f
= 100.0f
;
334 c
->Type
= GL_PERCENTAGE_AMD
;
337 unreachable("Invalid driver query type!");
340 stc
->query_type
= info
.query_type
;
344 perfmon
->NumGroups
++;
346 perfmon
->Groups
= groups
;
347 st
->perfmon
= stgroups
;
352 for (gid
= 0; gid
< num_groups
; gid
++) {
353 FREE(stgroups
[gid
].counters
);
354 FREE((void *)groups
[gid
].Counters
);
363 st_destroy_perfmon(struct st_context
*st
)
365 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
368 for (gid
= 0; gid
< perfmon
->NumGroups
; gid
++) {
369 FREE(st
->perfmon
[gid
].counters
);
370 FREE((void *)perfmon
->Groups
[gid
].Counters
);
373 FREE((void *)perfmon
->Groups
);
376 void st_init_perfmon_functions(struct dd_function_table
*functions
)
378 functions
->NewPerfMonitor
= st_NewPerfMonitor
;
379 functions
->DeletePerfMonitor
= st_DeletePerfMonitor
;
380 functions
->BeginPerfMonitor
= st_BeginPerfMonitor
;
381 functions
->EndPerfMonitor
= st_EndPerfMonitor
;
382 functions
->ResetPerfMonitor
= st_ResetPerfMonitor
;
383 functions
->IsPerfMonitorResultAvailable
= st_IsPerfMonitorResultAvailable
;
384 functions
->GetPerfMonitorResult
= st_GetPerfMonitorResult
;