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"
34 #include "util/bitset.h"
36 #include "pipe/p_context.h"
37 #include "pipe/p_screen.h"
38 #include "util/u_memory.h"
41 init_perf_monitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
43 struct st_context
*st
= st_context(ctx
);
44 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
45 struct pipe_context
*pipe
= st
->pipe
;
46 unsigned *batch
= NULL
;
47 unsigned num_active_counters
= 0;
48 unsigned max_batch_counters
= 0;
49 unsigned num_batch_counters
= 0;
52 st_flush_bitmap_cache(st
);
54 /* Determine the number of active counters. */
55 for (gid
= 0; gid
< ctx
->PerfMonitor
.NumGroups
; gid
++) {
56 const struct gl_perf_monitor_group
*g
= &ctx
->PerfMonitor
.Groups
[gid
];
57 const struct st_perf_monitor_group
*stg
= &st
->perfmon
[gid
];
59 if (m
->ActiveGroups
[gid
] > g
->MaxActiveCounters
) {
60 /* Maximum number of counters reached. Cannot start the session. */
61 if (ST_DEBUG
& DEBUG_MESA
) {
62 debug_printf("Maximum number of counters reached. "
63 "Cannot start the session!\n");
68 num_active_counters
+= m
->ActiveGroups
[gid
];
70 max_batch_counters
+= m
->ActiveGroups
[gid
];
73 if (!num_active_counters
)
76 stm
->active_counters
= CALLOC(num_active_counters
,
77 sizeof(*stm
->active_counters
));
78 if (!stm
->active_counters
)
81 if (max_batch_counters
) {
82 batch
= CALLOC(max_batch_counters
, sizeof(*batch
));
87 /* Create a query for each active counter. */
88 for (gid
= 0; gid
< ctx
->PerfMonitor
.NumGroups
; gid
++) {
89 const struct gl_perf_monitor_group
*g
= &ctx
->PerfMonitor
.Groups
[gid
];
90 const struct st_perf_monitor_group
*stg
= &st
->perfmon
[gid
];
93 BITSET_FOREACH_SET(cid
, tmp
, m
->ActiveCounters
[gid
], g
->NumCounters
) {
94 const struct st_perf_monitor_counter
*stc
= &stg
->counters
[cid
];
95 struct st_perf_counter_object
*cntr
=
96 &stm
->active_counters
[stm
->num_active_counters
];
100 if (stc
->flags
& PIPE_DRIVER_QUERY_FLAG_BATCH
) {
101 cntr
->batch_index
= num_batch_counters
;
102 batch
[num_batch_counters
++] = stc
->query_type
;
104 cntr
->query
= pipe
->create_query(pipe
, stc
->query_type
, 0);
108 ++stm
->num_active_counters
;
112 /* Create the batch query. */
113 if (num_batch_counters
) {
114 stm
->batch_query
= pipe
->create_batch_query(pipe
, num_batch_counters
,
116 stm
->batch_result
= CALLOC(num_batch_counters
, sizeof(stm
->batch_result
->batch
[0]));
117 if (!stm
->batch_query
|| !stm
->batch_result
)
130 reset_perf_monitor(struct st_perf_monitor_object
*stm
,
131 struct pipe_context
*pipe
)
135 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
136 struct pipe_query
*query
= stm
->active_counters
[i
].query
;
138 pipe
->destroy_query(pipe
, query
);
140 FREE(stm
->active_counters
);
141 stm
->active_counters
= NULL
;
142 stm
->num_active_counters
= 0;
144 if (stm
->batch_query
) {
145 pipe
->destroy_query(pipe
, stm
->batch_query
);
146 stm
->batch_query
= NULL
;
148 FREE(stm
->batch_result
);
149 stm
->batch_result
= NULL
;
152 static struct gl_perf_monitor_object
*
153 st_NewPerfMonitor(struct gl_context
*ctx
)
155 struct st_perf_monitor_object
*stq
= ST_CALLOC_STRUCT(st_perf_monitor_object
);
162 st_DeletePerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
164 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
165 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
167 reset_perf_monitor(stm
, pipe
);
172 st_BeginPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
174 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
175 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
178 if (!stm
->num_active_counters
) {
179 /* Create a query for each active counter before starting
180 * a new monitoring session. */
181 if (!init_perf_monitor(ctx
, m
))
185 /* Start the query for each active counter. */
186 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
187 struct pipe_query
*query
= stm
->active_counters
[i
].query
;
188 if (query
&& !pipe
->begin_query(pipe
, query
))
192 if (stm
->batch_query
&& !pipe
->begin_query(pipe
, stm
->batch_query
))
198 /* Failed to start the monitoring session. */
199 reset_perf_monitor(stm
, pipe
);
204 st_EndPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
206 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
207 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
210 /* Stop the query for each active counter. */
211 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
212 struct pipe_query
*query
= stm
->active_counters
[i
].query
;
214 pipe
->end_query(pipe
, query
);
217 if (stm
->batch_query
)
218 pipe
->end_query(pipe
, stm
->batch_query
);
222 st_ResetPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
224 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
225 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
228 st_EndPerfMonitor(ctx
, m
);
230 reset_perf_monitor(stm
, pipe
);
233 st_BeginPerfMonitor(ctx
, m
);
237 st_IsPerfMonitorResultAvailable(struct gl_context
*ctx
,
238 struct gl_perf_monitor_object
*m
)
240 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
241 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
244 if (!stm
->num_active_counters
)
247 /* The result of a monitoring session is only available if the query of
248 * each active counter is idle. */
249 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
250 struct pipe_query
*query
= stm
->active_counters
[i
].query
;
251 union pipe_query_result result
;
252 if (query
&& !pipe
->get_query_result(pipe
, query
, FALSE
, &result
)) {
253 /* The query is busy. */
258 if (stm
->batch_query
&&
259 !pipe
->get_query_result(pipe
, stm
->batch_query
, FALSE
, stm
->batch_result
))
266 st_GetPerfMonitorResult(struct gl_context
*ctx
,
267 struct gl_perf_monitor_object
*m
,
272 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
273 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
276 /* Copy data to the supplied array (data).
278 * The output data format is: <group ID, counter ID, value> for each
279 * active counter. The API allows counters to appear in any order.
282 bool have_batch_query
= false;
284 if (stm
->batch_query
)
285 have_batch_query
= pipe
->get_query_result(pipe
, stm
->batch_query
, TRUE
,
288 /* Read query results for each active counter. */
289 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
290 struct st_perf_counter_object
*cntr
= &stm
->active_counters
[i
];
291 union pipe_query_result result
= { 0 };
296 gid
= cntr
->group_id
;
297 type
= ctx
->PerfMonitor
.Groups
[gid
].Counters
[cid
].Type
;
300 if (!pipe
->get_query_result(pipe
, cntr
->query
, TRUE
, &result
))
303 if (!have_batch_query
)
305 result
.batch
[0] = stm
->batch_result
->batch
[cntr
->batch_index
];
308 data
[offset
++] = gid
;
309 data
[offset
++] = cid
;
311 case GL_UNSIGNED_INT64_AMD
:
312 memcpy(&data
[offset
], &result
.u64
, sizeof(uint64_t));
313 offset
+= sizeof(uint64_t) / sizeof(GLuint
);
315 case GL_UNSIGNED_INT
:
316 memcpy(&data
[offset
], &result
.u32
, sizeof(uint32_t));
317 offset
+= sizeof(uint32_t) / sizeof(GLuint
);
320 case GL_PERCENTAGE_AMD
:
321 memcpy(&data
[offset
], &result
.f
, sizeof(GLfloat
));
322 offset
+= sizeof(GLfloat
) / sizeof(GLuint
);
328 *bytesWritten
= offset
* sizeof(GLuint
);
333 st_have_perfmon(struct st_context
*st
)
335 struct pipe_screen
*screen
= st
->pipe
->screen
;
337 if (!screen
->get_driver_query_info
|| !screen
->get_driver_query_group_info
)
340 return screen
->get_driver_query_group_info(screen
, 0, NULL
) != 0;
344 st_InitPerfMonitorGroups(struct gl_context
*ctx
)
346 struct st_context
*st
= st_context(ctx
);
347 struct gl_perf_monitor_state
*perfmon
= &ctx
->PerfMonitor
;
348 struct pipe_screen
*screen
= st
->pipe
->screen
;
349 struct gl_perf_monitor_group
*groups
= NULL
;
350 struct st_perf_monitor_group
*stgroups
= NULL
;
351 int num_counters
, num_groups
;
354 /* Get the number of available queries. */
355 num_counters
= screen
->get_driver_query_info(screen
, 0, NULL
);
357 /* Get the number of available groups. */
358 num_groups
= screen
->get_driver_query_group_info(screen
, 0, NULL
);
359 groups
= CALLOC(num_groups
, sizeof(*groups
));
363 stgroups
= CALLOC(num_groups
, sizeof(*stgroups
));
365 goto fail_only_groups
;
367 for (gid
= 0; gid
< num_groups
; gid
++) {
368 struct gl_perf_monitor_group
*g
= &groups
[perfmon
->NumGroups
];
369 struct st_perf_monitor_group
*stg
= &stgroups
[perfmon
->NumGroups
];
370 struct pipe_driver_query_group_info group_info
;
371 struct gl_perf_monitor_counter
*counters
= NULL
;
372 struct st_perf_monitor_counter
*stcounters
= NULL
;
374 if (!screen
->get_driver_query_group_info(screen
, gid
, &group_info
))
377 g
->Name
= group_info
.name
;
378 g
->MaxActiveCounters
= group_info
.max_active_queries
;
380 if (group_info
.num_queries
)
381 counters
= CALLOC(group_info
.num_queries
, sizeof(*counters
));
384 g
->Counters
= counters
;
386 stcounters
= CALLOC(group_info
.num_queries
, sizeof(*stcounters
));
389 stg
->counters
= stcounters
;
391 for (cid
= 0; cid
< num_counters
; cid
++) {
392 struct gl_perf_monitor_counter
*c
= &counters
[g
->NumCounters
];
393 struct st_perf_monitor_counter
*stc
= &stcounters
[g
->NumCounters
];
394 struct pipe_driver_query_info info
;
396 if (!screen
->get_driver_query_info(screen
, cid
, &info
))
398 if (info
.group_id
!= gid
)
403 case PIPE_DRIVER_QUERY_TYPE_UINT64
:
404 case PIPE_DRIVER_QUERY_TYPE_BYTES
:
405 case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS
:
406 case PIPE_DRIVER_QUERY_TYPE_HZ
:
408 c
->Maximum
.u64
= info
.max_value
.u64
? info
.max_value
.u64
: -1;
409 c
->Type
= GL_UNSIGNED_INT64_AMD
;
411 case PIPE_DRIVER_QUERY_TYPE_UINT
:
413 c
->Maximum
.u32
= info
.max_value
.u32
? info
.max_value
.u32
: -1;
414 c
->Type
= GL_UNSIGNED_INT
;
416 case PIPE_DRIVER_QUERY_TYPE_FLOAT
:
418 c
->Maximum
.f
= info
.max_value
.f
? info
.max_value
.f
: -1;
421 case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE
:
423 c
->Maximum
.f
= 100.0f
;
424 c
->Type
= GL_PERCENTAGE_AMD
;
427 unreachable("Invalid driver query type!");
430 stc
->query_type
= info
.query_type
;
431 stc
->flags
= info
.flags
;
432 if (stc
->flags
& PIPE_DRIVER_QUERY_FLAG_BATCH
)
433 stg
->has_batch
= true;
437 perfmon
->NumGroups
++;
439 perfmon
->Groups
= groups
;
440 st
->perfmon
= stgroups
;
445 for (gid
= 0; gid
< num_groups
; gid
++) {
446 FREE(stgroups
[gid
].counters
);
447 FREE((void *)groups
[gid
].Counters
);
455 st_destroy_perfmon(struct st_context
*st
)
457 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
460 for (gid
= 0; gid
< perfmon
->NumGroups
; gid
++) {
461 FREE(st
->perfmon
[gid
].counters
);
462 FREE((void *)perfmon
->Groups
[gid
].Counters
);
465 FREE((void *)perfmon
->Groups
);
468 void st_init_perfmon_functions(struct dd_function_table
*functions
)
470 functions
->InitPerfMonitorGroups
= st_InitPerfMonitorGroups
;
471 functions
->NewPerfMonitor
= st_NewPerfMonitor
;
472 functions
->DeletePerfMonitor
= st_DeletePerfMonitor
;
473 functions
->BeginPerfMonitor
= st_BeginPerfMonitor
;
474 functions
->EndPerfMonitor
= st_EndPerfMonitor
;
475 functions
->ResetPerfMonitor
= st_ResetPerfMonitor
;
476 functions
->IsPerfMonitorResultAvailable
= st_IsPerfMonitorResultAvailable
;
477 functions
->GetPerfMonitorResult
= st_GetPerfMonitorResult
;