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