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