1*61046927SAndroid Build Coastguard Worker /*
2*61046927SAndroid Build Coastguard Worker * Copyright © 2016 Rob Clark <[email protected]>
3*61046927SAndroid Build Coastguard Worker * All Rights Reserved.
4*61046927SAndroid Build Coastguard Worker * SPDX-License-Identifier: MIT
5*61046927SAndroid Build Coastguard Worker */
6*61046927SAndroid Build Coastguard Worker
7*61046927SAndroid Build Coastguard Worker #include <assert.h>
8*61046927SAndroid Build Coastguard Worker #include <curses.h>
9*61046927SAndroid Build Coastguard Worker #include <err.h>
10*61046927SAndroid Build Coastguard Worker #include <inttypes.h>
11*61046927SAndroid Build Coastguard Worker #include <libconfig.h>
12*61046927SAndroid Build Coastguard Worker #include <locale.h>
13*61046927SAndroid Build Coastguard Worker #include <stdint.h>
14*61046927SAndroid Build Coastguard Worker #include <stdio.h>
15*61046927SAndroid Build Coastguard Worker #include <stdlib.h>
16*61046927SAndroid Build Coastguard Worker #include <string.h>
17*61046927SAndroid Build Coastguard Worker #include <time.h>
18*61046927SAndroid Build Coastguard Worker #include <unistd.h>
19*61046927SAndroid Build Coastguard Worker #include <xf86drm.h>
20*61046927SAndroid Build Coastguard Worker
21*61046927SAndroid Build Coastguard Worker #include "drm/freedreno_drmif.h"
22*61046927SAndroid Build Coastguard Worker #include "drm/freedreno_ringbuffer.h"
23*61046927SAndroid Build Coastguard Worker
24*61046927SAndroid Build Coastguard Worker #include "util/os_file.h"
25*61046927SAndroid Build Coastguard Worker
26*61046927SAndroid Build Coastguard Worker #include "freedreno_dt.h"
27*61046927SAndroid Build Coastguard Worker #include "freedreno_perfcntr.h"
28*61046927SAndroid Build Coastguard Worker
29*61046927SAndroid Build Coastguard Worker #define MAX_CNTR_PER_GROUP 24
30*61046927SAndroid Build Coastguard Worker #define REFRESH_MS 500
31*61046927SAndroid Build Coastguard Worker
32*61046927SAndroid Build Coastguard Worker static struct {
33*61046927SAndroid Build Coastguard Worker int refresh_ms;
34*61046927SAndroid Build Coastguard Worker bool dump;
35*61046927SAndroid Build Coastguard Worker } options = {
36*61046927SAndroid Build Coastguard Worker .refresh_ms = REFRESH_MS,
37*61046927SAndroid Build Coastguard Worker .dump = false,
38*61046927SAndroid Build Coastguard Worker };
39*61046927SAndroid Build Coastguard Worker
40*61046927SAndroid Build Coastguard Worker /* NOTE first counter group should always be CP, since we unconditionally
41*61046927SAndroid Build Coastguard Worker * use CP counter to measure the gpu freq.
42*61046927SAndroid Build Coastguard Worker */
43*61046927SAndroid Build Coastguard Worker
44*61046927SAndroid Build Coastguard Worker struct counter_group {
45*61046927SAndroid Build Coastguard Worker const struct fd_perfcntr_group *group;
46*61046927SAndroid Build Coastguard Worker
47*61046927SAndroid Build Coastguard Worker struct {
48*61046927SAndroid Build Coastguard Worker const struct fd_perfcntr_counter *counter;
49*61046927SAndroid Build Coastguard Worker uint16_t select_val;
50*61046927SAndroid Build Coastguard Worker bool is_gpufreq_counter;
51*61046927SAndroid Build Coastguard Worker } counter[MAX_CNTR_PER_GROUP];
52*61046927SAndroid Build Coastguard Worker
53*61046927SAndroid Build Coastguard Worker /* name of currently selected counters (for UI): */
54*61046927SAndroid Build Coastguard Worker const char *label[MAX_CNTR_PER_GROUP];
55*61046927SAndroid Build Coastguard Worker
56*61046927SAndroid Build Coastguard Worker uint64_t value[MAX_CNTR_PER_GROUP];
57*61046927SAndroid Build Coastguard Worker uint64_t value_delta[MAX_CNTR_PER_GROUP];
58*61046927SAndroid Build Coastguard Worker
59*61046927SAndroid Build Coastguard Worker uint64_t sample_time[MAX_CNTR_PER_GROUP];
60*61046927SAndroid Build Coastguard Worker uint64_t sample_time_delta[MAX_CNTR_PER_GROUP];
61*61046927SAndroid Build Coastguard Worker };
62*61046927SAndroid Build Coastguard Worker
63*61046927SAndroid Build Coastguard Worker static struct {
64*61046927SAndroid Build Coastguard Worker void *io;
65*61046927SAndroid Build Coastguard Worker uint32_t min_freq;
66*61046927SAndroid Build Coastguard Worker uint32_t max_freq;
67*61046927SAndroid Build Coastguard Worker /* per-generation table of counters: */
68*61046927SAndroid Build Coastguard Worker unsigned ngroups;
69*61046927SAndroid Build Coastguard Worker struct counter_group *groups;
70*61046927SAndroid Build Coastguard Worker /* drm device (for writing select regs via ring): */
71*61046927SAndroid Build Coastguard Worker struct fd_device *dev;
72*61046927SAndroid Build Coastguard Worker struct fd_pipe *pipe;
73*61046927SAndroid Build Coastguard Worker const struct fd_dev_id *dev_id;
74*61046927SAndroid Build Coastguard Worker struct fd_submit *submit;
75*61046927SAndroid Build Coastguard Worker struct fd_ringbuffer *ring;
76*61046927SAndroid Build Coastguard Worker } dev;
77*61046927SAndroid Build Coastguard Worker
78*61046927SAndroid Build Coastguard Worker static void config_save(void);
79*61046927SAndroid Build Coastguard Worker static void config_restore(void);
80*61046927SAndroid Build Coastguard Worker static void restore_counter_groups(void);
81*61046927SAndroid Build Coastguard Worker
82*61046927SAndroid Build Coastguard Worker /*
83*61046927SAndroid Build Coastguard Worker * helpers
84*61046927SAndroid Build Coastguard Worker */
85*61046927SAndroid Build Coastguard Worker
86*61046927SAndroid Build Coastguard Worker static uint64_t
gettime_us(void)87*61046927SAndroid Build Coastguard Worker gettime_us(void)
88*61046927SAndroid Build Coastguard Worker {
89*61046927SAndroid Build Coastguard Worker struct timespec ts;
90*61046927SAndroid Build Coastguard Worker clock_gettime(CLOCK_MONOTONIC, &ts);
91*61046927SAndroid Build Coastguard Worker return (ts.tv_sec * 1000000) + (ts.tv_nsec / 1000);
92*61046927SAndroid Build Coastguard Worker }
93*61046927SAndroid Build Coastguard Worker
94*61046927SAndroid Build Coastguard Worker static void
sleep_us(uint32_t us)95*61046927SAndroid Build Coastguard Worker sleep_us(uint32_t us)
96*61046927SAndroid Build Coastguard Worker {
97*61046927SAndroid Build Coastguard Worker const struct timespec ts = {
98*61046927SAndroid Build Coastguard Worker .tv_sec = us / 1000000,
99*61046927SAndroid Build Coastguard Worker .tv_nsec = (us % 1000000) * 1000,
100*61046927SAndroid Build Coastguard Worker };
101*61046927SAndroid Build Coastguard Worker clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
102*61046927SAndroid Build Coastguard Worker }
103*61046927SAndroid Build Coastguard Worker
104*61046927SAndroid Build Coastguard Worker static uint64_t
delta(uint64_t a,uint64_t b)105*61046927SAndroid Build Coastguard Worker delta(uint64_t a, uint64_t b)
106*61046927SAndroid Build Coastguard Worker {
107*61046927SAndroid Build Coastguard Worker /* deal with rollover: */
108*61046927SAndroid Build Coastguard Worker if (a > b)
109*61046927SAndroid Build Coastguard Worker return 0xffffffffffffffffull - a + b;
110*61046927SAndroid Build Coastguard Worker else
111*61046927SAndroid Build Coastguard Worker return b - a;
112*61046927SAndroid Build Coastguard Worker }
113*61046927SAndroid Build Coastguard Worker
114*61046927SAndroid Build Coastguard Worker static void
find_device(void)115*61046927SAndroid Build Coastguard Worker find_device(void)
116*61046927SAndroid Build Coastguard Worker {
117*61046927SAndroid Build Coastguard Worker int ret;
118*61046927SAndroid Build Coastguard Worker
119*61046927SAndroid Build Coastguard Worker dev.dev = fd_device_open();
120*61046927SAndroid Build Coastguard Worker if (!dev.dev)
121*61046927SAndroid Build Coastguard Worker err(1, "could not open drm device");
122*61046927SAndroid Build Coastguard Worker
123*61046927SAndroid Build Coastguard Worker dev.pipe = fd_pipe_new(dev.dev, FD_PIPE_3D);
124*61046927SAndroid Build Coastguard Worker
125*61046927SAndroid Build Coastguard Worker dev.dev_id = fd_pipe_dev_id(dev.pipe);
126*61046927SAndroid Build Coastguard Worker if (!fd_dev_info_raw(dev.dev_id))
127*61046927SAndroid Build Coastguard Worker err(1, "unknown device");
128*61046927SAndroid Build Coastguard Worker
129*61046927SAndroid Build Coastguard Worker printf("device: %s\n", fd_dev_name(dev.dev_id));
130*61046927SAndroid Build Coastguard Worker
131*61046927SAndroid Build Coastguard Worker /* try MAX_FREQ first as that will work regardless of old dt
132*61046927SAndroid Build Coastguard Worker * dt bindings vs upstream bindings:
133*61046927SAndroid Build Coastguard Worker */
134*61046927SAndroid Build Coastguard Worker uint64_t val;
135*61046927SAndroid Build Coastguard Worker ret = fd_pipe_get_param(dev.pipe, FD_MAX_FREQ, &val);
136*61046927SAndroid Build Coastguard Worker if (ret) {
137*61046927SAndroid Build Coastguard Worker printf("falling back to parsing DT bindings for freq\n");
138*61046927SAndroid Build Coastguard Worker if (!fd_dt_find_freqs(&dev.min_freq, &dev.max_freq))
139*61046927SAndroid Build Coastguard Worker err(1, "could not find GPU freqs");
140*61046927SAndroid Build Coastguard Worker } else {
141*61046927SAndroid Build Coastguard Worker dev.min_freq = 0;
142*61046927SAndroid Build Coastguard Worker dev.max_freq = val;
143*61046927SAndroid Build Coastguard Worker }
144*61046927SAndroid Build Coastguard Worker
145*61046927SAndroid Build Coastguard Worker printf("min_freq=%u, max_freq=%u\n", dev.min_freq, dev.max_freq);
146*61046927SAndroid Build Coastguard Worker
147*61046927SAndroid Build Coastguard Worker dev.io = fd_dt_find_io();
148*61046927SAndroid Build Coastguard Worker if (!dev.io) {
149*61046927SAndroid Build Coastguard Worker err(1, "could not map device");
150*61046927SAndroid Build Coastguard Worker }
151*61046927SAndroid Build Coastguard Worker
152*61046927SAndroid Build Coastguard Worker fd_pipe_set_param(dev.pipe, FD_SYSPROF, 1);
153*61046927SAndroid Build Coastguard Worker }
154*61046927SAndroid Build Coastguard Worker
155*61046927SAndroid Build Coastguard Worker /*
156*61046927SAndroid Build Coastguard Worker * perf-monitor
157*61046927SAndroid Build Coastguard Worker */
158*61046927SAndroid Build Coastguard Worker
159*61046927SAndroid Build Coastguard Worker static void
flush_ring(void)160*61046927SAndroid Build Coastguard Worker flush_ring(void)
161*61046927SAndroid Build Coastguard Worker {
162*61046927SAndroid Build Coastguard Worker if (!dev.submit)
163*61046927SAndroid Build Coastguard Worker return;
164*61046927SAndroid Build Coastguard Worker
165*61046927SAndroid Build Coastguard Worker struct fd_fence *fence = fd_submit_flush(dev.submit, -1, false);
166*61046927SAndroid Build Coastguard Worker
167*61046927SAndroid Build Coastguard Worker if (!fence)
168*61046927SAndroid Build Coastguard Worker errx(1, "submit failed");
169*61046927SAndroid Build Coastguard Worker
170*61046927SAndroid Build Coastguard Worker fd_fence_flush(fence);
171*61046927SAndroid Build Coastguard Worker fd_fence_del(fence);
172*61046927SAndroid Build Coastguard Worker fd_ringbuffer_del(dev.ring);
173*61046927SAndroid Build Coastguard Worker fd_submit_del(dev.submit);
174*61046927SAndroid Build Coastguard Worker
175*61046927SAndroid Build Coastguard Worker dev.ring = NULL;
176*61046927SAndroid Build Coastguard Worker dev.submit = NULL;
177*61046927SAndroid Build Coastguard Worker }
178*61046927SAndroid Build Coastguard Worker
179*61046927SAndroid Build Coastguard Worker static void
select_counter(struct counter_group * group,int ctr,int countable_val)180*61046927SAndroid Build Coastguard Worker select_counter(struct counter_group *group, int ctr, int countable_val)
181*61046927SAndroid Build Coastguard Worker {
182*61046927SAndroid Build Coastguard Worker assert(ctr < group->group->num_counters);
183*61046927SAndroid Build Coastguard Worker
184*61046927SAndroid Build Coastguard Worker unsigned countable_idx = UINT32_MAX;
185*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < group->group->num_countables; i++) {
186*61046927SAndroid Build Coastguard Worker if (countable_val != group->group->countables[i].selector)
187*61046927SAndroid Build Coastguard Worker continue;
188*61046927SAndroid Build Coastguard Worker
189*61046927SAndroid Build Coastguard Worker countable_idx = i;
190*61046927SAndroid Build Coastguard Worker break;
191*61046927SAndroid Build Coastguard Worker }
192*61046927SAndroid Build Coastguard Worker
193*61046927SAndroid Build Coastguard Worker if (countable_idx >= group->group->num_countables)
194*61046927SAndroid Build Coastguard Worker return;
195*61046927SAndroid Build Coastguard Worker
196*61046927SAndroid Build Coastguard Worker group->label[ctr] = group->group->countables[countable_idx].name;
197*61046927SAndroid Build Coastguard Worker group->counter[ctr].select_val = countable_val;
198*61046927SAndroid Build Coastguard Worker
199*61046927SAndroid Build Coastguard Worker if (!dev.submit) {
200*61046927SAndroid Build Coastguard Worker dev.submit = fd_submit_new(dev.pipe);
201*61046927SAndroid Build Coastguard Worker dev.ring = fd_submit_new_ringbuffer(
202*61046927SAndroid Build Coastguard Worker dev.submit, 0x1000, FD_RINGBUFFER_PRIMARY | FD_RINGBUFFER_GROWABLE);
203*61046927SAndroid Build Coastguard Worker }
204*61046927SAndroid Build Coastguard Worker
205*61046927SAndroid Build Coastguard Worker /* bashing select register directly while gpu is active will end
206*61046927SAndroid Build Coastguard Worker * in tears.. so we need to write it via the ring:
207*61046927SAndroid Build Coastguard Worker *
208*61046927SAndroid Build Coastguard Worker * TODO it would help startup time, if gpu is loaded, to batch
209*61046927SAndroid Build Coastguard Worker * all the initial writes and do a single flush.. although that
210*61046927SAndroid Build Coastguard Worker * makes things more complicated for capturing inital sample value
211*61046927SAndroid Build Coastguard Worker */
212*61046927SAndroid Build Coastguard Worker struct fd_ringbuffer *ring = dev.ring;
213*61046927SAndroid Build Coastguard Worker switch (fd_dev_gen(dev.dev_id)) {
214*61046927SAndroid Build Coastguard Worker case 2:
215*61046927SAndroid Build Coastguard Worker case 3:
216*61046927SAndroid Build Coastguard Worker case 4:
217*61046927SAndroid Build Coastguard Worker OUT_PKT3(ring, CP_WAIT_FOR_IDLE, 1);
218*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 0x00000000);
219*61046927SAndroid Build Coastguard Worker
220*61046927SAndroid Build Coastguard Worker if (group->group->counters[ctr].enable) {
221*61046927SAndroid Build Coastguard Worker OUT_PKT0(ring, group->group->counters[ctr].enable, 1);
222*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 0);
223*61046927SAndroid Build Coastguard Worker }
224*61046927SAndroid Build Coastguard Worker
225*61046927SAndroid Build Coastguard Worker if (group->group->counters[ctr].clear) {
226*61046927SAndroid Build Coastguard Worker OUT_PKT0(ring, group->group->counters[ctr].clear, 1);
227*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 1);
228*61046927SAndroid Build Coastguard Worker
229*61046927SAndroid Build Coastguard Worker OUT_PKT0(ring, group->group->counters[ctr].clear, 1);
230*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 0);
231*61046927SAndroid Build Coastguard Worker }
232*61046927SAndroid Build Coastguard Worker
233*61046927SAndroid Build Coastguard Worker OUT_PKT0(ring, group->group->counters[ctr].select_reg, 1);
234*61046927SAndroid Build Coastguard Worker OUT_RING(ring, countable_val);
235*61046927SAndroid Build Coastguard Worker
236*61046927SAndroid Build Coastguard Worker if (group->group->counters[ctr].enable) {
237*61046927SAndroid Build Coastguard Worker OUT_PKT0(ring, group->group->counters[ctr].enable, 1);
238*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 1);
239*61046927SAndroid Build Coastguard Worker }
240*61046927SAndroid Build Coastguard Worker
241*61046927SAndroid Build Coastguard Worker break;
242*61046927SAndroid Build Coastguard Worker case 5:
243*61046927SAndroid Build Coastguard Worker case 6:
244*61046927SAndroid Build Coastguard Worker case 7:
245*61046927SAndroid Build Coastguard Worker OUT_PKT7(ring, CP_WAIT_FOR_IDLE, 0);
246*61046927SAndroid Build Coastguard Worker
247*61046927SAndroid Build Coastguard Worker if (group->group->counters[ctr].enable) {
248*61046927SAndroid Build Coastguard Worker OUT_PKT4(ring, group->group->counters[ctr].enable, 1);
249*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 0);
250*61046927SAndroid Build Coastguard Worker }
251*61046927SAndroid Build Coastguard Worker
252*61046927SAndroid Build Coastguard Worker if (group->group->counters[ctr].clear) {
253*61046927SAndroid Build Coastguard Worker OUT_PKT4(ring, group->group->counters[ctr].clear, 1);
254*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 1);
255*61046927SAndroid Build Coastguard Worker
256*61046927SAndroid Build Coastguard Worker OUT_PKT4(ring, group->group->counters[ctr].clear, 1);
257*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 0);
258*61046927SAndroid Build Coastguard Worker }
259*61046927SAndroid Build Coastguard Worker
260*61046927SAndroid Build Coastguard Worker OUT_PKT4(ring, group->group->counters[ctr].select_reg, 1);
261*61046927SAndroid Build Coastguard Worker OUT_RING(ring, countable_val);
262*61046927SAndroid Build Coastguard Worker
263*61046927SAndroid Build Coastguard Worker if (group->group->counters[ctr].enable) {
264*61046927SAndroid Build Coastguard Worker OUT_PKT4(ring, group->group->counters[ctr].enable, 1);
265*61046927SAndroid Build Coastguard Worker OUT_RING(ring, 1);
266*61046927SAndroid Build Coastguard Worker }
267*61046927SAndroid Build Coastguard Worker
268*61046927SAndroid Build Coastguard Worker break;
269*61046927SAndroid Build Coastguard Worker }
270*61046927SAndroid Build Coastguard Worker }
271*61046927SAndroid Build Coastguard Worker
load_counter_value(struct counter_group * group,int ctr)272*61046927SAndroid Build Coastguard Worker static uint64_t load_counter_value(struct counter_group *group, int ctr)
273*61046927SAndroid Build Coastguard Worker {
274*61046927SAndroid Build Coastguard Worker /* We can read the counter register value as an uint64_t, as long as the
275*61046927SAndroid Build Coastguard Worker * lo/hi addresses are neighboring and the lo address is 8-byte-aligned.
276*61046927SAndroid Build Coastguard Worker * This currently holds for all counters exposed in perfcounter groups.
277*61046927SAndroid Build Coastguard Worker */
278*61046927SAndroid Build Coastguard Worker const struct fd_perfcntr_counter *counter = group->counter[ctr].counter;
279*61046927SAndroid Build Coastguard Worker assert(counter->counter_reg_lo + 1 == counter->counter_reg_hi);
280*61046927SAndroid Build Coastguard Worker assert(!((counter->counter_reg_lo * 4) % 8));
281*61046927SAndroid Build Coastguard Worker return *((uint64_t *) (dev.io + counter->counter_reg_lo * 4));
282*61046927SAndroid Build Coastguard Worker }
283*61046927SAndroid Build Coastguard Worker
284*61046927SAndroid Build Coastguard Worker static void
resample_counter(struct counter_group * group,int ctr,uint64_t sample_time)285*61046927SAndroid Build Coastguard Worker resample_counter(struct counter_group *group, int ctr, uint64_t sample_time)
286*61046927SAndroid Build Coastguard Worker {
287*61046927SAndroid Build Coastguard Worker uint64_t previous_value = group->value[ctr];
288*61046927SAndroid Build Coastguard Worker group->value[ctr] = load_counter_value(group, ctr);
289*61046927SAndroid Build Coastguard Worker group->value_delta[ctr] = delta(previous_value, group->value[ctr]);
290*61046927SAndroid Build Coastguard Worker
291*61046927SAndroid Build Coastguard Worker uint64_t previous_sample_time = group->sample_time[ctr];
292*61046927SAndroid Build Coastguard Worker group->sample_time[ctr] = sample_time;
293*61046927SAndroid Build Coastguard Worker group->sample_time_delta[ctr] = delta(previous_sample_time, sample_time);
294*61046927SAndroid Build Coastguard Worker }
295*61046927SAndroid Build Coastguard Worker
296*61046927SAndroid Build Coastguard Worker /* sample all the counters: */
297*61046927SAndroid Build Coastguard Worker static void
resample(void)298*61046927SAndroid Build Coastguard Worker resample(void)
299*61046927SAndroid Build Coastguard Worker {
300*61046927SAndroid Build Coastguard Worker static uint64_t last_time;
301*61046927SAndroid Build Coastguard Worker uint64_t current_time = gettime_us();
302*61046927SAndroid Build Coastguard Worker
303*61046927SAndroid Build Coastguard Worker if ((current_time - last_time) < (options.refresh_ms * 1000 / 2))
304*61046927SAndroid Build Coastguard Worker return;
305*61046927SAndroid Build Coastguard Worker
306*61046927SAndroid Build Coastguard Worker last_time = current_time;
307*61046927SAndroid Build Coastguard Worker
308*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < dev.ngroups; i++) {
309*61046927SAndroid Build Coastguard Worker struct counter_group *group = &dev.groups[i];
310*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < group->group->num_counters; j++) {
311*61046927SAndroid Build Coastguard Worker resample_counter(group, j, current_time);
312*61046927SAndroid Build Coastguard Worker }
313*61046927SAndroid Build Coastguard Worker }
314*61046927SAndroid Build Coastguard Worker }
315*61046927SAndroid Build Coastguard Worker
316*61046927SAndroid Build Coastguard Worker /*
317*61046927SAndroid Build Coastguard Worker * The UI
318*61046927SAndroid Build Coastguard Worker */
319*61046927SAndroid Build Coastguard Worker
320*61046927SAndroid Build Coastguard Worker #define COLOR_GROUP_HEADER 1
321*61046927SAndroid Build Coastguard Worker #define COLOR_FOOTER 2
322*61046927SAndroid Build Coastguard Worker #define COLOR_INVERSE 3
323*61046927SAndroid Build Coastguard Worker
324*61046927SAndroid Build Coastguard Worker static int w, h;
325*61046927SAndroid Build Coastguard Worker static int ctr_width;
326*61046927SAndroid Build Coastguard Worker static int max_rows, current_cntr = 1;
327*61046927SAndroid Build Coastguard Worker
328*61046927SAndroid Build Coastguard Worker static void
redraw_footer(WINDOW * win)329*61046927SAndroid Build Coastguard Worker redraw_footer(WINDOW *win)
330*61046927SAndroid Build Coastguard Worker {
331*61046927SAndroid Build Coastguard Worker char footer[128];
332*61046927SAndroid Build Coastguard Worker int n = snprintf(footer, sizeof(footer), " fdperf: %s (%.2fMHz..%.2fMHz)",
333*61046927SAndroid Build Coastguard Worker fd_dev_name(dev.dev_id), ((float)dev.min_freq) / 1000000.0,
334*61046927SAndroid Build Coastguard Worker ((float)dev.max_freq) / 1000000.0);
335*61046927SAndroid Build Coastguard Worker
336*61046927SAndroid Build Coastguard Worker wmove(win, h - 1, 0);
337*61046927SAndroid Build Coastguard Worker wattron(win, COLOR_PAIR(COLOR_FOOTER));
338*61046927SAndroid Build Coastguard Worker waddstr(win, footer);
339*61046927SAndroid Build Coastguard Worker whline(win, ' ', w - n);
340*61046927SAndroid Build Coastguard Worker wattroff(win, COLOR_PAIR(COLOR_FOOTER));
341*61046927SAndroid Build Coastguard Worker }
342*61046927SAndroid Build Coastguard Worker
343*61046927SAndroid Build Coastguard Worker static void
redraw_group_header(WINDOW * win,int row,const char * name)344*61046927SAndroid Build Coastguard Worker redraw_group_header(WINDOW *win, int row, const char *name)
345*61046927SAndroid Build Coastguard Worker {
346*61046927SAndroid Build Coastguard Worker wmove(win, row, 0);
347*61046927SAndroid Build Coastguard Worker wattron(win, A_BOLD);
348*61046927SAndroid Build Coastguard Worker wattron(win, COLOR_PAIR(COLOR_GROUP_HEADER));
349*61046927SAndroid Build Coastguard Worker waddstr(win, name);
350*61046927SAndroid Build Coastguard Worker whline(win, ' ', w - strlen(name));
351*61046927SAndroid Build Coastguard Worker wattroff(win, COLOR_PAIR(COLOR_GROUP_HEADER));
352*61046927SAndroid Build Coastguard Worker wattroff(win, A_BOLD);
353*61046927SAndroid Build Coastguard Worker }
354*61046927SAndroid Build Coastguard Worker
355*61046927SAndroid Build Coastguard Worker static void
redraw_counter_label(WINDOW * win,int row,const char * name,bool selected)356*61046927SAndroid Build Coastguard Worker redraw_counter_label(WINDOW *win, int row, const char *name, bool selected)
357*61046927SAndroid Build Coastguard Worker {
358*61046927SAndroid Build Coastguard Worker int n = strlen(name);
359*61046927SAndroid Build Coastguard Worker assert(n <= ctr_width);
360*61046927SAndroid Build Coastguard Worker wmove(win, row, 0);
361*61046927SAndroid Build Coastguard Worker whline(win, ' ', ctr_width - n);
362*61046927SAndroid Build Coastguard Worker wmove(win, row, ctr_width - n);
363*61046927SAndroid Build Coastguard Worker if (selected)
364*61046927SAndroid Build Coastguard Worker wattron(win, COLOR_PAIR(COLOR_INVERSE));
365*61046927SAndroid Build Coastguard Worker waddstr(win, name);
366*61046927SAndroid Build Coastguard Worker if (selected)
367*61046927SAndroid Build Coastguard Worker wattroff(win, COLOR_PAIR(COLOR_INVERSE));
368*61046927SAndroid Build Coastguard Worker waddstr(win, ": ");
369*61046927SAndroid Build Coastguard Worker }
370*61046927SAndroid Build Coastguard Worker
371*61046927SAndroid Build Coastguard Worker static void
redraw_counter_value_cycles(WINDOW * win,float val)372*61046927SAndroid Build Coastguard Worker redraw_counter_value_cycles(WINDOW *win, float val)
373*61046927SAndroid Build Coastguard Worker {
374*61046927SAndroid Build Coastguard Worker char str[32];
375*61046927SAndroid Build Coastguard Worker int x = getcurx(win);
376*61046927SAndroid Build Coastguard Worker int valwidth = w - x;
377*61046927SAndroid Build Coastguard Worker int barwidth, n;
378*61046927SAndroid Build Coastguard Worker
379*61046927SAndroid Build Coastguard Worker /* convert to fraction of max freq: */
380*61046927SAndroid Build Coastguard Worker val = val / (float)dev.max_freq;
381*61046927SAndroid Build Coastguard Worker
382*61046927SAndroid Build Coastguard Worker /* figure out percentage-bar width: */
383*61046927SAndroid Build Coastguard Worker barwidth = (int)(val * valwidth);
384*61046927SAndroid Build Coastguard Worker
385*61046927SAndroid Build Coastguard Worker /* sometimes things go over 100%.. idk why, could be
386*61046927SAndroid Build Coastguard Worker * things running faster than base clock, or counter
387*61046927SAndroid Build Coastguard Worker * summing up cycles in multiple cores?
388*61046927SAndroid Build Coastguard Worker */
389*61046927SAndroid Build Coastguard Worker barwidth = MIN2(barwidth, valwidth - 1);
390*61046927SAndroid Build Coastguard Worker
391*61046927SAndroid Build Coastguard Worker n = snprintf(str, sizeof(str), "%.2f%%", 100.0 * val);
392*61046927SAndroid Build Coastguard Worker wattron(win, COLOR_PAIR(COLOR_INVERSE));
393*61046927SAndroid Build Coastguard Worker waddnstr(win, str, barwidth);
394*61046927SAndroid Build Coastguard Worker if (barwidth > n) {
395*61046927SAndroid Build Coastguard Worker whline(win, ' ', barwidth - n);
396*61046927SAndroid Build Coastguard Worker wmove(win, getcury(win), x + barwidth);
397*61046927SAndroid Build Coastguard Worker }
398*61046927SAndroid Build Coastguard Worker wattroff(win, COLOR_PAIR(COLOR_INVERSE));
399*61046927SAndroid Build Coastguard Worker if (barwidth < n)
400*61046927SAndroid Build Coastguard Worker waddstr(win, str + barwidth);
401*61046927SAndroid Build Coastguard Worker whline(win, ' ', w - getcurx(win));
402*61046927SAndroid Build Coastguard Worker }
403*61046927SAndroid Build Coastguard Worker
404*61046927SAndroid Build Coastguard Worker static void
redraw_counter_value(WINDOW * win,int row,struct counter_group * group,int ctr)405*61046927SAndroid Build Coastguard Worker redraw_counter_value(WINDOW *win, int row, struct counter_group *group, int ctr)
406*61046927SAndroid Build Coastguard Worker {
407*61046927SAndroid Build Coastguard Worker char str[32];
408*61046927SAndroid Build Coastguard Worker int n = snprintf(str, sizeof(str), "%" PRIu64 " ", group->value_delta[ctr]);
409*61046927SAndroid Build Coastguard Worker
410*61046927SAndroid Build Coastguard Worker whline(win, ' ', 24 - n);
411*61046927SAndroid Build Coastguard Worker wmove(win, row, getcurx(win) + 24 - n);
412*61046927SAndroid Build Coastguard Worker waddstr(win, str);
413*61046927SAndroid Build Coastguard Worker
414*61046927SAndroid Build Coastguard Worker /* quick hack, if the label has "CYCLE" in the name, it is
415*61046927SAndroid Build Coastguard Worker * probably a cycle counter ;-)
416*61046927SAndroid Build Coastguard Worker * Perhaps add more info in rnndb schema to know how to
417*61046927SAndroid Build Coastguard Worker * treat individual counters (ie. which are cycles, and
418*61046927SAndroid Build Coastguard Worker * for those we want to present as a percentage do we
419*61046927SAndroid Build Coastguard Worker * need to scale the result.. ie. is it running at some
420*61046927SAndroid Build Coastguard Worker * multiple or divisor of core clk, etc)
421*61046927SAndroid Build Coastguard Worker *
422*61046927SAndroid Build Coastguard Worker * TODO it would be much more clever to get this from xml
423*61046927SAndroid Build Coastguard Worker * Also.. in some cases I think we want to know how many
424*61046927SAndroid Build Coastguard Worker * units the counter is counting for, ie. if a320 has 2x
425*61046927SAndroid Build Coastguard Worker * shader as a306 we might need to scale the result..
426*61046927SAndroid Build Coastguard Worker */
427*61046927SAndroid Build Coastguard Worker if (strstr(group->label[ctr], "CYCLE") ||
428*61046927SAndroid Build Coastguard Worker strstr(group->label[ctr], "BUSY") || strstr(group->label[ctr], "IDLE")) {
429*61046927SAndroid Build Coastguard Worker float cycles_val = (float) group->value_delta[ctr] * 1000000.0 /
430*61046927SAndroid Build Coastguard Worker (float) group->sample_time_delta[ctr];
431*61046927SAndroid Build Coastguard Worker redraw_counter_value_cycles(win, cycles_val);
432*61046927SAndroid Build Coastguard Worker } else {
433*61046927SAndroid Build Coastguard Worker whline(win, ' ', w - getcurx(win));
434*61046927SAndroid Build Coastguard Worker }
435*61046927SAndroid Build Coastguard Worker }
436*61046927SAndroid Build Coastguard Worker
437*61046927SAndroid Build Coastguard Worker static void
redraw_counter(WINDOW * win,int row,struct counter_group * group,int ctr,bool selected)438*61046927SAndroid Build Coastguard Worker redraw_counter(WINDOW *win, int row, struct counter_group *group, int ctr,
439*61046927SAndroid Build Coastguard Worker bool selected)
440*61046927SAndroid Build Coastguard Worker {
441*61046927SAndroid Build Coastguard Worker redraw_counter_label(win, row, group->label[ctr], selected);
442*61046927SAndroid Build Coastguard Worker redraw_counter_value(win, row, group, ctr);
443*61046927SAndroid Build Coastguard Worker }
444*61046927SAndroid Build Coastguard Worker
445*61046927SAndroid Build Coastguard Worker static void
redraw_gpufreq_counter(WINDOW * win,int row)446*61046927SAndroid Build Coastguard Worker redraw_gpufreq_counter(WINDOW *win, int row)
447*61046927SAndroid Build Coastguard Worker {
448*61046927SAndroid Build Coastguard Worker redraw_counter_label(win, row, "Freq (MHz)", false);
449*61046927SAndroid Build Coastguard Worker
450*61046927SAndroid Build Coastguard Worker struct counter_group *group = &dev.groups[0];
451*61046927SAndroid Build Coastguard Worker float freq_val = (float) group->value_delta[0] / (float) group->sample_time_delta[0];
452*61046927SAndroid Build Coastguard Worker
453*61046927SAndroid Build Coastguard Worker char str[32];
454*61046927SAndroid Build Coastguard Worker snprintf(str, sizeof(str), "%.2f", freq_val);
455*61046927SAndroid Build Coastguard Worker
456*61046927SAndroid Build Coastguard Worker waddstr(win, str);
457*61046927SAndroid Build Coastguard Worker whline(win, ' ', w - getcurx(win));
458*61046927SAndroid Build Coastguard Worker }
459*61046927SAndroid Build Coastguard Worker
460*61046927SAndroid Build Coastguard Worker static void
redraw(WINDOW * win)461*61046927SAndroid Build Coastguard Worker redraw(WINDOW *win)
462*61046927SAndroid Build Coastguard Worker {
463*61046927SAndroid Build Coastguard Worker static int scroll = 0;
464*61046927SAndroid Build Coastguard Worker int max, row = 0;
465*61046927SAndroid Build Coastguard Worker
466*61046927SAndroid Build Coastguard Worker w = getmaxx(win);
467*61046927SAndroid Build Coastguard Worker h = getmaxy(win);
468*61046927SAndroid Build Coastguard Worker
469*61046927SAndroid Build Coastguard Worker max = h - 3;
470*61046927SAndroid Build Coastguard Worker
471*61046927SAndroid Build Coastguard Worker if ((current_cntr - scroll) > (max - 1)) {
472*61046927SAndroid Build Coastguard Worker scroll = current_cntr - (max - 1);
473*61046927SAndroid Build Coastguard Worker } else if ((current_cntr - 1) < scroll) {
474*61046927SAndroid Build Coastguard Worker scroll = current_cntr - 1;
475*61046927SAndroid Build Coastguard Worker }
476*61046927SAndroid Build Coastguard Worker
477*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < dev.ngroups; i++) {
478*61046927SAndroid Build Coastguard Worker struct counter_group *group = &dev.groups[i];
479*61046927SAndroid Build Coastguard Worker unsigned j = 0;
480*61046927SAndroid Build Coastguard Worker
481*61046927SAndroid Build Coastguard Worker if (group->counter[0].is_gpufreq_counter)
482*61046927SAndroid Build Coastguard Worker j++;
483*61046927SAndroid Build Coastguard Worker
484*61046927SAndroid Build Coastguard Worker if (j < group->group->num_counters) {
485*61046927SAndroid Build Coastguard Worker if ((scroll <= row) && ((row - scroll) < max))
486*61046927SAndroid Build Coastguard Worker redraw_group_header(win, row - scroll, group->group->name);
487*61046927SAndroid Build Coastguard Worker row++;
488*61046927SAndroid Build Coastguard Worker }
489*61046927SAndroid Build Coastguard Worker
490*61046927SAndroid Build Coastguard Worker for (; j < group->group->num_counters; j++) {
491*61046927SAndroid Build Coastguard Worker if ((scroll <= row) && ((row - scroll) < max))
492*61046927SAndroid Build Coastguard Worker redraw_counter(win, row - scroll, group, j, row == current_cntr);
493*61046927SAndroid Build Coastguard Worker row++;
494*61046927SAndroid Build Coastguard Worker }
495*61046927SAndroid Build Coastguard Worker }
496*61046927SAndroid Build Coastguard Worker
497*61046927SAndroid Build Coastguard Worker /* convert back to physical (unscrolled) offset: */
498*61046927SAndroid Build Coastguard Worker row = max;
499*61046927SAndroid Build Coastguard Worker
500*61046927SAndroid Build Coastguard Worker redraw_group_header(win, row, "Status");
501*61046927SAndroid Build Coastguard Worker row++;
502*61046927SAndroid Build Coastguard Worker
503*61046927SAndroid Build Coastguard Worker /* Draw GPU freq row: */
504*61046927SAndroid Build Coastguard Worker redraw_gpufreq_counter(win, row);
505*61046927SAndroid Build Coastguard Worker row++;
506*61046927SAndroid Build Coastguard Worker
507*61046927SAndroid Build Coastguard Worker redraw_footer(win);
508*61046927SAndroid Build Coastguard Worker
509*61046927SAndroid Build Coastguard Worker refresh();
510*61046927SAndroid Build Coastguard Worker }
511*61046927SAndroid Build Coastguard Worker
512*61046927SAndroid Build Coastguard Worker static struct counter_group *
current_counter(int * ctr)513*61046927SAndroid Build Coastguard Worker current_counter(int *ctr)
514*61046927SAndroid Build Coastguard Worker {
515*61046927SAndroid Build Coastguard Worker int n = 0;
516*61046927SAndroid Build Coastguard Worker
517*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < dev.ngroups; i++) {
518*61046927SAndroid Build Coastguard Worker struct counter_group *group = &dev.groups[i];
519*61046927SAndroid Build Coastguard Worker unsigned j = 0;
520*61046927SAndroid Build Coastguard Worker
521*61046927SAndroid Build Coastguard Worker if (group->counter[0].is_gpufreq_counter)
522*61046927SAndroid Build Coastguard Worker j++;
523*61046927SAndroid Build Coastguard Worker
524*61046927SAndroid Build Coastguard Worker /* account for group header: */
525*61046927SAndroid Build Coastguard Worker if (j < group->group->num_counters) {
526*61046927SAndroid Build Coastguard Worker /* cannot select group header.. return null to indicate this
527*61046927SAndroid Build Coastguard Worker * main_ui():
528*61046927SAndroid Build Coastguard Worker */
529*61046927SAndroid Build Coastguard Worker if (n == current_cntr)
530*61046927SAndroid Build Coastguard Worker return NULL;
531*61046927SAndroid Build Coastguard Worker n++;
532*61046927SAndroid Build Coastguard Worker }
533*61046927SAndroid Build Coastguard Worker
534*61046927SAndroid Build Coastguard Worker for (; j < group->group->num_counters; j++) {
535*61046927SAndroid Build Coastguard Worker if (n == current_cntr) {
536*61046927SAndroid Build Coastguard Worker if (ctr)
537*61046927SAndroid Build Coastguard Worker *ctr = j;
538*61046927SAndroid Build Coastguard Worker return group;
539*61046927SAndroid Build Coastguard Worker }
540*61046927SAndroid Build Coastguard Worker n++;
541*61046927SAndroid Build Coastguard Worker }
542*61046927SAndroid Build Coastguard Worker }
543*61046927SAndroid Build Coastguard Worker
544*61046927SAndroid Build Coastguard Worker assert(0);
545*61046927SAndroid Build Coastguard Worker return NULL;
546*61046927SAndroid Build Coastguard Worker }
547*61046927SAndroid Build Coastguard Worker
548*61046927SAndroid Build Coastguard Worker static void
counter_dialog(void)549*61046927SAndroid Build Coastguard Worker counter_dialog(void)
550*61046927SAndroid Build Coastguard Worker {
551*61046927SAndroid Build Coastguard Worker WINDOW *dialog;
552*61046927SAndroid Build Coastguard Worker struct counter_group *group;
553*61046927SAndroid Build Coastguard Worker int cnt = 0, current = 0, scroll;
554*61046927SAndroid Build Coastguard Worker
555*61046927SAndroid Build Coastguard Worker /* figure out dialog size: */
556*61046927SAndroid Build Coastguard Worker int dh = h / 2;
557*61046927SAndroid Build Coastguard Worker int dw = ctr_width + 2;
558*61046927SAndroid Build Coastguard Worker
559*61046927SAndroid Build Coastguard Worker group = current_counter(&cnt);
560*61046927SAndroid Build Coastguard Worker
561*61046927SAndroid Build Coastguard Worker /* find currently selected idx (note there can be discontinuities
562*61046927SAndroid Build Coastguard Worker * so the selected value does not map 1:1 to current idx)
563*61046927SAndroid Build Coastguard Worker */
564*61046927SAndroid Build Coastguard Worker uint32_t selected = group->counter[cnt].select_val;
565*61046927SAndroid Build Coastguard Worker for (int i = 0; i < group->group->num_countables; i++) {
566*61046927SAndroid Build Coastguard Worker if (group->group->countables[i].selector == selected) {
567*61046927SAndroid Build Coastguard Worker current = i;
568*61046927SAndroid Build Coastguard Worker break;
569*61046927SAndroid Build Coastguard Worker }
570*61046927SAndroid Build Coastguard Worker }
571*61046927SAndroid Build Coastguard Worker
572*61046927SAndroid Build Coastguard Worker /* scrolling offset, if dialog is too small for all the choices: */
573*61046927SAndroid Build Coastguard Worker scroll = 0;
574*61046927SAndroid Build Coastguard Worker
575*61046927SAndroid Build Coastguard Worker dialog = newwin(dh, dw, (h - dh) / 2, (w - dw) / 2);
576*61046927SAndroid Build Coastguard Worker box(dialog, 0, 0);
577*61046927SAndroid Build Coastguard Worker wrefresh(dialog);
578*61046927SAndroid Build Coastguard Worker keypad(dialog, true);
579*61046927SAndroid Build Coastguard Worker
580*61046927SAndroid Build Coastguard Worker while (true) {
581*61046927SAndroid Build Coastguard Worker int max = MIN2(dh - 2, group->group->num_countables);
582*61046927SAndroid Build Coastguard Worker int selector = -1;
583*61046927SAndroid Build Coastguard Worker
584*61046927SAndroid Build Coastguard Worker if ((current - scroll) >= (dh - 3)) {
585*61046927SAndroid Build Coastguard Worker scroll = current - (dh - 3);
586*61046927SAndroid Build Coastguard Worker } else if (current < scroll) {
587*61046927SAndroid Build Coastguard Worker scroll = current;
588*61046927SAndroid Build Coastguard Worker }
589*61046927SAndroid Build Coastguard Worker
590*61046927SAndroid Build Coastguard Worker for (int i = 0; i < max; i++) {
591*61046927SAndroid Build Coastguard Worker int n = scroll + i;
592*61046927SAndroid Build Coastguard Worker wmove(dialog, i + 1, 1);
593*61046927SAndroid Build Coastguard Worker if (n == current) {
594*61046927SAndroid Build Coastguard Worker assert(n < group->group->num_countables);
595*61046927SAndroid Build Coastguard Worker selector = group->group->countables[n].selector;
596*61046927SAndroid Build Coastguard Worker wattron(dialog, COLOR_PAIR(COLOR_INVERSE));
597*61046927SAndroid Build Coastguard Worker }
598*61046927SAndroid Build Coastguard Worker if (n < group->group->num_countables)
599*61046927SAndroid Build Coastguard Worker waddstr(dialog, group->group->countables[n].name);
600*61046927SAndroid Build Coastguard Worker whline(dialog, ' ', dw - getcurx(dialog) - 1);
601*61046927SAndroid Build Coastguard Worker if (n == current)
602*61046927SAndroid Build Coastguard Worker wattroff(dialog, COLOR_PAIR(COLOR_INVERSE));
603*61046927SAndroid Build Coastguard Worker }
604*61046927SAndroid Build Coastguard Worker
605*61046927SAndroid Build Coastguard Worker assert(selector >= 0);
606*61046927SAndroid Build Coastguard Worker
607*61046927SAndroid Build Coastguard Worker switch (wgetch(dialog)) {
608*61046927SAndroid Build Coastguard Worker case KEY_UP:
609*61046927SAndroid Build Coastguard Worker current = MAX2(0, current - 1);
610*61046927SAndroid Build Coastguard Worker break;
611*61046927SAndroid Build Coastguard Worker case KEY_DOWN:
612*61046927SAndroid Build Coastguard Worker current = MIN2(group->group->num_countables - 1, current + 1);
613*61046927SAndroid Build Coastguard Worker break;
614*61046927SAndroid Build Coastguard Worker case KEY_LEFT:
615*61046927SAndroid Build Coastguard Worker case KEY_ENTER:
616*61046927SAndroid Build Coastguard Worker /* select new sampler */
617*61046927SAndroid Build Coastguard Worker select_counter(group, cnt, selector);
618*61046927SAndroid Build Coastguard Worker flush_ring();
619*61046927SAndroid Build Coastguard Worker config_save();
620*61046927SAndroid Build Coastguard Worker goto out;
621*61046927SAndroid Build Coastguard Worker case 'q':
622*61046927SAndroid Build Coastguard Worker goto out;
623*61046927SAndroid Build Coastguard Worker default:
624*61046927SAndroid Build Coastguard Worker /* ignore */
625*61046927SAndroid Build Coastguard Worker break;
626*61046927SAndroid Build Coastguard Worker }
627*61046927SAndroid Build Coastguard Worker
628*61046927SAndroid Build Coastguard Worker resample();
629*61046927SAndroid Build Coastguard Worker }
630*61046927SAndroid Build Coastguard Worker
631*61046927SAndroid Build Coastguard Worker out:
632*61046927SAndroid Build Coastguard Worker wborder(dialog, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ');
633*61046927SAndroid Build Coastguard Worker delwin(dialog);
634*61046927SAndroid Build Coastguard Worker }
635*61046927SAndroid Build Coastguard Worker
636*61046927SAndroid Build Coastguard Worker static void
scroll_cntr(int amount)637*61046927SAndroid Build Coastguard Worker scroll_cntr(int amount)
638*61046927SAndroid Build Coastguard Worker {
639*61046927SAndroid Build Coastguard Worker if (amount < 0) {
640*61046927SAndroid Build Coastguard Worker current_cntr = MAX2(1, current_cntr + amount);
641*61046927SAndroid Build Coastguard Worker if (current_counter(NULL) == NULL) {
642*61046927SAndroid Build Coastguard Worker current_cntr = MAX2(1, current_cntr - 1);
643*61046927SAndroid Build Coastguard Worker }
644*61046927SAndroid Build Coastguard Worker } else {
645*61046927SAndroid Build Coastguard Worker current_cntr = MIN2(max_rows - 1, current_cntr + amount);
646*61046927SAndroid Build Coastguard Worker if (current_counter(NULL) == NULL)
647*61046927SAndroid Build Coastguard Worker current_cntr = MIN2(max_rows - 1, current_cntr + 1);
648*61046927SAndroid Build Coastguard Worker }
649*61046927SAndroid Build Coastguard Worker }
650*61046927SAndroid Build Coastguard Worker
651*61046927SAndroid Build Coastguard Worker static void
main_ui(void)652*61046927SAndroid Build Coastguard Worker main_ui(void)
653*61046927SAndroid Build Coastguard Worker {
654*61046927SAndroid Build Coastguard Worker WINDOW *mainwin;
655*61046927SAndroid Build Coastguard Worker uint64_t last_time = gettime_us();
656*61046927SAndroid Build Coastguard Worker
657*61046927SAndroid Build Coastguard Worker /* Run an initial sample to set up baseline counter values. */
658*61046927SAndroid Build Coastguard Worker resample();
659*61046927SAndroid Build Coastguard Worker
660*61046927SAndroid Build Coastguard Worker /* curses setup: */
661*61046927SAndroid Build Coastguard Worker mainwin = initscr();
662*61046927SAndroid Build Coastguard Worker if (!mainwin)
663*61046927SAndroid Build Coastguard Worker goto out;
664*61046927SAndroid Build Coastguard Worker
665*61046927SAndroid Build Coastguard Worker cbreak();
666*61046927SAndroid Build Coastguard Worker wtimeout(mainwin, options.refresh_ms);
667*61046927SAndroid Build Coastguard Worker noecho();
668*61046927SAndroid Build Coastguard Worker keypad(mainwin, true);
669*61046927SAndroid Build Coastguard Worker curs_set(0);
670*61046927SAndroid Build Coastguard Worker start_color();
671*61046927SAndroid Build Coastguard Worker init_pair(COLOR_GROUP_HEADER, COLOR_WHITE, COLOR_GREEN);
672*61046927SAndroid Build Coastguard Worker init_pair(COLOR_FOOTER, COLOR_WHITE, COLOR_BLUE);
673*61046927SAndroid Build Coastguard Worker init_pair(COLOR_INVERSE, COLOR_BLACK, COLOR_WHITE);
674*61046927SAndroid Build Coastguard Worker
675*61046927SAndroid Build Coastguard Worker while (true) {
676*61046927SAndroid Build Coastguard Worker switch (wgetch(mainwin)) {
677*61046927SAndroid Build Coastguard Worker case KEY_UP:
678*61046927SAndroid Build Coastguard Worker scroll_cntr(-1);
679*61046927SAndroid Build Coastguard Worker break;
680*61046927SAndroid Build Coastguard Worker case KEY_DOWN:
681*61046927SAndroid Build Coastguard Worker scroll_cntr(+1);
682*61046927SAndroid Build Coastguard Worker break;
683*61046927SAndroid Build Coastguard Worker case KEY_NPAGE: /* page-down */
684*61046927SAndroid Build Coastguard Worker /* TODO figure out # of rows visible? */
685*61046927SAndroid Build Coastguard Worker scroll_cntr(+15);
686*61046927SAndroid Build Coastguard Worker break;
687*61046927SAndroid Build Coastguard Worker case KEY_PPAGE: /* page-up */
688*61046927SAndroid Build Coastguard Worker /* TODO figure out # of rows visible? */
689*61046927SAndroid Build Coastguard Worker scroll_cntr(-15);
690*61046927SAndroid Build Coastguard Worker break;
691*61046927SAndroid Build Coastguard Worker case KEY_RIGHT:
692*61046927SAndroid Build Coastguard Worker counter_dialog();
693*61046927SAndroid Build Coastguard Worker break;
694*61046927SAndroid Build Coastguard Worker case 'q':
695*61046927SAndroid Build Coastguard Worker goto out;
696*61046927SAndroid Build Coastguard Worker break;
697*61046927SAndroid Build Coastguard Worker default:
698*61046927SAndroid Build Coastguard Worker /* ignore */
699*61046927SAndroid Build Coastguard Worker break;
700*61046927SAndroid Build Coastguard Worker }
701*61046927SAndroid Build Coastguard Worker resample();
702*61046927SAndroid Build Coastguard Worker redraw(mainwin);
703*61046927SAndroid Build Coastguard Worker
704*61046927SAndroid Build Coastguard Worker /* restore the counters every 0.5s in case the GPU has suspended,
705*61046927SAndroid Build Coastguard Worker * in which case the current selected countables will have reset:
706*61046927SAndroid Build Coastguard Worker */
707*61046927SAndroid Build Coastguard Worker uint64_t t = gettime_us();
708*61046927SAndroid Build Coastguard Worker if (delta(last_time, t) > 500000) {
709*61046927SAndroid Build Coastguard Worker restore_counter_groups();
710*61046927SAndroid Build Coastguard Worker flush_ring();
711*61046927SAndroid Build Coastguard Worker last_time = t;
712*61046927SAndroid Build Coastguard Worker }
713*61046927SAndroid Build Coastguard Worker }
714*61046927SAndroid Build Coastguard Worker
715*61046927SAndroid Build Coastguard Worker /* restore settings.. maybe we need an atexit()??*/
716*61046927SAndroid Build Coastguard Worker out:
717*61046927SAndroid Build Coastguard Worker delwin(mainwin);
718*61046927SAndroid Build Coastguard Worker endwin();
719*61046927SAndroid Build Coastguard Worker refresh();
720*61046927SAndroid Build Coastguard Worker }
721*61046927SAndroid Build Coastguard Worker
722*61046927SAndroid Build Coastguard Worker static void
dump_counters(void)723*61046927SAndroid Build Coastguard Worker dump_counters(void)
724*61046927SAndroid Build Coastguard Worker {
725*61046927SAndroid Build Coastguard Worker resample();
726*61046927SAndroid Build Coastguard Worker sleep_us(options.refresh_ms * 1000);
727*61046927SAndroid Build Coastguard Worker resample();
728*61046927SAndroid Build Coastguard Worker
729*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < dev.ngroups; i++) {
730*61046927SAndroid Build Coastguard Worker const struct counter_group *group = &dev.groups[i];
731*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < group->group->num_counters; j++) {
732*61046927SAndroid Build Coastguard Worker const char *label = group->label[j];
733*61046927SAndroid Build Coastguard Worker float val = (float) group->value_delta[j] * 1000000.0 /
734*61046927SAndroid Build Coastguard Worker (float) group->sample_time_delta[j];
735*61046927SAndroid Build Coastguard Worker
736*61046927SAndroid Build Coastguard Worker int n = printf("%s: ", label) - 2;
737*61046927SAndroid Build Coastguard Worker while (n++ < ctr_width)
738*61046927SAndroid Build Coastguard Worker fputc(' ', stdout);
739*61046927SAndroid Build Coastguard Worker
740*61046927SAndroid Build Coastguard Worker n = printf("%" PRIu64, group->value_delta[j]);
741*61046927SAndroid Build Coastguard Worker while (n++ < 24)
742*61046927SAndroid Build Coastguard Worker fputc(' ', stdout);
743*61046927SAndroid Build Coastguard Worker
744*61046927SAndroid Build Coastguard Worker if (strstr(label, "CYCLE") ||
745*61046927SAndroid Build Coastguard Worker strstr(label, "BUSY") ||
746*61046927SAndroid Build Coastguard Worker strstr(label, "IDLE")) {
747*61046927SAndroid Build Coastguard Worker val = val / dev.max_freq * 100.0f;
748*61046927SAndroid Build Coastguard Worker printf(" %.2f%%\n", val);
749*61046927SAndroid Build Coastguard Worker } else {
750*61046927SAndroid Build Coastguard Worker printf("\n");
751*61046927SAndroid Build Coastguard Worker }
752*61046927SAndroid Build Coastguard Worker }
753*61046927SAndroid Build Coastguard Worker }
754*61046927SAndroid Build Coastguard Worker }
755*61046927SAndroid Build Coastguard Worker
756*61046927SAndroid Build Coastguard Worker static void
restore_counter_groups(void)757*61046927SAndroid Build Coastguard Worker restore_counter_groups(void)
758*61046927SAndroid Build Coastguard Worker {
759*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < dev.ngroups; i++) {
760*61046927SAndroid Build Coastguard Worker struct counter_group *group = &dev.groups[i];
761*61046927SAndroid Build Coastguard Worker
762*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < group->group->num_counters; j++) {
763*61046927SAndroid Build Coastguard Worker /* This should also write the CP_ALWAYS_COUNT selectable value into
764*61046927SAndroid Build Coastguard Worker * the reserved CP counter we use for GPU frequency measurement,
765*61046927SAndroid Build Coastguard Worker * avoiding someone else writing a different value there.
766*61046927SAndroid Build Coastguard Worker */
767*61046927SAndroid Build Coastguard Worker select_counter(group, j, group->counter[j].select_val);
768*61046927SAndroid Build Coastguard Worker }
769*61046927SAndroid Build Coastguard Worker }
770*61046927SAndroid Build Coastguard Worker }
771*61046927SAndroid Build Coastguard Worker
772*61046927SAndroid Build Coastguard Worker static void
setup_counter_groups(const struct fd_perfcntr_group * groups)773*61046927SAndroid Build Coastguard Worker setup_counter_groups(const struct fd_perfcntr_group *groups)
774*61046927SAndroid Build Coastguard Worker {
775*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < dev.ngroups; i++) {
776*61046927SAndroid Build Coastguard Worker struct counter_group *group = &dev.groups[i];
777*61046927SAndroid Build Coastguard Worker
778*61046927SAndroid Build Coastguard Worker group->group = &groups[i];
779*61046927SAndroid Build Coastguard Worker
780*61046927SAndroid Build Coastguard Worker max_rows += group->group->num_counters + 1;
781*61046927SAndroid Build Coastguard Worker
782*61046927SAndroid Build Coastguard Worker /* We reserve the first counter of the CP group (first in the list) for
783*61046927SAndroid Build Coastguard Worker * measuring GPU frequency that's displayed in the footer.
784*61046927SAndroid Build Coastguard Worker */
785*61046927SAndroid Build Coastguard Worker if (i == 0) {
786*61046927SAndroid Build Coastguard Worker /* We won't be displaying the private counter alongside others. We
787*61046927SAndroid Build Coastguard Worker * also won't be displaying the group header if we're taking over
788*61046927SAndroid Build Coastguard Worker * the only counter (e.g. on a2xx).
789*61046927SAndroid Build Coastguard Worker */
790*61046927SAndroid Build Coastguard Worker max_rows--;
791*61046927SAndroid Build Coastguard Worker if (groups[0].num_counters < 2)
792*61046927SAndroid Build Coastguard Worker max_rows--;
793*61046927SAndroid Build Coastguard Worker
794*61046927SAndroid Build Coastguard Worker /* Enforce the CP_ALWAYS_COUNT countable for this counter. */
795*61046927SAndroid Build Coastguard Worker unsigned always_count_index = UINT32_MAX;
796*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < groups[0].num_countables; ++i) {
797*61046927SAndroid Build Coastguard Worker if (strcmp(groups[0].countables[i].name, "PERF_CP_ALWAYS_COUNT"))
798*61046927SAndroid Build Coastguard Worker continue;
799*61046927SAndroid Build Coastguard Worker
800*61046927SAndroid Build Coastguard Worker always_count_index = i;
801*61046927SAndroid Build Coastguard Worker break;
802*61046927SAndroid Build Coastguard Worker }
803*61046927SAndroid Build Coastguard Worker
804*61046927SAndroid Build Coastguard Worker if (always_count_index < groups[0].num_countables) {
805*61046927SAndroid Build Coastguard Worker group->counter[0].select_val = groups[0].countables[always_count_index].selector;
806*61046927SAndroid Build Coastguard Worker group->counter[0].is_gpufreq_counter = true;
807*61046927SAndroid Build Coastguard Worker }
808*61046927SAndroid Build Coastguard Worker }
809*61046927SAndroid Build Coastguard Worker
810*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < group->group->num_counters; j++) {
811*61046927SAndroid Build Coastguard Worker group->counter[j].counter = &group->group->counters[j];
812*61046927SAndroid Build Coastguard Worker
813*61046927SAndroid Build Coastguard Worker if (!group->counter[j].is_gpufreq_counter)
814*61046927SAndroid Build Coastguard Worker group->counter[j].select_val = j;
815*61046927SAndroid Build Coastguard Worker }
816*61046927SAndroid Build Coastguard Worker
817*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < group->group->num_countables; j++) {
818*61046927SAndroid Build Coastguard Worker ctr_width =
819*61046927SAndroid Build Coastguard Worker MAX2(ctr_width, strlen(group->group->countables[j].name) + 1);
820*61046927SAndroid Build Coastguard Worker }
821*61046927SAndroid Build Coastguard Worker }
822*61046927SAndroid Build Coastguard Worker }
823*61046927SAndroid Build Coastguard Worker
824*61046927SAndroid Build Coastguard Worker /*
825*61046927SAndroid Build Coastguard Worker * configuration / persistence
826*61046927SAndroid Build Coastguard Worker */
827*61046927SAndroid Build Coastguard Worker
828*61046927SAndroid Build Coastguard Worker static config_t cfg;
829*61046927SAndroid Build Coastguard Worker static config_setting_t *setting;
830*61046927SAndroid Build Coastguard Worker
831*61046927SAndroid Build Coastguard Worker static void
config_save(void)832*61046927SAndroid Build Coastguard Worker config_save(void)
833*61046927SAndroid Build Coastguard Worker {
834*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < dev.ngroups; i++) {
835*61046927SAndroid Build Coastguard Worker struct counter_group *group = &dev.groups[i];
836*61046927SAndroid Build Coastguard Worker config_setting_t *sect =
837*61046927SAndroid Build Coastguard Worker config_setting_get_member(setting, group->group->name);
838*61046927SAndroid Build Coastguard Worker
839*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < group->group->num_counters; j++) {
840*61046927SAndroid Build Coastguard Worker /* Don't save the GPU frequency measurement counter. */
841*61046927SAndroid Build Coastguard Worker if (group->counter[j].is_gpufreq_counter)
842*61046927SAndroid Build Coastguard Worker continue;
843*61046927SAndroid Build Coastguard Worker
844*61046927SAndroid Build Coastguard Worker char name[] = "counter0000";
845*61046927SAndroid Build Coastguard Worker sprintf(name, "counter%d", j);
846*61046927SAndroid Build Coastguard Worker config_setting_t *s = config_setting_lookup(sect, name);
847*61046927SAndroid Build Coastguard Worker config_setting_set_int(s, group->counter[j].select_val);
848*61046927SAndroid Build Coastguard Worker }
849*61046927SAndroid Build Coastguard Worker }
850*61046927SAndroid Build Coastguard Worker
851*61046927SAndroid Build Coastguard Worker config_write_file(&cfg, "fdperf.cfg");
852*61046927SAndroid Build Coastguard Worker }
853*61046927SAndroid Build Coastguard Worker
854*61046927SAndroid Build Coastguard Worker static void
config_restore(void)855*61046927SAndroid Build Coastguard Worker config_restore(void)
856*61046927SAndroid Build Coastguard Worker {
857*61046927SAndroid Build Coastguard Worker config_init(&cfg);
858*61046927SAndroid Build Coastguard Worker
859*61046927SAndroid Build Coastguard Worker /* Read the file. If there is an error, report it and exit. */
860*61046927SAndroid Build Coastguard Worker if (!config_read_file(&cfg, "fdperf.cfg")) {
861*61046927SAndroid Build Coastguard Worker warn("could not restore settings");
862*61046927SAndroid Build Coastguard Worker }
863*61046927SAndroid Build Coastguard Worker
864*61046927SAndroid Build Coastguard Worker config_setting_t *root = config_root_setting(&cfg);
865*61046927SAndroid Build Coastguard Worker
866*61046927SAndroid Build Coastguard Worker /* per device settings: */
867*61046927SAndroid Build Coastguard Worker char device_name[64];
868*61046927SAndroid Build Coastguard Worker snprintf(device_name, sizeof(device_name), "%s", fd_dev_name(dev.dev_id));
869*61046927SAndroid Build Coastguard Worker setting = config_setting_get_member(root, device_name);
870*61046927SAndroid Build Coastguard Worker if (!setting)
871*61046927SAndroid Build Coastguard Worker setting = config_setting_add(root, device_name, CONFIG_TYPE_GROUP);
872*61046927SAndroid Build Coastguard Worker if (!setting)
873*61046927SAndroid Build Coastguard Worker return;
874*61046927SAndroid Build Coastguard Worker
875*61046927SAndroid Build Coastguard Worker for (unsigned i = 0; i < dev.ngroups; i++) {
876*61046927SAndroid Build Coastguard Worker struct counter_group *group = &dev.groups[i];
877*61046927SAndroid Build Coastguard Worker config_setting_t *sect =
878*61046927SAndroid Build Coastguard Worker config_setting_get_member(setting, group->group->name);
879*61046927SAndroid Build Coastguard Worker
880*61046927SAndroid Build Coastguard Worker if (!sect) {
881*61046927SAndroid Build Coastguard Worker sect =
882*61046927SAndroid Build Coastguard Worker config_setting_add(setting, group->group->name, CONFIG_TYPE_GROUP);
883*61046927SAndroid Build Coastguard Worker }
884*61046927SAndroid Build Coastguard Worker
885*61046927SAndroid Build Coastguard Worker for (unsigned j = 0; j < group->group->num_counters; j++) {
886*61046927SAndroid Build Coastguard Worker /* Don't restore the GPU frequency measurement counter. */
887*61046927SAndroid Build Coastguard Worker if (group->counter[j].is_gpufreq_counter)
888*61046927SAndroid Build Coastguard Worker continue;
889*61046927SAndroid Build Coastguard Worker
890*61046927SAndroid Build Coastguard Worker char name[] = "counter0000";
891*61046927SAndroid Build Coastguard Worker sprintf(name, "counter%d", j);
892*61046927SAndroid Build Coastguard Worker config_setting_t *s = config_setting_lookup(sect, name);
893*61046927SAndroid Build Coastguard Worker if (!s) {
894*61046927SAndroid Build Coastguard Worker config_setting_add(sect, name, CONFIG_TYPE_INT);
895*61046927SAndroid Build Coastguard Worker continue;
896*61046927SAndroid Build Coastguard Worker }
897*61046927SAndroid Build Coastguard Worker select_counter(group, j, config_setting_get_int(s));
898*61046927SAndroid Build Coastguard Worker }
899*61046927SAndroid Build Coastguard Worker }
900*61046927SAndroid Build Coastguard Worker }
901*61046927SAndroid Build Coastguard Worker
902*61046927SAndroid Build Coastguard Worker static void
print_usage(const char * argv0)903*61046927SAndroid Build Coastguard Worker print_usage(const char *argv0)
904*61046927SAndroid Build Coastguard Worker {
905*61046927SAndroid Build Coastguard Worker fprintf(stderr,
906*61046927SAndroid Build Coastguard Worker "Usage: %s [OPTION]...\n"
907*61046927SAndroid Build Coastguard Worker "\n"
908*61046927SAndroid Build Coastguard Worker " -r <N> refresh every N milliseconds\n"
909*61046927SAndroid Build Coastguard Worker " -d dump counters and exit\n"
910*61046927SAndroid Build Coastguard Worker " -h show this message\n",
911*61046927SAndroid Build Coastguard Worker argv0);
912*61046927SAndroid Build Coastguard Worker exit(2);
913*61046927SAndroid Build Coastguard Worker }
914*61046927SAndroid Build Coastguard Worker
915*61046927SAndroid Build Coastguard Worker static void
parse_options(int argc,char ** argv)916*61046927SAndroid Build Coastguard Worker parse_options(int argc, char **argv)
917*61046927SAndroid Build Coastguard Worker {
918*61046927SAndroid Build Coastguard Worker int c;
919*61046927SAndroid Build Coastguard Worker
920*61046927SAndroid Build Coastguard Worker while ((c = getopt(argc, argv, "r:d")) != -1) {
921*61046927SAndroid Build Coastguard Worker switch (c) {
922*61046927SAndroid Build Coastguard Worker case 'r':
923*61046927SAndroid Build Coastguard Worker options.refresh_ms = atoi(optarg);
924*61046927SAndroid Build Coastguard Worker break;
925*61046927SAndroid Build Coastguard Worker case 'd':
926*61046927SAndroid Build Coastguard Worker options.dump = true;
927*61046927SAndroid Build Coastguard Worker break;
928*61046927SAndroid Build Coastguard Worker default:
929*61046927SAndroid Build Coastguard Worker print_usage(argv[0]);
930*61046927SAndroid Build Coastguard Worker break;
931*61046927SAndroid Build Coastguard Worker }
932*61046927SAndroid Build Coastguard Worker }
933*61046927SAndroid Build Coastguard Worker }
934*61046927SAndroid Build Coastguard Worker
935*61046927SAndroid Build Coastguard Worker /*
936*61046927SAndroid Build Coastguard Worker * main
937*61046927SAndroid Build Coastguard Worker */
938*61046927SAndroid Build Coastguard Worker
939*61046927SAndroid Build Coastguard Worker int
main(int argc,char ** argv)940*61046927SAndroid Build Coastguard Worker main(int argc, char **argv)
941*61046927SAndroid Build Coastguard Worker {
942*61046927SAndroid Build Coastguard Worker parse_options(argc, argv);
943*61046927SAndroid Build Coastguard Worker
944*61046927SAndroid Build Coastguard Worker find_device();
945*61046927SAndroid Build Coastguard Worker
946*61046927SAndroid Build Coastguard Worker const struct fd_perfcntr_group *groups;
947*61046927SAndroid Build Coastguard Worker groups = fd_perfcntrs(dev.dev_id, &dev.ngroups);
948*61046927SAndroid Build Coastguard Worker if (!groups) {
949*61046927SAndroid Build Coastguard Worker errx(1, "no perfcntr support");
950*61046927SAndroid Build Coastguard Worker }
951*61046927SAndroid Build Coastguard Worker
952*61046927SAndroid Build Coastguard Worker dev.groups = calloc(dev.ngroups, sizeof(struct counter_group));
953*61046927SAndroid Build Coastguard Worker
954*61046927SAndroid Build Coastguard Worker setlocale(LC_NUMERIC, "en_US.UTF-8");
955*61046927SAndroid Build Coastguard Worker
956*61046927SAndroid Build Coastguard Worker setup_counter_groups(groups);
957*61046927SAndroid Build Coastguard Worker restore_counter_groups();
958*61046927SAndroid Build Coastguard Worker config_restore();
959*61046927SAndroid Build Coastguard Worker flush_ring();
960*61046927SAndroid Build Coastguard Worker
961*61046927SAndroid Build Coastguard Worker if (options.dump)
962*61046927SAndroid Build Coastguard Worker dump_counters();
963*61046927SAndroid Build Coastguard Worker else
964*61046927SAndroid Build Coastguard Worker main_ui();
965*61046927SAndroid Build Coastguard Worker
966*61046927SAndroid Build Coastguard Worker return 0;
967*61046927SAndroid Build Coastguard Worker }
968