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