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