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
;
45 unsigned num_active_counters
= 0;
48 st_flush_bitmap_cache(st
);
50 /* Determine the number of active counters. */
51 for (gid
= 0; gid
< ctx
->PerfMonitor
.NumGroups
; gid
++) {
52 const struct gl_perf_monitor_group
*g
= &ctx
->PerfMonitor
.Groups
[gid
];
54 if (m
->ActiveGroups
[gid
] > g
->MaxActiveCounters
) {
55 /* Maximum number of counters reached. Cannot start the session. */
56 if (ST_DEBUG
& DEBUG_MESA
) {
57 debug_printf("Maximum number of counters reached. "
58 "Cannot start the session!\n");
63 num_active_counters
+= m
->ActiveGroups
[gid
];
66 if (!num_active_counters
)
69 stm
->active_counters
= CALLOC(num_active_counters
,
70 sizeof(*stm
->active_counters
));
71 if (!stm
->active_counters
)
74 /* Create a query for each active counter. */
75 for (gid
= 0; gid
< ctx
->PerfMonitor
.NumGroups
; gid
++) {
76 const struct gl_perf_monitor_group
*g
= &ctx
->PerfMonitor
.Groups
[gid
];
77 const struct st_perf_monitor_group
*stg
= &st
->perfmon
[gid
];
80 BITSET_FOREACH_SET(cid
, tmp
, m
->ActiveCounters
[gid
], g
->NumCounters
) {
81 const struct st_perf_monitor_counter
*stc
= &stg
->counters
[cid
];
82 struct st_perf_counter_object
*cntr
=
83 &stm
->active_counters
[stm
->num_active_counters
];
85 cntr
->query
= pipe
->create_query(pipe
, stc
->query_type
, 0);
88 ++stm
->num_active_counters
;
95 reset_perf_monitor(struct st_perf_monitor_object
*stm
,
96 struct pipe_context
*pipe
)
100 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
101 struct pipe_query
*query
= stm
->active_counters
[i
].query
;
103 pipe
->destroy_query(pipe
, query
);
105 FREE(stm
->active_counters
);
106 stm
->active_counters
= NULL
;
107 stm
->num_active_counters
= 0;
110 static struct gl_perf_monitor_object
*
111 st_NewPerfMonitor(struct gl_context
*ctx
)
113 struct st_perf_monitor_object
*stq
= ST_CALLOC_STRUCT(st_perf_monitor_object
);
120 st_DeletePerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
122 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
123 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
125 reset_perf_monitor(stm
, pipe
);
130 st_BeginPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
132 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
133 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
136 if (!stm
->num_active_counters
) {
137 /* Create a query for each active counter before starting
138 * a new monitoring session. */
139 if (!init_perf_monitor(ctx
, m
))
143 /* Start the query for each active counter. */
144 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
145 struct pipe_query
*query
= stm
->active_counters
[i
].query
;
146 if (!pipe
->begin_query(pipe
, query
))
152 /* Failed to start the monitoring session. */
153 reset_perf_monitor(stm
, pipe
);
158 st_EndPerfMonitor(struct gl_context
*ctx
, struct gl_perf_monitor_object
*m
)
160 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
161 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
164 /* Stop the query for each active counter. */
165 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
166 struct pipe_query
*query
= stm
->active_counters
[i
].query
;
167 pipe
->end_query(pipe
, query
);
172 st_ResetPerfMonitor(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 st_EndPerfMonitor(ctx
, m
);
180 reset_perf_monitor(stm
, pipe
);
183 st_BeginPerfMonitor(ctx
, m
);
187 st_IsPerfMonitorResultAvailable(struct gl_context
*ctx
,
188 struct gl_perf_monitor_object
*m
)
190 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
191 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
194 if (!stm
->num_active_counters
)
197 /* The result of a monitoring session is only available if the query of
198 * each active counter is idle. */
199 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
200 struct pipe_query
*query
= stm
->active_counters
[i
].query
;
201 union pipe_query_result result
;
202 if (!pipe
->get_query_result(pipe
, query
, FALSE
, &result
)) {
203 /* The query is busy. */
211 st_GetPerfMonitorResult(struct gl_context
*ctx
,
212 struct gl_perf_monitor_object
*m
,
217 struct st_perf_monitor_object
*stm
= st_perf_monitor_object(m
);
218 struct pipe_context
*pipe
= st_context(ctx
)->pipe
;
221 /* Copy data to the supplied array (data).
223 * The output data format is: <group ID, counter ID, value> for each
224 * active counter. The API allows counters to appear in any order.
228 /* Read query results for each active counter. */
229 for (i
= 0; i
< stm
->num_active_counters
; ++i
) {
230 struct st_perf_counter_object
*cntr
= &stm
->active_counters
[i
];
231 union pipe_query_result result
= { 0 };
236 gid
= cntr
->group_id
;
237 type
= ctx
->PerfMonitor
.Groups
[gid
].Counters
[cid
].Type
;
239 if (!pipe
->get_query_result(pipe
, cntr
->query
, TRUE
, &result
))
242 data
[offset
++] = gid
;
243 data
[offset
++] = cid
;
245 case GL_UNSIGNED_INT64_AMD
:
246 *(uint64_t *)&data
[offset
] = result
.u64
;
247 offset
+= sizeof(uint64_t) / sizeof(GLuint
);
249 case GL_UNSIGNED_INT
:
250 *(uint32_t *)&data
[offset
] = result
.u32
;
251 offset
+= sizeof(uint32_t) / sizeof(GLuint
);
254 case GL_PERCENTAGE_AMD
:
255 *(GLfloat
*)&data
[offset
] = result
.f
;
256 offset
+= sizeof(GLfloat
) / sizeof(GLuint
);
262 *bytesWritten
= offset
* sizeof(GLuint
);
267 st_init_perfmon(struct st_context
*st
)
269 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
270 struct pipe_screen
*screen
= st
->pipe
->screen
;
271 struct gl_perf_monitor_group
*groups
= NULL
;
272 struct st_perf_monitor_group
*stgroups
= NULL
;
273 int num_counters
, num_groups
;
276 if (!screen
->get_driver_query_info
|| !screen
->get_driver_query_group_info
)
279 /* Get the number of available queries. */
280 num_counters
= screen
->get_driver_query_info(screen
, 0, NULL
);
284 /* Get the number of available groups. */
285 num_groups
= screen
->get_driver_query_group_info(screen
, 0, NULL
);
287 groups
= CALLOC(num_groups
, sizeof(*groups
));
291 stgroups
= CALLOC(num_groups
, sizeof(*stgroups
));
293 goto fail_only_groups
;
295 for (gid
= 0; gid
< num_groups
; gid
++) {
296 struct gl_perf_monitor_group
*g
= &groups
[perfmon
->NumGroups
];
297 struct pipe_driver_query_group_info group_info
;
298 struct gl_perf_monitor_counter
*counters
= NULL
;
299 struct st_perf_monitor_counter
*stcounters
= NULL
;
301 if (!screen
->get_driver_query_group_info(screen
, gid
, &group_info
))
304 g
->Name
= group_info
.name
;
305 g
->MaxActiveCounters
= group_info
.max_active_queries
;
307 if (group_info
.num_queries
)
308 counters
= CALLOC(group_info
.num_queries
, sizeof(*counters
));
311 g
->Counters
= counters
;
313 stcounters
= CALLOC(group_info
.num_queries
, sizeof(*stcounters
));
316 stgroups
[perfmon
->NumGroups
].counters
= stcounters
;
318 for (cid
= 0; cid
< num_counters
; cid
++) {
319 struct gl_perf_monitor_counter
*c
= &counters
[g
->NumCounters
];
320 struct st_perf_monitor_counter
*stc
= &stcounters
[g
->NumCounters
];
321 struct pipe_driver_query_info info
;
323 if (!screen
->get_driver_query_info(screen
, cid
, &info
))
325 if (info
.group_id
!= gid
)
330 case PIPE_DRIVER_QUERY_TYPE_UINT64
:
331 case PIPE_DRIVER_QUERY_TYPE_BYTES
:
332 case PIPE_DRIVER_QUERY_TYPE_MICROSECONDS
:
333 case PIPE_DRIVER_QUERY_TYPE_HZ
:
335 c
->Maximum
.u64
= info
.max_value
.u64
? info
.max_value
.u64
: -1;
336 c
->Type
= GL_UNSIGNED_INT64_AMD
;
338 case PIPE_DRIVER_QUERY_TYPE_UINT
:
340 c
->Maximum
.u32
= info
.max_value
.u32
? info
.max_value
.u32
: -1;
341 c
->Type
= GL_UNSIGNED_INT
;
343 case PIPE_DRIVER_QUERY_TYPE_FLOAT
:
345 c
->Maximum
.f
= info
.max_value
.f
? info
.max_value
.f
: -1;
348 case PIPE_DRIVER_QUERY_TYPE_PERCENTAGE
:
350 c
->Maximum
.f
= 100.0f
;
351 c
->Type
= GL_PERCENTAGE_AMD
;
354 unreachable("Invalid driver query type!");
357 stc
->query_type
= info
.query_type
;
361 perfmon
->NumGroups
++;
363 perfmon
->Groups
= groups
;
364 st
->perfmon
= stgroups
;
369 for (gid
= 0; gid
< num_groups
; gid
++) {
370 FREE(stgroups
[gid
].counters
);
371 FREE((void *)groups
[gid
].Counters
);
380 st_destroy_perfmon(struct st_context
*st
)
382 struct gl_perf_monitor_state
*perfmon
= &st
->ctx
->PerfMonitor
;
385 for (gid
= 0; gid
< perfmon
->NumGroups
; gid
++) {
386 FREE(st
->perfmon
[gid
].counters
);
387 FREE((void *)perfmon
->Groups
[gid
].Counters
);
390 FREE((void *)perfmon
->Groups
);
393 void st_init_perfmon_functions(struct dd_function_table
*functions
)
395 functions
->NewPerfMonitor
= st_NewPerfMonitor
;
396 functions
->DeletePerfMonitor
= st_DeletePerfMonitor
;
397 functions
->BeginPerfMonitor
= st_BeginPerfMonitor
;
398 functions
->EndPerfMonitor
= st_EndPerfMonitor
;
399 functions
->ResetPerfMonitor
= st_ResetPerfMonitor
;
400 functions
->IsPerfMonitorResultAvailable
= st_IsPerfMonitorResultAvailable
;
401 functions
->GetPerfMonitorResult
= st_GetPerfMonitorResult
;