root/tools/perf/util/arm-spe.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. arm_spe_dump
  2. arm_spe_dump_event
  3. arm_spe_process_event
  4. arm_spe_process_auxtrace_event
  5. arm_spe_flush
  6. arm_spe_free_queue
  7. arm_spe_free_events
  8. arm_spe_free
  9. arm_spe_print_info
  10. arm_spe_process_auxtrace_info

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

/* [<][>][^][v][top][bottom][index][help] */