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