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 <errno.h>
   6#include <linux/zalloc.h>
   7
   8#include "values.h"
   9#include "debug.h"
  10
  11int 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
  36out_free_counter:
  37        zfree(&values->counterrawid);
  38        zfree(&values->countername);
  39out_free_pid:
  40        zfree(&values->pid);
  41        zfree(&values->tid);
  42        zfree(&values->value);
  43        return -ENOMEM;
  44}
  45
  46void 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
  64static 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;
  79out_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
  87static 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
 116static 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;
 153out_free_name:
 154        free(countername);
 155out_free_rawid:
 156        free(counterrawid);
 157out_enomem:
 158        return -ENOMEM;
 159}
 160
 161static 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
 183int 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
 200static 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
 248static 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
 298void 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