1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
29c0899f1SArnaldo Carvalho de Melo #include <inttypes.h>
39c0899f1SArnaldo Carvalho de Melo #include <stdio.h>
48d513270SBrice Goglin #include <stdlib.h>
5*8520a98dSArnaldo Carvalho de Melo #include <string.h>
69c0899f1SArnaldo Carvalho de Melo #include <errno.h>
77f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h>
88d513270SBrice Goglin
98d513270SBrice Goglin #include "values.h"
1089973506SArnaldo Carvalho de Melo #include "debug.h"
118d513270SBrice Goglin
perf_read_values_init(struct perf_read_values * values)1289973506SArnaldo Carvalho de Melo int perf_read_values_init(struct perf_read_values *values)
138d513270SBrice Goglin {
148d513270SBrice Goglin values->threads_max = 16;
158d513270SBrice Goglin values->pid = malloc(values->threads_max * sizeof(*values->pid));
168d513270SBrice Goglin values->tid = malloc(values->threads_max * sizeof(*values->tid));
17a1834fc9SJiri Olsa values->value = zalloc(values->threads_max * sizeof(*values->value));
1889973506SArnaldo Carvalho de Melo if (!values->pid || !values->tid || !values->value) {
1989973506SArnaldo Carvalho de Melo pr_debug("failed to allocate read_values threads arrays");
2089973506SArnaldo Carvalho de Melo goto out_free_pid;
2189973506SArnaldo Carvalho de Melo }
228d513270SBrice Goglin values->threads = 0;
238d513270SBrice Goglin
248d513270SBrice Goglin values->counters_max = 16;
258d513270SBrice Goglin values->counterrawid = malloc(values->counters_max
268d513270SBrice Goglin * sizeof(*values->counterrawid));
278d513270SBrice Goglin values->countername = malloc(values->counters_max
288d513270SBrice Goglin * sizeof(*values->countername));
2989973506SArnaldo Carvalho de Melo if (!values->counterrawid || !values->countername) {
3089973506SArnaldo Carvalho de Melo pr_debug("failed to allocate read_values counters arrays");
3189973506SArnaldo Carvalho de Melo goto out_free_counter;
3289973506SArnaldo Carvalho de Melo }
338d513270SBrice Goglin values->counters = 0;
3489973506SArnaldo Carvalho de Melo
3589973506SArnaldo Carvalho de Melo return 0;
3689973506SArnaldo Carvalho de Melo
3789973506SArnaldo Carvalho de Melo out_free_counter:
3889973506SArnaldo Carvalho de Melo zfree(&values->counterrawid);
3989973506SArnaldo Carvalho de Melo zfree(&values->countername);
4089973506SArnaldo Carvalho de Melo out_free_pid:
4189973506SArnaldo Carvalho de Melo zfree(&values->pid);
4289973506SArnaldo Carvalho de Melo zfree(&values->tid);
4389973506SArnaldo Carvalho de Melo zfree(&values->value);
4489973506SArnaldo Carvalho de Melo return -ENOMEM;
458d513270SBrice Goglin }
468d513270SBrice Goglin
perf_read_values_destroy(struct perf_read_values * values)478d513270SBrice Goglin void perf_read_values_destroy(struct perf_read_values *values)
488d513270SBrice Goglin {
498d513270SBrice Goglin int i;
508d513270SBrice Goglin
518d513270SBrice Goglin if (!values->threads_max || !values->counters_max)
528d513270SBrice Goglin return;
538d513270SBrice Goglin
548d513270SBrice Goglin for (i = 0; i < values->threads; i++)
5574cf249dSArnaldo Carvalho de Melo zfree(&values->value[i]);
5674cf249dSArnaldo Carvalho de Melo zfree(&values->value);
5774cf249dSArnaldo Carvalho de Melo zfree(&values->pid);
5874cf249dSArnaldo Carvalho de Melo zfree(&values->tid);
5974cf249dSArnaldo Carvalho de Melo zfree(&values->counterrawid);
608d513270SBrice Goglin for (i = 0; i < values->counters; i++)
6174cf249dSArnaldo Carvalho de Melo zfree(&values->countername[i]);
6274cf249dSArnaldo Carvalho de Melo zfree(&values->countername);
638d513270SBrice Goglin }
648d513270SBrice Goglin
perf_read_values__enlarge_threads(struct perf_read_values * values)6589973506SArnaldo Carvalho de Melo static int perf_read_values__enlarge_threads(struct perf_read_values *values)
668d513270SBrice Goglin {
6789973506SArnaldo Carvalho de Melo int nthreads_max = values->threads_max * 2;
6889973506SArnaldo Carvalho de Melo void *npid = realloc(values->pid, nthreads_max * sizeof(*values->pid)),
6989973506SArnaldo Carvalho de Melo *ntid = realloc(values->tid, nthreads_max * sizeof(*values->tid)),
7089973506SArnaldo Carvalho de Melo *nvalue = realloc(values->value, nthreads_max * sizeof(*values->value));
7189973506SArnaldo Carvalho de Melo
7289973506SArnaldo Carvalho de Melo if (!npid || !ntid || !nvalue)
7389973506SArnaldo Carvalho de Melo goto out_err;
7489973506SArnaldo Carvalho de Melo
7589973506SArnaldo Carvalho de Melo values->threads_max = nthreads_max;
7689973506SArnaldo Carvalho de Melo values->pid = npid;
7789973506SArnaldo Carvalho de Melo values->tid = ntid;
7889973506SArnaldo Carvalho de Melo values->value = nvalue;
7989973506SArnaldo Carvalho de Melo return 0;
8089973506SArnaldo Carvalho de Melo out_err:
8189973506SArnaldo Carvalho de Melo free(npid);
8289973506SArnaldo Carvalho de Melo free(ntid);
8389973506SArnaldo Carvalho de Melo free(nvalue);
8489973506SArnaldo Carvalho de Melo pr_debug("failed to enlarge read_values threads arrays");
8589973506SArnaldo Carvalho de Melo return -ENOMEM;
868d513270SBrice Goglin }
878d513270SBrice Goglin
perf_read_values__findnew_thread(struct perf_read_values * values,u32 pid,u32 tid)888d513270SBrice Goglin static int perf_read_values__findnew_thread(struct perf_read_values *values,
898d513270SBrice Goglin u32 pid, u32 tid)
908d513270SBrice Goglin {
918d513270SBrice Goglin int i;
928d513270SBrice Goglin
938d513270SBrice Goglin for (i = 0; i < values->threads; i++)
948d513270SBrice Goglin if (values->pid[i] == pid && values->tid[i] == tid)
958d513270SBrice Goglin return i;
968d513270SBrice Goglin
9789973506SArnaldo Carvalho de Melo if (values->threads == values->threads_max) {
9889973506SArnaldo Carvalho de Melo i = perf_read_values__enlarge_threads(values);
9989973506SArnaldo Carvalho de Melo if (i < 0)
10089973506SArnaldo Carvalho de Melo return i;
10189973506SArnaldo Carvalho de Melo }
1028d513270SBrice Goglin
10364eed1deSJiri Olsa i = values->threads;
104a1834fc9SJiri Olsa
105a1834fc9SJiri Olsa values->value[i] = zalloc(values->counters_max * sizeof(**values->value));
10689973506SArnaldo Carvalho de Melo if (!values->value[i]) {
10789973506SArnaldo Carvalho de Melo pr_debug("failed to allocate read_values counters array");
10889973506SArnaldo Carvalho de Melo return -ENOMEM;
10989973506SArnaldo Carvalho de Melo }
1108d513270SBrice Goglin values->pid[i] = pid;
1118d513270SBrice Goglin values->tid[i] = tid;
11264eed1deSJiri Olsa values->threads = i + 1;
1138d513270SBrice Goglin
1148d513270SBrice Goglin return i;
1158d513270SBrice Goglin }
1168d513270SBrice Goglin
perf_read_values__enlarge_counters(struct perf_read_values * values)117f05082b5SArnaldo Carvalho de Melo static int perf_read_values__enlarge_counters(struct perf_read_values *values)
1188d513270SBrice Goglin {
119f05082b5SArnaldo Carvalho de Melo char **countername;
120f05082b5SArnaldo Carvalho de Melo int i, counters_max = values->counters_max * 2;
121f05082b5SArnaldo Carvalho de Melo u64 *counterrawid = realloc(values->counterrawid, counters_max * sizeof(*values->counterrawid));
1228d513270SBrice Goglin
123f05082b5SArnaldo Carvalho de Melo if (!counterrawid) {
124f05082b5SArnaldo Carvalho de Melo pr_debug("failed to enlarge read_values rawid array");
125f05082b5SArnaldo Carvalho de Melo goto out_enomem;
126f05082b5SArnaldo Carvalho de Melo }
127f05082b5SArnaldo Carvalho de Melo
128f05082b5SArnaldo Carvalho de Melo countername = realloc(values->countername, counters_max * sizeof(*values->countername));
129f05082b5SArnaldo Carvalho de Melo if (!countername) {
130f05082b5SArnaldo Carvalho de Melo pr_debug("failed to enlarge read_values rawid array");
131f05082b5SArnaldo Carvalho de Melo goto out_free_rawid;
132f05082b5SArnaldo Carvalho de Melo }
1338d513270SBrice Goglin
1348d513270SBrice Goglin for (i = 0; i < values->threads; i++) {
135f05082b5SArnaldo Carvalho de Melo u64 *value = realloc(values->value[i], counters_max * sizeof(**values->value));
136a1834fc9SJiri Olsa int j;
137f05082b5SArnaldo Carvalho de Melo
138f4ef3b7cSJiri Olsa if (!value) {
139f05082b5SArnaldo Carvalho de Melo pr_debug("failed to enlarge read_values ->values array");
140f05082b5SArnaldo Carvalho de Melo goto out_free_name;
1418d513270SBrice Goglin }
142f05082b5SArnaldo Carvalho de Melo
143a1834fc9SJiri Olsa for (j = values->counters_max; j < counters_max; j++)
144a1834fc9SJiri Olsa value[j] = 0;
145a1834fc9SJiri Olsa
146f05082b5SArnaldo Carvalho de Melo values->value[i] = value;
147f05082b5SArnaldo Carvalho de Melo }
148f05082b5SArnaldo Carvalho de Melo
149f05082b5SArnaldo Carvalho de Melo values->counters_max = counters_max;
150f05082b5SArnaldo Carvalho de Melo values->counterrawid = counterrawid;
151f05082b5SArnaldo Carvalho de Melo values->countername = countername;
152f05082b5SArnaldo Carvalho de Melo
153f05082b5SArnaldo Carvalho de Melo return 0;
154f05082b5SArnaldo Carvalho de Melo out_free_name:
155f05082b5SArnaldo Carvalho de Melo free(countername);
156f05082b5SArnaldo Carvalho de Melo out_free_rawid:
157f05082b5SArnaldo Carvalho de Melo free(counterrawid);
158f05082b5SArnaldo Carvalho de Melo out_enomem:
159f05082b5SArnaldo Carvalho de Melo return -ENOMEM;
1608d513270SBrice Goglin }
1618d513270SBrice Goglin
perf_read_values__findnew_counter(struct perf_read_values * values,u64 rawid,const char * name)1628d513270SBrice Goglin static int perf_read_values__findnew_counter(struct perf_read_values *values,
16383a0944fSIngo Molnar u64 rawid, const char *name)
1648d513270SBrice Goglin {
1658d513270SBrice Goglin int i;
1668d513270SBrice Goglin
1678d513270SBrice Goglin for (i = 0; i < values->counters; i++)
1688d513270SBrice Goglin if (values->counterrawid[i] == rawid)
1698d513270SBrice Goglin return i;
1708d513270SBrice Goglin
171f05082b5SArnaldo Carvalho de Melo if (values->counters == values->counters_max) {
172f05082b5SArnaldo Carvalho de Melo i = perf_read_values__enlarge_counters(values);
173f05082b5SArnaldo Carvalho de Melo if (i)
174f05082b5SArnaldo Carvalho de Melo return i;
175f05082b5SArnaldo Carvalho de Melo }
1768d513270SBrice Goglin
1778d513270SBrice Goglin i = values->counters++;
1788d513270SBrice Goglin values->counterrawid[i] = rawid;
1798d513270SBrice Goglin values->countername[i] = strdup(name);
1808d513270SBrice Goglin
1818d513270SBrice Goglin return i;
1828d513270SBrice Goglin }
1838d513270SBrice Goglin
perf_read_values_add_value(struct perf_read_values * values,u32 pid,u32 tid,u64 rawid,const char * name,u64 value)18489973506SArnaldo Carvalho de Melo int perf_read_values_add_value(struct perf_read_values *values,
1858d513270SBrice Goglin u32 pid, u32 tid,
18683a0944fSIngo Molnar u64 rawid, const char *name, u64 value)
1878d513270SBrice Goglin {
1888d513270SBrice Goglin int tindex, cindex;
1898d513270SBrice Goglin
1908d513270SBrice Goglin tindex = perf_read_values__findnew_thread(values, pid, tid);
19189973506SArnaldo Carvalho de Melo if (tindex < 0)
19289973506SArnaldo Carvalho de Melo return tindex;
1938d513270SBrice Goglin cindex = perf_read_values__findnew_counter(values, rawid, name);
19489973506SArnaldo Carvalho de Melo if (cindex < 0)
19589973506SArnaldo Carvalho de Melo return cindex;
1968d513270SBrice Goglin
1979933183eSJiri Olsa values->value[tindex][cindex] += value;
19889973506SArnaldo Carvalho de Melo return 0;
1998d513270SBrice Goglin }
2008d513270SBrice Goglin
perf_read_values__display_pretty(FILE * fp,struct perf_read_values * values)2019f866697SBrice Goglin static void perf_read_values__display_pretty(FILE *fp,
2029f866697SBrice Goglin struct perf_read_values *values)
2038d513270SBrice Goglin {
2048d513270SBrice Goglin int i, j;
2058d513270SBrice Goglin int pidwidth, tidwidth;
2068d513270SBrice Goglin int *counterwidth;
2078d513270SBrice Goglin
2088d513270SBrice Goglin counterwidth = malloc(values->counters * sizeof(*counterwidth));
2099c0899f1SArnaldo Carvalho de Melo if (!counterwidth) {
2109c0899f1SArnaldo Carvalho de Melo fprintf(fp, "INTERNAL ERROR: Failed to allocate counterwidth array\n");
2119c0899f1SArnaldo Carvalho de Melo return;
2129c0899f1SArnaldo Carvalho de Melo }
2138d513270SBrice Goglin tidwidth = 3;
2148d513270SBrice Goglin pidwidth = 3;
2158d513270SBrice Goglin for (j = 0; j < values->counters; j++)
2168d513270SBrice Goglin counterwidth[j] = strlen(values->countername[j]);
2178d513270SBrice Goglin for (i = 0; i < values->threads; i++) {
2188d513270SBrice Goglin int width;
2198d513270SBrice Goglin
2208d513270SBrice Goglin width = snprintf(NULL, 0, "%d", values->pid[i]);
2218d513270SBrice Goglin if (width > pidwidth)
2228d513270SBrice Goglin pidwidth = width;
2238d513270SBrice Goglin width = snprintf(NULL, 0, "%d", values->tid[i]);
2248d513270SBrice Goglin if (width > tidwidth)
2258d513270SBrice Goglin tidwidth = width;
2268d513270SBrice Goglin for (j = 0; j < values->counters; j++) {
2279486aa38SArnaldo Carvalho de Melo width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
2288d513270SBrice Goglin if (width > counterwidth[j])
2298d513270SBrice Goglin counterwidth[j] = width;
2308d513270SBrice Goglin }
2318d513270SBrice Goglin }
2328d513270SBrice Goglin
2338d513270SBrice Goglin fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID");
2348d513270SBrice Goglin for (j = 0; j < values->counters; j++)
2358d513270SBrice Goglin fprintf(fp, " %*s", counterwidth[j], values->countername[j]);
2368d513270SBrice Goglin fprintf(fp, "\n");
2378d513270SBrice Goglin
2388d513270SBrice Goglin for (i = 0; i < values->threads; i++) {
2398d513270SBrice Goglin fprintf(fp, " %*d %*d", pidwidth, values->pid[i],
2408d513270SBrice Goglin tidwidth, values->tid[i]);
2418d513270SBrice Goglin for (j = 0; j < values->counters; j++)
2429486aa38SArnaldo Carvalho de Melo fprintf(fp, " %*" PRIu64,
2438d513270SBrice Goglin counterwidth[j], values->value[i][j]);
2448d513270SBrice Goglin fprintf(fp, "\n");
2458d513270SBrice Goglin }
2468d9e5039SAlexander Beregalov free(counterwidth);
2478d513270SBrice Goglin }
2489f866697SBrice Goglin
perf_read_values__display_raw(FILE * fp,struct perf_read_values * values)2499f866697SBrice Goglin static void perf_read_values__display_raw(FILE *fp,
2509f866697SBrice Goglin struct perf_read_values *values)
2519f866697SBrice Goglin {
2529f866697SBrice Goglin int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth;
2539f866697SBrice Goglin int i, j;
2549f866697SBrice Goglin
2559f866697SBrice Goglin tidwidth = 3; /* TID */
2569f866697SBrice Goglin pidwidth = 3; /* PID */
2579f866697SBrice Goglin namewidth = 4; /* "Name" */
2589f866697SBrice Goglin rawwidth = 3; /* "Raw" */
2599f866697SBrice Goglin countwidth = 5; /* "Count" */
2609f866697SBrice Goglin
2619f866697SBrice Goglin for (i = 0; i < values->threads; i++) {
2629f866697SBrice Goglin width = snprintf(NULL, 0, "%d", values->pid[i]);
2639f866697SBrice Goglin if (width > pidwidth)
2649f866697SBrice Goglin pidwidth = width;
2659f866697SBrice Goglin width = snprintf(NULL, 0, "%d", values->tid[i]);
2669f866697SBrice Goglin if (width > tidwidth)
2679f866697SBrice Goglin tidwidth = width;
2689f866697SBrice Goglin }
2699f866697SBrice Goglin for (j = 0; j < values->counters; j++) {
2709f866697SBrice Goglin width = strlen(values->countername[j]);
2719f866697SBrice Goglin if (width > namewidth)
2729f866697SBrice Goglin namewidth = width;
2739486aa38SArnaldo Carvalho de Melo width = snprintf(NULL, 0, "%" PRIx64, values->counterrawid[j]);
2749f866697SBrice Goglin if (width > rawwidth)
2759f866697SBrice Goglin rawwidth = width;
2769f866697SBrice Goglin }
2779f866697SBrice Goglin for (i = 0; i < values->threads; i++) {
2789f866697SBrice Goglin for (j = 0; j < values->counters; j++) {
2799486aa38SArnaldo Carvalho de Melo width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]);
2809f866697SBrice Goglin if (width > countwidth)
2819f866697SBrice Goglin countwidth = width;
2829f866697SBrice Goglin }
2839f866697SBrice Goglin }
2849f866697SBrice Goglin
2859f866697SBrice Goglin fprintf(fp, "# %*s %*s %*s %*s %*s\n",
2869f866697SBrice Goglin pidwidth, "PID", tidwidth, "TID",
2879f866697SBrice Goglin namewidth, "Name", rawwidth, "Raw",
2889f866697SBrice Goglin countwidth, "Count");
2899f866697SBrice Goglin for (i = 0; i < values->threads; i++)
2909f866697SBrice Goglin for (j = 0; j < values->counters; j++)
2919486aa38SArnaldo Carvalho de Melo fprintf(fp, " %*d %*d %*s %*" PRIx64 " %*" PRIu64,
2929f866697SBrice Goglin pidwidth, values->pid[i],
2939f866697SBrice Goglin tidwidth, values->tid[i],
2949f866697SBrice Goglin namewidth, values->countername[j],
2959f866697SBrice Goglin rawwidth, values->counterrawid[j],
2969f866697SBrice Goglin countwidth, values->value[i][j]);
2979f866697SBrice Goglin }
2989f866697SBrice Goglin
perf_read_values_display(FILE * fp,struct perf_read_values * values,int raw)29983a0944fSIngo Molnar void perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw)
3009f866697SBrice Goglin {
3019f866697SBrice Goglin if (raw)
3029f866697SBrice Goglin perf_read_values__display_raw(fp, values);
3039f866697SBrice Goglin else
3049f866697SBrice Goglin perf_read_values__display_pretty(fp, values);
3059f866697SBrice Goglin }
306