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