arm-spe.c 5.3 KB

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