GNU Linux-libre 5.19-rc6-gnu
[releases.git] / tools / perf / dlfilters / dlfilter-show-cycles.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * dlfilter-show-cycles.c: Print the number of cycles at the start of each line
4  * Copyright (c) 2021, Intel Corporation.
5  */
6 #include <perf/perf_dlfilter.h>
7 #include <string.h>
8 #include <stdio.h>
9
10 #define MAX_CPU 4096
11
12 enum {
13         INSTR_CYC,
14         BRNCH_CYC,
15         OTHER_CYC,
16         MAX_ENTRY
17 };
18
19 static __u64 cycles[MAX_CPU][MAX_ENTRY];
20 static __u64 cycles_rpt[MAX_CPU][MAX_ENTRY];
21
22 #define BITS            16
23 #define TABLESZ         (1 << BITS)
24 #define TABLEMAX        (TABLESZ / 2)
25 #define MASK            (TABLESZ - 1)
26
27 static struct entry {
28         __u32 used;
29         __s32 tid;
30         __u64 cycles[MAX_ENTRY];
31         __u64 cycles_rpt[MAX_ENTRY];
32 } table[TABLESZ];
33
34 static int tid_cnt;
35
36 static int event_entry(const char *event)
37 {
38         if (!event)
39                 return OTHER_CYC;
40         if (!strncmp(event, "instructions", 12))
41                 return INSTR_CYC;
42         if (!strncmp(event, "branches", 8))
43                 return BRNCH_CYC;
44         return OTHER_CYC;
45 }
46
47 static struct entry *find_entry(__s32 tid)
48 {
49         __u32 pos = tid & MASK;
50         struct entry *e;
51
52         e = &table[pos];
53         while (e->used) {
54                 if (e->tid == tid)
55                         return e;
56                 if (++pos == TABLESZ)
57                         pos = 0;
58                 e = &table[pos];
59         }
60
61         if (tid_cnt >= TABLEMAX) {
62                 fprintf(stderr, "Too many threads\n");
63                 return NULL;
64         }
65
66         tid_cnt += 1;
67         e->used = 1;
68         e->tid = tid;
69         return e;
70 }
71
72 static void add_entry(__s32 tid, int pos, __u64 cnt)
73 {
74         struct entry *e = find_entry(tid);
75
76         if (e)
77                 e->cycles[pos] += cnt;
78 }
79
80 int filter_event_early(void *data, const struct perf_dlfilter_sample *sample, void *ctx)
81 {
82         __s32 cpu = sample->cpu;
83         __s32 tid = sample->tid;
84         int pos;
85
86         if (!sample->cyc_cnt)
87                 return 0;
88
89         pos = event_entry(sample->event);
90
91         if (cpu >= 0 && cpu < MAX_CPU)
92                 cycles[cpu][pos] += sample->cyc_cnt;
93         else if (tid != -1)
94                 add_entry(tid, pos, sample->cyc_cnt);
95         return 0;
96 }
97
98 static void print_vals(__u64 cycles, __u64 delta)
99 {
100         if (delta)
101                 printf("%10llu %10llu ", cycles, delta);
102         else
103                 printf("%10llu %10s ", cycles, "");
104 }
105
106 int filter_event(void *data, const struct perf_dlfilter_sample *sample, void *ctx)
107 {
108         __s32 cpu = sample->cpu;
109         __s32 tid = sample->tid;
110         int pos;
111
112         pos = event_entry(sample->event);
113
114         if (cpu >= 0 && cpu < MAX_CPU) {
115                 print_vals(cycles[cpu][pos], cycles[cpu][pos] - cycles_rpt[cpu][pos]);
116                 cycles_rpt[cpu][pos] = cycles[cpu][pos];
117                 return 0;
118         }
119
120         if (tid != -1) {
121                 struct entry *e = find_entry(tid);
122
123                 if (e) {
124                         print_vals(e->cycles[pos], e->cycles[pos] - e->cycles_rpt[pos]);
125                         e->cycles_rpt[pos] = e->cycles[pos];
126                         return 0;
127                 }
128         }
129
130         printf("%22s", "");
131         return 0;
132 }
133
134 const char *filter_description(const char **long_description)
135 {
136         static char *long_desc = "Cycle counts are accumulated per CPU (or "
137                 "per thread if CPU is not recorded) from IPC information, and "
138                 "printed together with the change since the last print, at the "
139                 "start of each line. Separate counts are kept for branches, "
140                 "instructions or other events.";
141
142         *long_description = long_desc;
143         return "Print the number of cycles at the start of each line";
144 }