linux/tools/perf/builtin-mem.c
<<
>>
Prefs
   1#include "builtin.h"
   2#include "perf.h"
   3
   4#include "util/parse-options.h"
   5#include "util/trace-event.h"
   6#include "util/tool.h"
   7#include "util/session.h"
   8
   9#define MEM_OPERATION_LOAD      "load"
  10#define MEM_OPERATION_STORE     "store"
  11
  12static const char       *mem_operation          = MEM_OPERATION_LOAD;
  13
  14struct perf_mem {
  15        struct perf_tool        tool;
  16        char const              *input_name;
  17        symbol_filter_t         annotate_init;
  18        bool                    hide_unresolved;
  19        bool                    dump_raw;
  20        const char              *cpu_list;
  21        DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
  22};
  23
  24static const char * const mem_usage[] = {
  25        "perf mem [<options>] {record <command> |report}",
  26        NULL
  27};
  28
  29static int __cmd_record(int argc, const char **argv)
  30{
  31        int rec_argc, i = 0, j;
  32        const char **rec_argv;
  33        char event[64];
  34        int ret;
  35
  36        rec_argc = argc + 4;
  37        rec_argv = calloc(rec_argc + 1, sizeof(char *));
  38        if (!rec_argv)
  39                return -1;
  40
  41        rec_argv[i++] = strdup("record");
  42        if (!strcmp(mem_operation, MEM_OPERATION_LOAD))
  43                rec_argv[i++] = strdup("-W");
  44        rec_argv[i++] = strdup("-d");
  45        rec_argv[i++] = strdup("-e");
  46
  47        if (strcmp(mem_operation, MEM_OPERATION_LOAD))
  48                sprintf(event, "cpu/mem-stores/pp");
  49        else
  50                sprintf(event, "cpu/mem-loads/pp");
  51
  52        rec_argv[i++] = strdup(event);
  53        for (j = 1; j < argc; j++, i++)
  54                rec_argv[i] = argv[j];
  55
  56        ret = cmd_record(i, rec_argv, NULL);
  57        free(rec_argv);
  58        return ret;
  59}
  60
  61static int
  62dump_raw_samples(struct perf_tool *tool,
  63                 union perf_event *event,
  64                 struct perf_sample *sample,
  65                 struct perf_evsel *evsel __maybe_unused,
  66                 struct machine *machine)
  67{
  68        struct perf_mem *mem = container_of(tool, struct perf_mem, tool);
  69        struct addr_location al;
  70        const char *fmt;
  71
  72        if (perf_event__preprocess_sample(event, machine, &al, sample,
  73                                mem->annotate_init) < 0) {
  74                fprintf(stderr, "problem processing %d event, skipping it.\n",
  75                                event->header.type);
  76                return -1;
  77        }
  78
  79        if (al.filtered || (mem->hide_unresolved && al.sym == NULL))
  80                return 0;
  81
  82        if (al.map != NULL)
  83                al.map->dso->hit = 1;
  84
  85        if (symbol_conf.field_sep) {
  86                fmt = "%d%s%d%s0x%"PRIx64"%s0x%"PRIx64"%s%"PRIu64
  87                      "%s0x%"PRIx64"%s%s:%s\n";
  88        } else {
  89                fmt = "%5d%s%5d%s0x%016"PRIx64"%s0x016%"PRIx64
  90                      "%s%5"PRIu64"%s0x%06"PRIx64"%s%s:%s\n";
  91                symbol_conf.field_sep = " ";
  92        }
  93
  94        printf(fmt,
  95                sample->pid,
  96                symbol_conf.field_sep,
  97                sample->tid,
  98                symbol_conf.field_sep,
  99                event->ip.ip,
 100                symbol_conf.field_sep,
 101                sample->addr,
 102                symbol_conf.field_sep,
 103                sample->weight,
 104                symbol_conf.field_sep,
 105                sample->data_src,
 106                symbol_conf.field_sep,
 107                al.map ? (al.map->dso ? al.map->dso->long_name : "???") : "???",
 108                al.sym ? al.sym->name : "???");
 109
 110        return 0;
 111}
 112
 113static int process_sample_event(struct perf_tool *tool,
 114                                union perf_event *event,
 115                                struct perf_sample *sample,
 116                                struct perf_evsel *evsel,
 117                                struct machine *machine)
 118{
 119        return dump_raw_samples(tool, event, sample, evsel, machine);
 120}
 121
 122static int report_raw_events(struct perf_mem *mem)
 123{
 124        int err = -EINVAL;
 125        int ret;
 126        struct perf_session *session = perf_session__new(input_name, O_RDONLY,
 127                                                         0, false, &mem->tool);
 128
 129        if (session == NULL)
 130                return -ENOMEM;
 131
 132        if (mem->cpu_list) {
 133                ret = perf_session__cpu_bitmap(session, mem->cpu_list,
 134                                               mem->cpu_bitmap);
 135                if (ret)
 136                        goto out_delete;
 137        }
 138
 139        if (symbol__init() < 0)
 140                return -1;
 141
 142        printf("# PID, TID, IP, ADDR, LOCAL WEIGHT, DSRC, SYMBOL\n");
 143
 144        err = perf_session__process_events(session, &mem->tool);
 145        if (err)
 146                return err;
 147
 148        return 0;
 149
 150out_delete:
 151        perf_session__delete(session);
 152        return err;
 153}
 154
 155static int report_events(int argc, const char **argv, struct perf_mem *mem)
 156{
 157        const char **rep_argv;
 158        int ret, i = 0, j, rep_argc;
 159
 160        if (mem->dump_raw)
 161                return report_raw_events(mem);
 162
 163        rep_argc = argc + 3;
 164        rep_argv = calloc(rep_argc + 1, sizeof(char *));
 165        if (!rep_argv)
 166                return -1;
 167
 168        rep_argv[i++] = strdup("report");
 169        rep_argv[i++] = strdup("--mem-mode");
 170        rep_argv[i++] = strdup("-n"); /* display number of samples */
 171
 172        /*
 173         * there is no weight (cost) associated with stores, so don't print
 174         * the column
 175         */
 176        if (strcmp(mem_operation, MEM_OPERATION_LOAD))
 177                rep_argv[i++] = strdup("--sort=mem,sym,dso,symbol_daddr,"
 178                                       "dso_daddr,tlb,locked");
 179
 180        for (j = 1; j < argc; j++, i++)
 181                rep_argv[i] = argv[j];
 182
 183        ret = cmd_report(i, rep_argv, NULL);
 184        free(rep_argv);
 185        return ret;
 186}
 187
 188int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
 189{
 190        struct stat st;
 191        struct perf_mem mem = {
 192                .tool = {
 193                        .sample         = process_sample_event,
 194                        .mmap           = perf_event__process_mmap,
 195                        .comm           = perf_event__process_comm,
 196                        .lost           = perf_event__process_lost,
 197                        .fork           = perf_event__process_fork,
 198                        .build_id       = perf_event__process_build_id,
 199                        .ordered_samples = true,
 200                },
 201                .input_name              = "perf.data",
 202        };
 203        const struct option mem_options[] = {
 204        OPT_STRING('t', "type", &mem_operation,
 205                   "type", "memory operations(load/store)"),
 206        OPT_BOOLEAN('D', "dump-raw-samples", &mem.dump_raw,
 207                    "dump raw samples in ASCII"),
 208        OPT_BOOLEAN('U', "hide-unresolved", &mem.hide_unresolved,
 209                    "Only display entries resolved to a symbol"),
 210        OPT_STRING('i', "input", &input_name, "file",
 211                   "input file name"),
 212        OPT_STRING('C', "cpu", &mem.cpu_list, "cpu",
 213                   "list of cpus to profile"),
 214        OPT_STRING('x', "field-separator", &symbol_conf.field_sep,
 215                   "separator",
 216                   "separator for columns, no spaces will be added"
 217                   " between columns '.' is reserved."),
 218        OPT_END()
 219        };
 220
 221        argc = parse_options(argc, argv, mem_options, mem_usage,
 222                             PARSE_OPT_STOP_AT_NON_OPTION);
 223
 224        if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation))
 225                usage_with_options(mem_usage, mem_options);
 226
 227        if (!mem.input_name || !strlen(mem.input_name)) {
 228                if (!fstat(STDIN_FILENO, &st) && S_ISFIFO(st.st_mode))
 229                        mem.input_name = "-";
 230                else
 231                        mem.input_name = "perf.data";
 232        }
 233
 234        if (!strncmp(argv[0], "rec", 3))
 235                return __cmd_record(argc, argv);
 236        else if (!strncmp(argv[0], "rep", 3))
 237                return report_events(argc, argv, &mem);
 238        else
 239                usage_with_options(mem_usage, mem_options);
 240
 241        return 0;
 242}
 243
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.