xref: /aosp_15_r20/external/mesa3d/src/freedreno/perfcntrs/fdperf.c (revision 6104692788411f58d303aa86923a9ff6ecaded22)
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