1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <inttypes.h>
3*4882a593Smuzhiyun #include <stdio.h>
4*4882a593Smuzhiyun #include <stdlib.h>
5*4882a593Smuzhiyun #include <string.h>
6*4882a593Smuzhiyun #include <errno.h>
7*4882a593Smuzhiyun #include <linux/zalloc.h>
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include "values.h"
10*4882a593Smuzhiyun #include "debug.h"
11*4882a593Smuzhiyun
perf_read_values_init(struct perf_read_values * values)12*4882a593Smuzhiyun int perf_read_values_init(struct perf_read_values *values)
13*4882a593Smuzhiyun {
14*4882a593Smuzhiyun values->threads_max = 16;
15*4882a593Smuzhiyun values->pid = malloc(values->threads_max * sizeof(*values->pid));
16*4882a593Smuzhiyun values->tid = malloc(values->threads_max * sizeof(*values->tid));
17*4882a593Smuzhiyun values->value = zalloc(values->threads_max * sizeof(*values->value));
18*4882a593Smuzhiyun if (!values->pid || !values->tid || !values->value) {
19*4882a593Smuzhiyun pr_debug("failed to allocate read_values threads arrays");
20*4882a593Smuzhiyun goto out_free_pid;
21*4882a593Smuzhiyun }
22*4882a593Smuzhiyun values->threads = 0;
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun values->counters_max = 16;
25*4882a593Smuzhiyun values->counterrawid = malloc(values->counters_max
26*4882a593Smuzhiyun * sizeof(*values->counterrawid));
27*4882a593Smuzhiyun values->countername = malloc(values->counters_max
28*4882a593Smuzhiyun * sizeof(*values->countername));
29*4882a593Smuzhiyun if (!values->counterrawid || !values->countername) {
30*4882a593Smuzhiyun pr_debug("failed to allocate read_values counters arrays");
31*4882a593Smuzhiyun goto out_free_counter;
32*4882a593Smuzhiyun }
33*4882a593Smuzhiyun values->counters = 0;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun return 0;
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun out_free_counter:
38*4882a593Smuzhiyun zfree(&values->counterrawid);
39*4882a593Smuzhiyun zfree(&values->countername);
40*4882a593Smuzhiyun out_free_pid:
41*4882a593Smuzhiyun zfree(&values->pid);
42*4882a593Smuzhiyun zfree(&values->tid);
43*4882a593Smuzhiyun zfree(&values->value);
44*4882a593Smuzhiyun return -ENOMEM;
45*4882a593Smuzhiyun }
46*4882a593Smuzhiyun
perf_read_values_destroy(struct perf_read_values * values)47*4882a593Smuzhiyun void perf_read_values_destroy(struct perf_read_values *values)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun int i;
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun if (!values->threads_max || !values->counters_max)
52*4882a593Smuzhiyun return;
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun for (i = 0; i < values->threads; i++)
55*4882a593Smuzhiyun zfree(&values->value[i]);
56*4882a593Smuzhiyun zfree(&values->value);
57*4882a593Smuzhiyun zfree(&values->pid);
58*4882a593Smuzhiyun zfree(&values->tid);
59*4882a593Smuzhiyun zfree(&values->counterrawid);
60*4882a593Smuzhiyun for (i = 0; i < values->counters; i++)
61*4882a593Smuzhiyun zfree(&values->countername[i]);
62*4882a593Smuzhiyun zfree(&values->countername);
63*4882a593Smuzhiyun }
64*4882a593Smuzhiyun
perf_read_values__enlarge_threads(struct perf_read_values * values)65*4882a593Smuzhiyun static int perf_read_values__enlarge_threads(struct perf_read_values *values)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun int nthreads_max = values->threads_max * 2;
68*4882a593Smuzhiyun void *npid = realloc(values->pid, nthreads_max * sizeof(*values->pid)),
69*4882a593Smuzhiyun *ntid = realloc(values->tid, nthreads_max * sizeof(*values->tid)),
70*4882a593Smuzhiyun *nvalue = realloc(values->value, nthreads_max * sizeof(*values->value));
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun if (!npid || !ntid || !nvalue)
73*4882a593Smuzhiyun goto out_err;
74*4882a593Smuzhiyun
75*4882a593Smuzhiyun values->threads_max = nthreads_max;
76*4882a593Smuzhiyun values->pid = npid;
77*4882a593Smuzhiyun values->tid = ntid;
78*4882a593Smuzhiyun values->value = nvalue;
79*4882a593Smuzhiyun return 0;
80*4882a593Smuzhiyun out_err:
81*4882a593Smuzhiyun free(npid);
82*4882a593Smuzhiyun free(ntid);
83*4882a593Smuzhiyun free(nvalue);
84*4882a593Smuzhiyun pr_debug("failed to enlarge read_values threads arrays");
85*4882a593Smuzhiyun return -ENOMEM;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
perf_read_values__findnew_thread(struct perf_read_values * values,u32 pid,u32 tid)88*4882a593Smuzhiyun static int perf_read_values__findnew_thread(struct perf_read_values *values,
89*4882a593Smuzhiyun u32 pid, u32 tid)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun int i;
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun for (i = 0; i < values->threads; i++)
94*4882a593Smuzhiyun if (values->pid[i] == pid && values->tid[i] == tid)
95*4882a593Smuzhiyun return i;
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun if (values->threads == values->threads_max) {
98*4882a593Smuzhiyun i = perf_read_values__enlarge_threads(values);
99*4882a593Smuzhiyun if (i < 0)
100*4882a593Smuzhiyun return i;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun
103*4882a593Smuzhiyun i = values->threads;
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun values->value[i] = zalloc(values->counters_max * sizeof(**values->value));
106*4882a593Smuzhiyun if (!values->value[i]) {
107*4882a593Smuzhiyun pr_debug("failed to allocate read_values counters array");
108*4882a593Smuzhiyun return -ENOMEM;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun values->pid[i] = pid;
111*4882a593Smuzhiyun values->tid[i] = tid;
112*4882a593Smuzhiyun values->threads = i + 1;
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun return i;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
perf_read_values__enlarge_counters(struct perf_read_values * values)117*4882a593Smuzhiyun static int perf_read_values__enlarge_counters(struct perf_read_values *values)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun char **countername;
120*4882a593Smuzhiyun int i, counters_max = values->counters_max * 2;
121*4882a593Smuzhiyun u64 *counterrawid = realloc(values->counterrawid, counters_max * sizeof(*values->counterrawid));
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (!counterrawid) {
124*4882a593Smuzhiyun pr_debug("failed to enlarge read_values rawid array");
125*4882a593Smuzhiyun goto out_enomem;
126*4882a593Smuzhiyun }
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun countername = realloc(values->countername, counters_max * sizeof(*values->countername));
129*4882a593Smuzhiyun if (!countername) {
130*4882a593Smuzhiyun pr_debug("failed to enlarge read_values rawid array");
131*4882a593Smuzhiyun goto out_free_rawid;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun for (i = 0; i < values->threads; i++) {
135*4882a593Smuzhiyun u64 *value = realloc(values->value[i], counters_max * sizeof(**values->value));
136*4882a593Smuzhiyun int j;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun if (!value) {
139*4882a593Smuzhiyun pr_debug("failed to enlarge read_values ->values array");
140*4882a593Smuzhiyun goto out_free_name;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun for (j = values->counters_max; j < counters_max; j++)
144*4882a593Smuzhiyun value[j] = 0;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun values->value[i] = value;
147*4882a593Smuzhiyun }
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun values->counters_max = counters_max;
150*4882a593Smuzhiyun values->counterrawid = counterrawid;
151*4882a593Smuzhiyun values->countername = countername;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun return 0;
154*4882a593Smuzhiyun out_free_name:
155*4882a593Smuzhiyun free(countername);
156*4882a593Smuzhiyun out_free_rawid:
157*4882a593Smuzhiyun free(counterrawid);
158*4882a593Smuzhiyun out_enomem:
159*4882a593Smuzhiyun return -ENOMEM;
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
perf_read_values__findnew_counter(struct perf_read_values * values,u64 rawid,const char * name)162*4882a593Smuzhiyun static int perf_read_values__findnew_counter(struct perf_read_values *values,
163*4882a593Smuzhiyun u64 rawid, const char *name)
164*4882a593Smuzhiyun {
165*4882a593Smuzhiyun int i;
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun for (i = 0; i < values->counters; i++)
168*4882a593Smuzhiyun if (values->counterrawid[i] == rawid)
169*4882a593Smuzhiyun return i;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun if (values->counters == values->counters_max) {
172*4882a593Smuzhiyun i = perf_read_values__enlarge_counters(values);
173*4882a593Smuzhiyun if (i)
174*4882a593Smuzhiyun return i;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun
177*4882a593Smuzhiyun i = values->counters++;
178*4882a593Smuzhiyun values->counterrawid[i] = rawid;
179*4882a593Smuzhiyun values->countername[i] = strdup(name);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun return i;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
perf_read_values_add_value(struct perf_read_values * values,u32 pid,u32 tid,u64 rawid,const char * name,u64 value)184*4882a593Smuzhiyun int perf_read_values_add_value(struct perf_read_values *values,
185*4882a593Smuzhiyun u32 pid, u32 tid,
186*4882a593Smuzhiyun u64 rawid, const char *name, u64 value)
187*4882a593Smuzhiyun {
188*4882a593Smuzhiyun int tindex, cindex;
189*4882a593Smuzhiyun
190*4882a593Smuzhiyun tindex = perf_read_values__findnew_thread(values, pid, tid);
191*4882a593Smuzhiyun if (tindex < 0)
192*4882a593Smuzhiyun return tindex;
193*4882a593Smuzhiyun cindex = perf_read_values__findnew_counter(values, rawid, name);
194*4882a593Smuzhiyun if (cindex < 0)
195*4882a593Smuzhiyun return cindex;
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun values->value[tindex][cindex] += value;
198*4882a593Smuzhiyun return 0;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun
perf_read_values__display_pretty(FILE * fp,struct perf_read_values * values)201*4882a593Smuzhiyun static void perf_read_values__display_pretty(FILE *fp,
202*4882a593Smuzhiyun struct perf_read_values *values)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun int i, j;
205*4882a593Smuzhiyun int pidwidth, tidwidth;
206*4882a593Smuzhiyun int *counterwidth;
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun counterwidth = malloc(values->counters * sizeof(*counterwidth));
209*4882a593Smuzhiyun if (!counterwidth) {
210*4882a593Smuzhiyun fprintf(fp, "INTERNAL ERROR: Failed to allocate counterwidth array\n");
211*4882a593Smuzhiyun return;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun tidwidth = 3;
214*4882a593Smuzhiyun pidwidth = 3;
215*4882a593Smuzhiyun for (j = 0; j < values->counters; j++)
216*4882a593Smuzhiyun counterwidth[j] = strlen(values->countername[j]);
217*4882a593Smuzhiyun for (i = 0; i < values->threads; i++) {
218*4882a593Smuzhiyun int width;
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun width = snprintf(NULL, 0, "%d", values->pid[i]);
221*4882a593Smuzhiyun if (width > pidwidth)
222*4882a593Smuzhiyun pidwidth = width;
223*4882a593Smuzhiyun width = snprintf(NULL, 0, "%d", values->tid[i]);
224*4882a593Smuzhiyun if (width > tidwidth)
225*4882a593Smuzhiyun tidwidth = width;
226*4882a593Smuzhiyun for (j = 0; j < values->counters; j++) {
227*4882a593Smuzhiyun width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
228*4882a593Smuzhiyun if (width > counterwidth[j])
229*4882a593Smuzhiyun counterwidth[j] = width;
230*4882a593Smuzhiyun }
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID");
234*4882a593Smuzhiyun for (j = 0; j < values->counters; j++)
235*4882a593Smuzhiyun fprintf(fp, " %*s", counterwidth[j], values->countername[j]);
236*4882a593Smuzhiyun fprintf(fp, "\n");
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun for (i = 0; i < values->threads; i++) {
239*4882a593Smuzhiyun fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
240*4882a593Smuzhiyun tidwidth, values->tid[i]);
241*4882a593Smuzhiyun for (j = 0; j < values->counters; j++)
242*4882a593Smuzhiyun fprintf(fp, " %*" PRIu64,
243*4882a593Smuzhiyun counterwidth[j], values->value[i][j]);
244*4882a593Smuzhiyun fprintf(fp, "\n");
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun free(counterwidth);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun
perf_read_values__display_raw(FILE * fp,struct perf_read_values * values)249*4882a593Smuzhiyun static void perf_read_values__display_raw(FILE *fp,
250*4882a593Smuzhiyun struct perf_read_values *values)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth;
253*4882a593Smuzhiyun int i, j;
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun tidwidth = 3; /* TID */
256*4882a593Smuzhiyun pidwidth = 3; /* PID */
257*4882a593Smuzhiyun namewidth = 4; /* "Name" */
258*4882a593Smuzhiyun rawwidth = 3; /* "Raw" */
259*4882a593Smuzhiyun countwidth = 5; /* "Count" */
260*4882a593Smuzhiyun
261*4882a593Smuzhiyun for (i = 0; i < values->threads; i++) {
262*4882a593Smuzhiyun width = snprintf(NULL, 0, "%d", values->pid[i]);
263*4882a593Smuzhiyun if (width > pidwidth)
264*4882a593Smuzhiyun pidwidth = width;
265*4882a593Smuzhiyun width = snprintf(NULL, 0, "%d", values->tid[i]);
266*4882a593Smuzhiyun if (width > tidwidth)
267*4882a593Smuzhiyun tidwidth = width;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun for (j = 0; j < values->counters; j++) {
270*4882a593Smuzhiyun width = strlen(values->countername[j]);
271*4882a593Smuzhiyun if (width > namewidth)
272*4882a593Smuzhiyun namewidth = width;
273*4882a593Smuzhiyun width = snprintf(NULL, 0, "%" PRIx64, values->counterrawid[j]);
274*4882a593Smuzhiyun if (width > rawwidth)
275*4882a593Smuzhiyun rawwidth = width;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun for (i = 0; i < values->threads; i++) {
278*4882a593Smuzhiyun for (j = 0; j < values->counters; j++) {
279*4882a593Smuzhiyun width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
280*4882a593Smuzhiyun if (width > countwidth)
281*4882a593Smuzhiyun countwidth = width;
282*4882a593Smuzhiyun }
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun fprintf(fp, "# %*s %*s %*s %*s %*s\n",
286*4882a593Smuzhiyun pidwidth, "PID", tidwidth, "TID",
287*4882a593Smuzhiyun namewidth, "Name", rawwidth, "Raw",
288*4882a593Smuzhiyun countwidth, "Count");
289*4882a593Smuzhiyun for (i = 0; i < values->threads; i++)
290*4882a593Smuzhiyun for (j = 0; j < values->counters; j++)
291*4882a593Smuzhiyun fprintf(fp, " %*d %*d %*s %*" PRIx64 " %*" PRIu64,
292*4882a593Smuzhiyun pidwidth, values->pid[i],
293*4882a593Smuzhiyun tidwidth, values->tid[i],
294*4882a593Smuzhiyun namewidth, values->countername[j],
295*4882a593Smuzhiyun rawwidth, values->counterrawid[j],
296*4882a593Smuzhiyun countwidth, values->value[i][j]);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun
perf_read_values_display(FILE * fp,struct perf_read_values * values,int raw)299*4882a593Smuzhiyun void perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw)
300*4882a593Smuzhiyun {
301*4882a593Smuzhiyun if (raw)
302*4882a593Smuzhiyun perf_read_values__display_raw(fp, values);
303*4882a593Smuzhiyun else
304*4882a593Smuzhiyun perf_read_values__display_pretty(fp, values);
305*4882a593Smuzhiyun }
306