linux/tools/perf/util/values.c
<<
>>
Prefs
   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
  12int 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
  37out_free_counter:
  38        zfree(&values->counterrawid);
  39        zfree(&values->countername);
  40out_free_pid:
  41        zfree(&values->pid);
  42        zfree(&values->tid);
  43        zfree(&values->value);
  44        return -ENOMEM;
  45}
  46
  47void 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
  65static 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;
  80out_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
  88static 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
 117static 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;
 154out_free_name:
 155        free(countername);
 156out_free_rawid:
 157        free(counterrawid);
 158out_enomem:
 159        return -ENOMEM;
 160}
 161
 162static 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
 184int 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
 201static 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
 249static 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
 299void 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