Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/freedreno/ds/fd_pps_driver.cc
4565 views
1
/*
2
* Copyright © 2021 Google, Inc.
3
*
4
* SPDX-License-Identifier: MIT
5
*/
6
7
#include "fd_pps_driver.h"
8
9
#include <cstring>
10
#include <iostream>
11
#include <perfetto.h>
12
13
#include "pps/pps.h"
14
#include "pps/pps_algorithm.h"
15
16
namespace pps
17
{
18
19
uint64_t
20
FreedrenoDriver::get_min_sampling_period_ns()
21
{
22
return 100000;
23
}
24
25
/*
26
TODO this sees like it would be largely the same for a5xx as well
27
(ie. same countable names)..
28
*/
29
void
30
FreedrenoDriver::setup_a6xx_counters()
31
{
32
/* TODO is there a reason to want more than one group? */
33
CounterGroup group = {};
34
group.name = "counters";
35
groups.clear();
36
counters.clear();
37
countables.clear();
38
enabled_counters.clear();
39
groups.emplace_back(std::move(group));
40
41
/*
42
* Create the countables that we'll be using.
43
*/
44
45
auto PERF_CP_ALWAYS_COUNT = countable("PERF_CP_ALWAYS_COUNT");
46
auto PERF_CP_BUSY_CYCLES = countable("PERF_CP_BUSY_CYCLES");
47
auto PERF_RB_3D_PIXELS = countable("PERF_RB_3D_PIXELS");
48
auto PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS = countable("PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS");
49
auto PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS = countable("PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS");
50
auto PERF_TP_L1_CACHELINE_MISSES = countable("PERF_TP_L1_CACHELINE_MISSES");
51
auto PERF_SP_BUSY_CYCLES = countable("PERF_SP_BUSY_CYCLES");
52
53
/*
54
* And then setup the derived counters that we are exporting to
55
* pps based on the captured countable values
56
*/
57
58
counter("GPU Frequency", Counter::Units::Hertz, [=]() {
59
return PERF_CP_ALWAYS_COUNT / time;
60
}
61
);
62
63
counter("GPU % Utilization", Counter::Units::Percent, [=]() {
64
return 100.0 * (PERF_CP_BUSY_CYCLES / time) / max_freq;
65
}
66
);
67
68
// This one is a bit of a guess, but seems plausible..
69
counter("ALU / Fragment", Counter::Units::None, [=]() {
70
return (PERF_SP_FS_STAGE_FULL_ALU_INSTRUCTIONS +
71
PERF_SP_FS_STAGE_HALF_ALU_INSTRUCTIONS / 2) / PERF_RB_3D_PIXELS;
72
}
73
);
74
75
counter("TP L1 Cache Misses", Counter::Units::None, [=]() {
76
return PERF_TP_L1_CACHELINE_MISSES / time;
77
}
78
);
79
80
counter("Shader Core Utilization", Counter::Units::Percent, [=]() {
81
return 100.0 * (PERF_SP_BUSY_CYCLES / time) / (max_freq * info->num_sp_cores);
82
}
83
);
84
85
// TODO add more.. see https://gpuinspector.dev/docs/gpu-counters/qualcomm
86
// for what blob exposes
87
}
88
89
/**
90
* Generate an submit the cmdstream to configure the counter/countable
91
* muxing
92
*/
93
void
94
FreedrenoDriver::configure_counters(bool reset, bool wait)
95
{
96
struct fd_submit *submit = fd_submit_new(pipe);
97
enum fd_ringbuffer_flags flags =
98
(enum fd_ringbuffer_flags)(FD_RINGBUFFER_PRIMARY | FD_RINGBUFFER_GROWABLE);
99
struct fd_ringbuffer *ring = fd_submit_new_ringbuffer(submit, 0x1000, flags);
100
101
for (auto countable : countables)
102
countable.configure(ring, reset);
103
104
struct fd_submit_fence fence = {};
105
util_queue_fence_init(&fence.ready);
106
107
fd_submit_flush(submit, -1, &fence);
108
109
util_queue_fence_wait(&fence.ready);
110
111
fd_ringbuffer_del(ring);
112
fd_submit_del(submit);
113
114
if (wait)
115
fd_pipe_wait(pipe, &fence.fence);
116
}
117
118
/**
119
* Read the current counter values and record the time.
120
*/
121
void
122
FreedrenoDriver::collect_countables()
123
{
124
last_dump_ts = perfetto::base::GetBootTimeNs().count();
125
126
for (auto countable : countables)
127
countable.collect();
128
}
129
130
bool
131
FreedrenoDriver::init_perfcnt()
132
{
133
uint64_t val;
134
135
dev = fd_device_new(drm_device.fd);
136
pipe = fd_pipe_new(dev, FD_PIPE_3D);
137
138
if (fd_pipe_get_param(pipe, FD_GPU_ID, &val)) {
139
PERFETTO_FATAL("Could not get GPU_ID");
140
return false;
141
}
142
gpu_id = val;
143
144
if (fd_pipe_get_param(pipe, FD_MAX_FREQ, &val)) {
145
PERFETTO_FATAL("Could not get MAX_FREQ");
146
return false;
147
}
148
max_freq = val;
149
150
if (fd_pipe_get_param(pipe, FD_SUSPEND_COUNT, &val)) {
151
PERFETTO_ILOG("Could not get SUSPEND_COUNT");
152
} else {
153
suspend_count = val;
154
has_suspend_count = true;
155
}
156
157
perfcntrs = fd_perfcntrs(gpu_id, &num_perfcntrs);
158
if (num_perfcntrs == 0) {
159
PERFETTO_FATAL("No hw counters available");
160
return false;
161
}
162
163
assigned_counters.resize(num_perfcntrs);
164
assigned_counters.assign(assigned_counters.size(), 0);
165
166
switch (gpu_id) {
167
case 600 ... 699:
168
setup_a6xx_counters();
169
break;
170
default:
171
PERFETTO_FATAL("Unsupported GPU: a%03u", gpu_id);
172
return false;
173
}
174
175
state.resize(next_countable_id);
176
177
for (auto countable : countables)
178
countable.resolve();
179
180
info = fd_dev_info(gpu_id);
181
182
io = fd_dt_find_io();
183
if (!io) {
184
PERFETTO_FATAL("Could not map GPU I/O space");
185
return false;
186
}
187
188
configure_counters(true, true);
189
collect_countables();
190
191
return true;
192
}
193
194
void
195
FreedrenoDriver::enable_counter(const uint32_t counter_id)
196
{
197
enabled_counters.push_back(counters[counter_id]);
198
}
199
200
void
201
FreedrenoDriver::enable_all_counters()
202
{
203
enabled_counters.reserve(counters.size());
204
for (auto &counter : counters) {
205
enabled_counters.push_back(counter);
206
}
207
}
208
209
void
210
FreedrenoDriver::enable_perfcnt(const uint64_t /* sampling_period_ns */)
211
{
212
}
213
214
bool
215
FreedrenoDriver::dump_perfcnt()
216
{
217
if (has_suspend_count) {
218
uint64_t val;
219
220
fd_pipe_get_param(pipe, FD_SUSPEND_COUNT, &val);
221
222
if (suspend_count != val) {
223
PERFETTO_ILOG("Device had suspended!");
224
225
suspend_count = val;
226
227
configure_counters(true, true);
228
collect_countables();
229
230
/* We aren't going to have anything sensible by comparing
231
* current values to values from prior to the suspend, so
232
* just skip this sampling period.
233
*/
234
return false;
235
}
236
}
237
238
auto last_ts = last_dump_ts;
239
240
/* Capture the timestamp from the *start* of the sampling period: */
241
last_capture_ts = last_dump_ts;
242
243
collect_countables();
244
245
auto elapsed_time_ns = last_dump_ts - last_ts;
246
247
time = (float)elapsed_time_ns / 1000000000.0;
248
249
/* On older kernels that dont' support querying the suspend-
250
* count, just send configuration cmdstream regularly to keep
251
* the GPU alive and correctly configured for the countables
252
* we want
253
*/
254
if (!has_suspend_count) {
255
configure_counters(false, false);
256
}
257
258
return true;
259
}
260
261
uint64_t FreedrenoDriver::next()
262
{
263
auto ret = last_capture_ts;
264
last_capture_ts = 0;
265
return ret;
266
}
267
268
void FreedrenoDriver::disable_perfcnt()
269
{
270
/* There isn't really any disable, only reconfiguring which countables
271
* get muxed to which counters
272
*/
273
}
274
275
/*
276
* Countable
277
*/
278
279
FreedrenoDriver::Countable
280
FreedrenoDriver::countable(std::string name)
281
{
282
auto countable = Countable(this, name);
283
countables.emplace_back(countable);
284
return countable;
285
}
286
287
FreedrenoDriver::Countable::Countable(FreedrenoDriver *d, std::string name)
288
: id {d->next_countable_id++}, d {d}, name {name}
289
{
290
}
291
292
/* Emit register writes on ring to configure counter/countable muxing: */
293
void
294
FreedrenoDriver::Countable::configure(struct fd_ringbuffer *ring, bool reset)
295
{
296
const struct fd_perfcntr_countable *countable = d->state[id].countable;
297
const struct fd_perfcntr_counter *counter = d->state[id].counter;
298
299
OUT_PKT7(ring, CP_WAIT_FOR_IDLE, 0);
300
301
if (counter->enable && reset) {
302
OUT_PKT4(ring, counter->enable, 1);
303
OUT_RING(ring, 0);
304
}
305
306
if (counter->clear && reset) {
307
OUT_PKT4(ring, counter->clear, 1);
308
OUT_RING(ring, 1);
309
310
OUT_PKT4(ring, counter->clear, 1);
311
OUT_RING(ring, 0);
312
}
313
314
OUT_PKT4(ring, counter->select_reg, 1);
315
OUT_RING(ring, countable->selector);
316
317
if (counter->enable && reset) {
318
OUT_PKT4(ring, counter->enable, 1);
319
OUT_RING(ring, 1);
320
}
321
}
322
323
/* Collect current counter value and calculate delta since last sample: */
324
void
325
FreedrenoDriver::Countable::collect()
326
{
327
const struct fd_perfcntr_counter *counter = d->state[id].counter;
328
329
d->state[id].last_value = d->state[id].value;
330
331
uint32_t *reg_lo = (uint32_t *)d->io + counter->counter_reg_lo;
332
uint32_t *reg_hi = (uint32_t *)d->io + counter->counter_reg_hi;
333
334
uint32_t lo = *reg_lo;
335
uint32_t hi = *reg_hi;
336
337
d->state[id].value = lo | ((uint64_t)hi << 32);
338
}
339
340
/* Resolve the countable and assign next counter from it's group: */
341
void
342
FreedrenoDriver::Countable::resolve()
343
{
344
for (unsigned i = 0; i < d->num_perfcntrs; i++) {
345
const struct fd_perfcntr_group *g = &d->perfcntrs[i];
346
for (unsigned j = 0; j < g->num_countables; j++) {
347
const struct fd_perfcntr_countable *c = &g->countables[j];
348
if (name == c->name) {
349
d->state[id].countable = c;
350
351
/* Assign a counter from the same group: */
352
assert(d->assigned_counters[i] < g->num_counters);
353
d->state[id].counter = &g->counters[d->assigned_counters[i]++];
354
355
std::cout << "Countable: " << name << ", group=" << g->name <<
356
", counter=" << d->assigned_counters[i] - 1 << "\n";
357
358
return;
359
}
360
}
361
}
362
unreachable("no such countable!");
363
}
364
365
uint64_t
366
FreedrenoDriver::Countable::get_value() const
367
{
368
return d->state[id].value - d->state[id].last_value;
369
}
370
371
/*
372
* DerivedCounter
373
*/
374
375
FreedrenoDriver::DerivedCounter::DerivedCounter(FreedrenoDriver *d, std::string name,
376
Counter::Units units,
377
std::function<int64_t()> derive)
378
: Counter(d->next_counter_id++, name, 0)
379
{
380
std::cout << "DerivedCounter: " << name << ", id=" << id << "\n";
381
this->units = units;
382
set_getter([=](const Counter &c, const Driver &d) {
383
return derive();
384
}
385
);
386
}
387
388
FreedrenoDriver::DerivedCounter
389
FreedrenoDriver::counter(std::string name, Counter::Units units,
390
std::function<int64_t()> derive)
391
{
392
auto counter = DerivedCounter(this, name, units, derive);
393
counters.emplace_back(counter);
394
return counter;
395
}
396
397
} // namespace pps
398
399