18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <inttypes.h> 38c2ecf20Sopenharmony_ci#include <stdio.h> 48c2ecf20Sopenharmony_ci#include <stdlib.h> 58c2ecf20Sopenharmony_ci#include <string.h> 68c2ecf20Sopenharmony_ci#include <errno.h> 78c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include "values.h" 108c2ecf20Sopenharmony_ci#include "debug.h" 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ciint perf_read_values_init(struct perf_read_values *values) 138c2ecf20Sopenharmony_ci{ 148c2ecf20Sopenharmony_ci values->threads_max = 16; 158c2ecf20Sopenharmony_ci values->pid = malloc(values->threads_max * sizeof(*values->pid)); 168c2ecf20Sopenharmony_ci values->tid = malloc(values->threads_max * sizeof(*values->tid)); 178c2ecf20Sopenharmony_ci values->value = zalloc(values->threads_max * sizeof(*values->value)); 188c2ecf20Sopenharmony_ci if (!values->pid || !values->tid || !values->value) { 198c2ecf20Sopenharmony_ci pr_debug("failed to allocate read_values threads arrays"); 208c2ecf20Sopenharmony_ci goto out_free_pid; 218c2ecf20Sopenharmony_ci } 228c2ecf20Sopenharmony_ci values->threads = 0; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci values->counters_max = 16; 258c2ecf20Sopenharmony_ci values->counterrawid = malloc(values->counters_max 268c2ecf20Sopenharmony_ci * sizeof(*values->counterrawid)); 278c2ecf20Sopenharmony_ci values->countername = malloc(values->counters_max 288c2ecf20Sopenharmony_ci * sizeof(*values->countername)); 298c2ecf20Sopenharmony_ci if (!values->counterrawid || !values->countername) { 308c2ecf20Sopenharmony_ci pr_debug("failed to allocate read_values counters arrays"); 318c2ecf20Sopenharmony_ci goto out_free_counter; 328c2ecf20Sopenharmony_ci } 338c2ecf20Sopenharmony_ci values->counters = 0; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci return 0; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ciout_free_counter: 388c2ecf20Sopenharmony_ci zfree(&values->counterrawid); 398c2ecf20Sopenharmony_ci zfree(&values->countername); 408c2ecf20Sopenharmony_ciout_free_pid: 418c2ecf20Sopenharmony_ci zfree(&values->pid); 428c2ecf20Sopenharmony_ci zfree(&values->tid); 438c2ecf20Sopenharmony_ci zfree(&values->value); 448c2ecf20Sopenharmony_ci return -ENOMEM; 458c2ecf20Sopenharmony_ci} 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_civoid perf_read_values_destroy(struct perf_read_values *values) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci int i; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci if (!values->threads_max || !values->counters_max) 528c2ecf20Sopenharmony_ci return; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci for (i = 0; i < values->threads; i++) 558c2ecf20Sopenharmony_ci zfree(&values->value[i]); 568c2ecf20Sopenharmony_ci zfree(&values->value); 578c2ecf20Sopenharmony_ci zfree(&values->pid); 588c2ecf20Sopenharmony_ci zfree(&values->tid); 598c2ecf20Sopenharmony_ci zfree(&values->counterrawid); 608c2ecf20Sopenharmony_ci for (i = 0; i < values->counters; i++) 618c2ecf20Sopenharmony_ci zfree(&values->countername[i]); 628c2ecf20Sopenharmony_ci zfree(&values->countername); 638c2ecf20Sopenharmony_ci} 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic int perf_read_values__enlarge_threads(struct perf_read_values *values) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci int nthreads_max = values->threads_max * 2; 688c2ecf20Sopenharmony_ci void *npid = realloc(values->pid, nthreads_max * sizeof(*values->pid)), 698c2ecf20Sopenharmony_ci *ntid = realloc(values->tid, nthreads_max * sizeof(*values->tid)), 708c2ecf20Sopenharmony_ci *nvalue = realloc(values->value, nthreads_max * sizeof(*values->value)); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (!npid || !ntid || !nvalue) 738c2ecf20Sopenharmony_ci goto out_err; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci values->threads_max = nthreads_max; 768c2ecf20Sopenharmony_ci values->pid = npid; 778c2ecf20Sopenharmony_ci values->tid = ntid; 788c2ecf20Sopenharmony_ci values->value = nvalue; 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ciout_err: 818c2ecf20Sopenharmony_ci free(npid); 828c2ecf20Sopenharmony_ci free(ntid); 838c2ecf20Sopenharmony_ci free(nvalue); 848c2ecf20Sopenharmony_ci pr_debug("failed to enlarge read_values threads arrays"); 858c2ecf20Sopenharmony_ci return -ENOMEM; 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic int perf_read_values__findnew_thread(struct perf_read_values *values, 898c2ecf20Sopenharmony_ci u32 pid, u32 tid) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci int i; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci for (i = 0; i < values->threads; i++) 948c2ecf20Sopenharmony_ci if (values->pid[i] == pid && values->tid[i] == tid) 958c2ecf20Sopenharmony_ci return i; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (values->threads == values->threads_max) { 988c2ecf20Sopenharmony_ci i = perf_read_values__enlarge_threads(values); 998c2ecf20Sopenharmony_ci if (i < 0) 1008c2ecf20Sopenharmony_ci return i; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci i = values->threads; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci values->value[i] = zalloc(values->counters_max * sizeof(**values->value)); 1068c2ecf20Sopenharmony_ci if (!values->value[i]) { 1078c2ecf20Sopenharmony_ci pr_debug("failed to allocate read_values counters array"); 1088c2ecf20Sopenharmony_ci return -ENOMEM; 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci values->pid[i] = pid; 1118c2ecf20Sopenharmony_ci values->tid[i] = tid; 1128c2ecf20Sopenharmony_ci values->threads = i + 1; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return i; 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic int perf_read_values__enlarge_counters(struct perf_read_values *values) 1188c2ecf20Sopenharmony_ci{ 1198c2ecf20Sopenharmony_ci char **countername; 1208c2ecf20Sopenharmony_ci int i, counters_max = values->counters_max * 2; 1218c2ecf20Sopenharmony_ci u64 *counterrawid = realloc(values->counterrawid, counters_max * sizeof(*values->counterrawid)); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!counterrawid) { 1248c2ecf20Sopenharmony_ci pr_debug("failed to enlarge read_values rawid array"); 1258c2ecf20Sopenharmony_ci goto out_enomem; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci countername = realloc(values->countername, counters_max * sizeof(*values->countername)); 1298c2ecf20Sopenharmony_ci if (!countername) { 1308c2ecf20Sopenharmony_ci pr_debug("failed to enlarge read_values rawid array"); 1318c2ecf20Sopenharmony_ci goto out_free_rawid; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci for (i = 0; i < values->threads; i++) { 1358c2ecf20Sopenharmony_ci u64 *value = realloc(values->value[i], counters_max * sizeof(**values->value)); 1368c2ecf20Sopenharmony_ci int j; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (!value) { 1398c2ecf20Sopenharmony_ci pr_debug("failed to enlarge read_values ->values array"); 1408c2ecf20Sopenharmony_ci goto out_free_name; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci for (j = values->counters_max; j < counters_max; j++) 1448c2ecf20Sopenharmony_ci value[j] = 0; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci values->value[i] = value; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci values->counters_max = counters_max; 1508c2ecf20Sopenharmony_ci values->counterrawid = counterrawid; 1518c2ecf20Sopenharmony_ci values->countername = countername; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci return 0; 1548c2ecf20Sopenharmony_ciout_free_name: 1558c2ecf20Sopenharmony_ci free(countername); 1568c2ecf20Sopenharmony_ciout_free_rawid: 1578c2ecf20Sopenharmony_ci free(counterrawid); 1588c2ecf20Sopenharmony_ciout_enomem: 1598c2ecf20Sopenharmony_ci return -ENOMEM; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic int perf_read_values__findnew_counter(struct perf_read_values *values, 1638c2ecf20Sopenharmony_ci u64 rawid, const char *name) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int i; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci for (i = 0; i < values->counters; i++) 1688c2ecf20Sopenharmony_ci if (values->counterrawid[i] == rawid) 1698c2ecf20Sopenharmony_ci return i; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci if (values->counters == values->counters_max) { 1728c2ecf20Sopenharmony_ci i = perf_read_values__enlarge_counters(values); 1738c2ecf20Sopenharmony_ci if (i) 1748c2ecf20Sopenharmony_ci return i; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci i = values->counters++; 1788c2ecf20Sopenharmony_ci values->counterrawid[i] = rawid; 1798c2ecf20Sopenharmony_ci values->countername[i] = strdup(name); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci return i; 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciint perf_read_values_add_value(struct perf_read_values *values, 1858c2ecf20Sopenharmony_ci u32 pid, u32 tid, 1868c2ecf20Sopenharmony_ci u64 rawid, const char *name, u64 value) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci int tindex, cindex; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci tindex = perf_read_values__findnew_thread(values, pid, tid); 1918c2ecf20Sopenharmony_ci if (tindex < 0) 1928c2ecf20Sopenharmony_ci return tindex; 1938c2ecf20Sopenharmony_ci cindex = perf_read_values__findnew_counter(values, rawid, name); 1948c2ecf20Sopenharmony_ci if (cindex < 0) 1958c2ecf20Sopenharmony_ci return cindex; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci values->value[tindex][cindex] += value; 1988c2ecf20Sopenharmony_ci return 0; 1998c2ecf20Sopenharmony_ci} 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic void perf_read_values__display_pretty(FILE *fp, 2028c2ecf20Sopenharmony_ci struct perf_read_values *values) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci int i, j; 2058c2ecf20Sopenharmony_ci int pidwidth, tidwidth; 2068c2ecf20Sopenharmony_ci int *counterwidth; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci counterwidth = malloc(values->counters * sizeof(*counterwidth)); 2098c2ecf20Sopenharmony_ci if (!counterwidth) { 2108c2ecf20Sopenharmony_ci fprintf(fp, "INTERNAL ERROR: Failed to allocate counterwidth array\n"); 2118c2ecf20Sopenharmony_ci return; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci tidwidth = 3; 2148c2ecf20Sopenharmony_ci pidwidth = 3; 2158c2ecf20Sopenharmony_ci for (j = 0; j < values->counters; j++) 2168c2ecf20Sopenharmony_ci counterwidth[j] = strlen(values->countername[j]); 2178c2ecf20Sopenharmony_ci for (i = 0; i < values->threads; i++) { 2188c2ecf20Sopenharmony_ci int width; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci width = snprintf(NULL, 0, "%d", values->pid[i]); 2218c2ecf20Sopenharmony_ci if (width > pidwidth) 2228c2ecf20Sopenharmony_ci pidwidth = width; 2238c2ecf20Sopenharmony_ci width = snprintf(NULL, 0, "%d", values->tid[i]); 2248c2ecf20Sopenharmony_ci if (width > tidwidth) 2258c2ecf20Sopenharmony_ci tidwidth = width; 2268c2ecf20Sopenharmony_ci for (j = 0; j < values->counters; j++) { 2278c2ecf20Sopenharmony_ci width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]); 2288c2ecf20Sopenharmony_ci if (width > counterwidth[j]) 2298c2ecf20Sopenharmony_ci counterwidth[j] = width; 2308c2ecf20Sopenharmony_ci } 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci fprintf(fp, "# %*s %*s", pidwidth, "PID", tidwidth, "TID"); 2348c2ecf20Sopenharmony_ci for (j = 0; j < values->counters; j++) 2358c2ecf20Sopenharmony_ci fprintf(fp, " %*s", counterwidth[j], values->countername[j]); 2368c2ecf20Sopenharmony_ci fprintf(fp, "\n"); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci for (i = 0; i < values->threads; i++) { 2398c2ecf20Sopenharmony_ci fprintf(fp, " %*d %*d", pidwidth, values->pid[i], 2408c2ecf20Sopenharmony_ci tidwidth, values->tid[i]); 2418c2ecf20Sopenharmony_ci for (j = 0; j < values->counters; j++) 2428c2ecf20Sopenharmony_ci fprintf(fp, " %*" PRIu64, 2438c2ecf20Sopenharmony_ci counterwidth[j], values->value[i][j]); 2448c2ecf20Sopenharmony_ci fprintf(fp, "\n"); 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci free(counterwidth); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic void perf_read_values__display_raw(FILE *fp, 2508c2ecf20Sopenharmony_ci struct perf_read_values *values) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci int width, pidwidth, tidwidth, namewidth, rawwidth, countwidth; 2538c2ecf20Sopenharmony_ci int i, j; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci tidwidth = 3; /* TID */ 2568c2ecf20Sopenharmony_ci pidwidth = 3; /* PID */ 2578c2ecf20Sopenharmony_ci namewidth = 4; /* "Name" */ 2588c2ecf20Sopenharmony_ci rawwidth = 3; /* "Raw" */ 2598c2ecf20Sopenharmony_ci countwidth = 5; /* "Count" */ 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci for (i = 0; i < values->threads; i++) { 2628c2ecf20Sopenharmony_ci width = snprintf(NULL, 0, "%d", values->pid[i]); 2638c2ecf20Sopenharmony_ci if (width > pidwidth) 2648c2ecf20Sopenharmony_ci pidwidth = width; 2658c2ecf20Sopenharmony_ci width = snprintf(NULL, 0, "%d", values->tid[i]); 2668c2ecf20Sopenharmony_ci if (width > tidwidth) 2678c2ecf20Sopenharmony_ci tidwidth = width; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci for (j = 0; j < values->counters; j++) { 2708c2ecf20Sopenharmony_ci width = strlen(values->countername[j]); 2718c2ecf20Sopenharmony_ci if (width > namewidth) 2728c2ecf20Sopenharmony_ci namewidth = width; 2738c2ecf20Sopenharmony_ci width = snprintf(NULL, 0, "%" PRIx64, values->counterrawid[j]); 2748c2ecf20Sopenharmony_ci if (width > rawwidth) 2758c2ecf20Sopenharmony_ci rawwidth = width; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci for (i = 0; i < values->threads; i++) { 2788c2ecf20Sopenharmony_ci for (j = 0; j < values->counters; j++) { 2798c2ecf20Sopenharmony_ci width = snprintf(NULL, 0, "%" PRIu64, values->value[i][j]); 2808c2ecf20Sopenharmony_ci if (width > countwidth) 2818c2ecf20Sopenharmony_ci countwidth = width; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci fprintf(fp, "# %*s %*s %*s %*s %*s\n", 2868c2ecf20Sopenharmony_ci pidwidth, "PID", tidwidth, "TID", 2878c2ecf20Sopenharmony_ci namewidth, "Name", rawwidth, "Raw", 2888c2ecf20Sopenharmony_ci countwidth, "Count"); 2898c2ecf20Sopenharmony_ci for (i = 0; i < values->threads; i++) 2908c2ecf20Sopenharmony_ci for (j = 0; j < values->counters; j++) 2918c2ecf20Sopenharmony_ci fprintf(fp, " %*d %*d %*s %*" PRIx64 " %*" PRIu64, 2928c2ecf20Sopenharmony_ci pidwidth, values->pid[i], 2938c2ecf20Sopenharmony_ci tidwidth, values->tid[i], 2948c2ecf20Sopenharmony_ci namewidth, values->countername[j], 2958c2ecf20Sopenharmony_ci rawwidth, values->counterrawid[j], 2968c2ecf20Sopenharmony_ci countwidth, values->value[i][j]); 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_civoid perf_read_values_display(FILE *fp, struct perf_read_values *values, int raw) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci if (raw) 3028c2ecf20Sopenharmony_ci perf_read_values__display_raw(fp, values); 3038c2ecf20Sopenharmony_ci else 3048c2ecf20Sopenharmony_ci perf_read_values__display_pretty(fp, values); 3058c2ecf20Sopenharmony_ci} 306