linux/tools/perf/util/arm-spe.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Arm Statistical Profiling Extensions (SPE) support
   4 * Copyright (c) 2017-2018, Arm Ltd.
   5 */
   6
   7#include <endian.h>
   8#include <errno.h>
   9#include <byteswap.h>
  10#include <inttypes.h>
  11#include <linux/kernel.h>
  12#include <linux/types.h>
  13#include <linux/bitops.h>
  14#include <linux/log2.h>
  15#include <linux/zalloc.h>
  16
  17#include "cpumap.h"
  18#include "color.h"
  19#include "evsel.h"
  20#include "evlist.h"
  21#include "machine.h"
  22#include "session.h"
  23#include "thread.h"
  24#include "debug.h"
  25#include "auxtrace.h"
  26#include "arm-spe.h"
  27#include "arm-spe-pkt-decoder.h"
  28
  29struct arm_spe {
  30        struct auxtrace                 auxtrace;
  31        struct auxtrace_queues          queues;
  32        struct auxtrace_heap            heap;
  33        u32                             auxtrace_type;
  34        struct perf_session             *session;
  35        struct machine                  *machine;
  36        u32                             pmu_type;
  37};
  38
  39struct arm_spe_queue {
  40        struct arm_spe          *spe;
  41        unsigned int            queue_nr;
  42        struct auxtrace_buffer  *buffer;
  43        bool                    on_heap;
  44        bool                    done;
  45        pid_t                   pid;
  46        pid_t                   tid;
  47        int                     cpu;
  48};
  49
  50static void arm_spe_dump(struct arm_spe *spe __maybe_unused,
  51                         unsigned char *buf, size_t len)
  52{
  53        struct arm_spe_pkt packet;
  54        size_t pos = 0;
  55        int ret, pkt_len, i;
  56        char desc[ARM_SPE_PKT_DESC_MAX];
  57        const char *color = PERF_COLOR_BLUE;
  58
  59        color_fprintf(stdout, color,
  60                      ". ... ARM SPE data: size %zu bytes\n",
  61                      len);
  62
  63        while (len) {
  64                ret = arm_spe_get_packet(buf, len, &packet);
  65                if (ret > 0)
  66                        pkt_len = ret;
  67                else
  68                        pkt_len = 1;
  69                printf(".");
  70                color_fprintf(stdout, color, "  %08x: ", pos);
  71                for (i = 0; i < pkt_len; i++)
  72                        color_fprintf(stdout, color, " %02x", buf[i]);
  73                for (; i < 16; i++)
  74                        color_fprintf(stdout, color, "   ");
  75                if (ret > 0) {
  76                        ret = arm_spe_pkt_desc(&packet, desc,
  77                                               ARM_SPE_PKT_DESC_MAX);
  78                        if (ret > 0)
  79                                color_fprintf(stdout, color, " %s\n", desc);
  80                } else {
  81                        color_fprintf(stdout, color, " Bad packet!\n");
  82                }
  83                pos += pkt_len;
  84                buf += pkt_len;
  85                len -= pkt_len;
  86        }
  87}
  88
  89static void arm_spe_dump_event(struct arm_spe *spe, unsigned char *buf,
  90                               size_t len)
  91{
  92        printf(".\n");
  93        arm_spe_dump(spe, buf, len);
  94}
  95
  96static int arm_spe_process_event(struct perf_session *session __maybe_unused,
  97                                 union perf_event *event __maybe_unused,
  98                                 struct perf_sample *sample __maybe_unused,
  99                                 struct perf_tool *tool __maybe_unused)
 100{
 101        return 0;
 102}
 103
 104static int arm_spe_process_auxtrace_event(struct perf_session *session,
 105                                          union perf_event *event,
 106                                          struct perf_tool *tool __maybe_unused)
 107{
 108        struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
 109                                             auxtrace);
 110        struct auxtrace_buffer *buffer;
 111        off_t data_offset;
 112        int fd = perf_data__fd(session->data);
 113        int err;
 114
 115        if (perf_data__is_pipe(session->data)) {
 116                data_offset = 0;
 117        } else {
 118                data_offset = lseek(fd, 0, SEEK_CUR);
 119                if (data_offset == -1)
 120                        return -errno;
 121        }
 122
 123        err = auxtrace_queues__add_event(&spe->queues, session, event,
 124                                         data_offset, &buffer);
 125        if (err)
 126                return err;
 127
 128        /* Dump here now we have copied a piped trace out of the pipe */
 129        if (dump_trace) {
 130                if (auxtrace_buffer__get_data(buffer, fd)) {
 131                        arm_spe_dump_event(spe, buffer->data,
 132                                             buffer->size);
 133                        auxtrace_buffer__put_data(buffer);
 134                }
 135        }
 136
 137        return 0;
 138}
 139
 140static int arm_spe_flush(struct perf_session *session __maybe_unused,
 141                         struct perf_tool *tool __maybe_unused)
 142{
 143        return 0;
 144}
 145
 146static void arm_spe_free_queue(void *priv)
 147{
 148        struct arm_spe_queue *speq = priv;
 149
 150        if (!speq)
 151                return;
 152        free(speq);
 153}
 154
 155static void arm_spe_free_events(struct perf_session *session)
 156{
 157        struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
 158                                             auxtrace);
 159        struct auxtrace_queues *queues = &spe->queues;
 160        unsigned int i;
 161
 162        for (i = 0; i < queues->nr_queues; i++) {
 163                arm_spe_free_queue(queues->queue_array[i].priv);
 164                queues->queue_array[i].priv = NULL;
 165        }
 166        auxtrace_queues__free(queues);
 167}
 168
 169static void arm_spe_free(struct perf_session *session)
 170{
 171        struct arm_spe *spe = container_of(session->auxtrace, struct arm_spe,
 172                                             auxtrace);
 173
 174        auxtrace_heap__free(&spe->heap);
 175        arm_spe_free_events(session);
 176        session->auxtrace = NULL;
 177        free(spe);
 178}
 179
 180static const char * const arm_spe_info_fmts[] = {
 181        [ARM_SPE_PMU_TYPE]              = "  PMU Type           %"PRId64"\n",
 182};
 183
 184static void arm_spe_print_info(u64 *arr)
 185{
 186        if (!dump_trace)
 187                return;
 188
 189        fprintf(stdout, arm_spe_info_fmts[ARM_SPE_PMU_TYPE], arr[ARM_SPE_PMU_TYPE]);
 190}
 191
 192int arm_spe_process_auxtrace_info(union perf_event *event,
 193                                  struct perf_session *session)
 194{
 195        struct auxtrace_info_event *auxtrace_info = &event->auxtrace_info;
 196        size_t min_sz = sizeof(u64) * ARM_SPE_PMU_TYPE;
 197        struct arm_spe *spe;
 198        int err;
 199
 200        if (auxtrace_info->header.size < sizeof(struct auxtrace_info_event) +
 201                                        min_sz)
 202                return -EINVAL;
 203
 204        spe = zalloc(sizeof(struct arm_spe));
 205        if (!spe)
 206                return -ENOMEM;
 207
 208        err = auxtrace_queues__init(&spe->queues);
 209        if (err)
 210                goto err_free;
 211
 212        spe->session = session;
 213        spe->machine = &session->machines.host; /* No kvm support */
 214        spe->auxtrace_type = auxtrace_info->type;
 215        spe->pmu_type = auxtrace_info->priv[ARM_SPE_PMU_TYPE];
 216
 217        spe->auxtrace.process_event = arm_spe_process_event;
 218        spe->auxtrace.process_auxtrace_event = arm_spe_process_auxtrace_event;
 219        spe->auxtrace.flush_events = arm_spe_flush;
 220        spe->auxtrace.free_events = arm_spe_free_events;
 221        spe->auxtrace.free = arm_spe_free;
 222        session->auxtrace = &spe->auxtrace;
 223
 224        arm_spe_print_info(&auxtrace_info->priv[0]);
 225
 226        return 0;
 227
 228err_free:
 229        free(spe);
 230        return err;
 231}
 232