ipe_benchmark.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. #define _PCILIB_DMA_IPE_C
  2. #define _BSD_SOURCE
  3. #define _DEFAULT_SOURCE
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <unistd.h>
  8. #include <sched.h>
  9. #include <sys/time.h>
  10. #include <arpa/inet.h>
  11. #include "pci.h"
  12. #include "pcilib.h"
  13. #include "error.h"
  14. #include "tools.h"
  15. #include "debug.h"
  16. #include "ipe.h"
  17. #include "ipe_private.h"
  18. typedef struct {
  19. size_t size;
  20. size_t pos;
  21. pcilib_dma_flags_t flags;
  22. } dma_ipe_skim_callback_context_t;
  23. static int dma_ipe_skim_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) {
  24. dma_ipe_skim_callback_context_t *ctx = (dma_ipe_skim_callback_context_t*)arg;
  25. ctx->pos += bufsize;
  26. if (flags & PCILIB_DMA_FLAG_EOP) {
  27. if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) {
  28. if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return PCILIB_STREAMING_WAIT;
  29. else return PCILIB_STREAMING_CONTINUE;
  30. }
  31. return PCILIB_STREAMING_STOP;
  32. }
  33. return PCILIB_STREAMING_REQ_FRAGMENT;
  34. }
  35. int dma_ipe_skim_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes) {
  36. int err;
  37. dma_ipe_skim_callback_context_t opts = {
  38. size, 0, flags
  39. };
  40. err = pcilib_stream_dma(ctx, dma, addr, size, flags, timeout, dma_ipe_skim_callback, &opts);
  41. if (read_bytes) *read_bytes = opts.pos;
  42. return err;
  43. }
  44. double dma_ipe_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) {
  45. int err = 0;
  46. ipe_dma_t *ctx = (ipe_dma_t*)vctx;
  47. int iter;
  48. size_t us = 0;
  49. struct timeval start, cur;
  50. void *buf;
  51. size_t bytes, rbytes;
  52. int (*read_dma)(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes);
  53. if ((direction == PCILIB_DMA_TO_DEVICE)||(direction == PCILIB_DMA_BIDIRECTIONAL)) return -1.;
  54. if ((dma != PCILIB_DMA_ENGINE_INVALID)&&(dma > 1)) return -1.;
  55. if (size%IPEDMA_PAGE_SIZE) size = (1 + size / IPEDMA_PAGE_SIZE) * IPEDMA_PAGE_SIZE;
  56. err = dma_ipe_start(vctx, 0, PCILIB_DMA_FLAGS_DEFAULT);
  57. if (err) return err;
  58. if (getenv("PCILIB_BENCHMARK_HARDWARE"))
  59. read_dma = dma_ipe_skim_dma_custom;
  60. else
  61. read_dma = pcilib_read_dma_custom;
  62. // There is no significant difference and we can remove this when testing phase is over.
  63. if (getenv("PCILIB_BENCHMARK_STREAMING")) {
  64. size_t dma_buffer_space;
  65. pcilib_dma_engine_status_t dma_status;
  66. if (read_dma == pcilib_read_dma_custom)
  67. pcilib_info_once("Benchmarking the DMA streaming (with memcpy)");
  68. else
  69. pcilib_info_once("Benchmarking the DMA streaming (without memcpy)");
  70. // Starting DMA
  71. WR(IPEDMA_REG_CONTROL, 0x1);
  72. gettimeofday(&start, NULL);
  73. pcilib_calc_deadline(&start, IPEDMA_DMA_TIMEOUT * IPEDMA_DMA_PAGES);
  74. #ifdef IPEDMA_BUG_LAST_READ
  75. dma_buffer_space = (IPEDMA_DMA_PAGES - 2) * IPEDMA_PAGE_SIZE;
  76. #else /* IPEDMA_BUG_LAST_READ */
  77. dma_buffer_space = (IPEDMA_DMA_PAGES - 1) * IPEDMA_PAGE_SIZE;
  78. #endif /* IPEDMA_BUG_LAST_READ */
  79. // Allocate memory and prepare data
  80. buf = malloc(size + dma_buffer_space);
  81. if (!buf) return -1;
  82. // Wait all DMA buffers are filled
  83. memset(&dma_status, 0, sizeof(dma_status));
  84. do {
  85. usleep(10 * IPEDMA_NODATA_SLEEP);
  86. err = dma_ipe_get_status(vctx, dma, &dma_status, 0, NULL);
  87. } while ((!err)&&(dma_status.written_bytes < dma_buffer_space)&&(pcilib_calc_time_to_deadline(&start) > 0));
  88. if (err) {
  89. pcilib_error("Error (%i) getting dma status", err);
  90. return -1;
  91. } else if (dma_status.written_bytes < dma_buffer_space) {
  92. pcilib_error("Timeout while waiting DMA engine to feel the buffer space completely, only %zu bytes of %zu written", dma_status.written_bytes, dma_buffer_space);
  93. return -1;
  94. }
  95. gettimeofday(&start, NULL);
  96. for (iter = 0; iter < iterations; iter++) {
  97. for (bytes = 0; bytes < (size + dma_buffer_space); bytes += rbytes) {
  98. err = read_dma(ctx->dmactx.pcilib, 0, addr, size + dma_buffer_space - bytes, PCILIB_DMA_FLAG_MULTIPACKET, PCILIB_DMA_TIMEOUT, buf + bytes, &rbytes);
  99. if (err) {
  100. pcilib_error("Can't read data from DMA, error %i", err);
  101. return -1;
  102. }
  103. }
  104. dma_buffer_space = 0;
  105. }
  106. gettimeofday(&cur, NULL);
  107. us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec));
  108. // Stopping DMA
  109. WR(IPEDMA_REG_CONTROL, 0x0);
  110. pcilib_skip_dma(ctx->dmactx.pcilib, 0);
  111. } else {
  112. if (read_dma == dma_ipe_skim_dma_custom)
  113. pcilib_info_once("Benchmarking the DMA hardware (without memcpy)");
  114. WR(IPEDMA_REG_CONTROL, 0x0);
  115. /*
  116. err = pcilib_skip_dma(ctx->dmactx.pcilib, 0);
  117. if (err) {
  118. pcilib_error("Can't start benchmark, devices continuously writes unexpected data using DMA engine");
  119. return -1;
  120. }
  121. */
  122. // Allocate memory and prepare data
  123. buf = malloc(size);
  124. if (!buf) return -1;
  125. for (iter = 0; iter < iterations; iter++) {
  126. gettimeofday(&start, NULL);
  127. // Starting DMA
  128. WR(IPEDMA_REG_CONTROL, 0x1);
  129. for (bytes = 0; bytes < size; bytes += rbytes) {
  130. err = read_dma(ctx->dmactx.pcilib, 0, addr, size - bytes, PCILIB_DMA_FLAG_MULTIPACKET, PCILIB_DMA_TIMEOUT, buf + bytes, &rbytes);
  131. if (err) {
  132. pcilib_error("Can't read data from DMA (iteration: %zu, offset: %zu), error %i", iter, bytes, err);
  133. return -1;
  134. }
  135. }
  136. // Stopping DMA
  137. WR(IPEDMA_REG_CONTROL, 0x0);
  138. if (err) break;
  139. gettimeofday(&cur, NULL);
  140. us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec));
  141. /*
  142. err = pcilib_skip_dma(ctx->dmactx.pcilib, 0);
  143. if (err) {
  144. pcilib_error("Can't start iteration, devices continuously writes unexpected data using DMA engine");
  145. break;
  146. }
  147. */
  148. }
  149. }
  150. free(buf);
  151. return err?-1:((1. * size * iterations * 1000000) / (1024. * 1024. * us));
  152. }