/**
* @file axidma_benchmark.c
* @date Thursday, November 26, 2015 at 10:29:26 PM EST
* @author Brandon Perez (bmperez)
* @author Jared Choi (jaewonch)
*
* This is a simple program that benchmarks the AXI DMA transfer rate for
* whatever logic is sitting on the PL fabric. It sends some data out over the
* PL fabric via AXI DMA to whatever is sitting there, and waits to receive
* some data back from the PL fabric.
*
* The program first runs a single transfer to verify that the DMA works
* properly, then profiles the DMA engine. The program sends out a specific
* transfer size, and gets back a potentially different receive size. It runs
* the a given number of times to calculate the performance statistics. All of
* these options are configurable from the command line.
*
* NOTE: This program assumes that there are only two DMA channels being used by
* the PL fabric, one that consumes data and sends it to the PL fabric logic,
* and another that sends the output of the PL fabric back to memory. If you
* have additional DMA channels, you will need to modify the program. This
* program will work with the AXI DMA/VDMA loopback examples (where the S2MM and
* MM2S ports are simply connected to one another).
*
* @bug No known bugs.
**/
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <string.h> // Strlen function
#include <fcntl.h> // Flags for open()
#include <sys/stat.h> // Open() system call
#include <sys/types.h> // Types for open()
#include <sys/mman.h> // Mmap system call
#include <sys/ioctl.h> // IOCTL system call
#include <unistd.h> // Close() system call
#include <sys/time.h> // Timing functions and definitions
#include <getopt.h> // Option parsing
#include <errno.h> // Error codes
#include "libaxidma.h" // Interface to the AXI DMA
#include "util.h" // Miscellaneous utilities
#include "conversion.h" // Miscellaneous conversion utilities
/*----------------------------------------------------------------------------
* Internal Definitons
*----------------------------------------------------------------------------*/
// The size of data to send per transfer (1080p image, 7.24 MiB)
#define IMAGE_SIZE (1920 * 1080)
#define DEFAULT_TRANSFER_SIZE ((int)(IMAGE_SIZE * sizeof(int)))
// The default number of transfers to benchmark
#define DEFAULT_NUM_TRANSFERS 1000
// The pattern that we fill into the buffers
#define TEST_PATTERN(i) ((int)(0x1234ACDE ^ (i)))
// The DMA context passed to the helper thread, who handles remainder channels
/*----------------------------------------------------------------------------
* Command-line Interface
*----------------------------------------------------------------------------*/
// Prints the usage for this program
static void print_usage(bool help)
{
FILE* stream = (help) ? stdout : stderr;
double default_size;
fprintf(stream, "Usage: axidma_benchmark [-v] [-t <(V)DMA tx channel>] "
"[-r <(V)DMA rx channel>] [-i <Tx transfer size (MiB)>] "
"[-b <Tx transfer size (bytes)>] [-f <Tx frame size (HxWxD)>] "
"[-o <Rx transfer size (MiB)>] [-s <Rx transfer size (bytes)>] "
"[-g <Rx frame size (HxWxD)>] [-n <number transfers>]\n");
if (!help) {
return;
}
default_size = BYTE_TO_MIB(DEFAULT_TRANSFER_SIZE);
fprintf(stream, "\t-v:\t\t\t\tUse the AXI VDMA channels instead of AXI DMA "
"ones for the transfer.\n");
fprintf(stream, "\t-t <DMA tx channel>:\t\t\tThe device id of the DMA "
"channel to use for transmitting the data to the PL fabric.\n");
fprintf(stream, "\t-r <DMA rx channel>:\t\t\tThe device id of the DMA "
"channel to use for receiving the the data from the PL fabric.\n");
fprintf(stream, "\t-i <transmit transfer size (MiB)>:\tThe size of the "
"data transmit over the DMA on each transfer. Default is %0.2f "
"MiB.\n", default_size);
fprintf(stream, "\t-b <Tx transfer size (bytes)>:\tThe size of the "
"data transmit over the DMA on each transfer. Default is %d "
"bytes.\n", DEFAULT_TRANSFER_SIZE);
fprintf(stream, "\t-f <Tx frame size (height x width x depth)>:\tThe size "
"of the frame to transmit over VDMA on each transfer, where the "
"depth is in bytes.");
fprintf(stream, "\t-o <Rx transfer size (MiB)>:\tThe size of the data "
"to receive from the DMA on each transfer. Default is %0.2f MiB.\n",
default_size);
fprintf(stream, "\t-s <Rx transfer size (bytes)>:\tThe size of the "
"data to receive from the DMA on each transfer. Default is %d "
"bytes.\n", DEFAULT_TRANSFER_SIZE);
fprintf(stream, "\t-g <Rx frame size (height x width x depth)>:\tThe size "
"of the frame to receive over VDMA on each transfer, where the "
"depth is in bytes.");
fprintf(stream, "\t-n <number transfers>:\t\t\tThe number of DMA transfers "
"to perform to do the benchmark. Default is %d transfers.\n",
DEFAULT_NUM_TRANSFERS);
return;
}
/* Parses the command line arguments overriding the default transfer sizes,
* and number of transfer to use for the benchmark if specified. */
static int parse_args(int argc, char **argv, int *tx_channel, int *rx_channel,
size_t *tx_size, struct axidma_video_frame *tx_frame, size_t *rx_size,
struct axidma_video_frame *rx_frame, int *num_transfers, bool *use_vdma)
{
double double_arg;
int int_arg;
char option;
bool tx_frame_specified, rx_frame_specified;
// Set the default data size and number of transfers
*use_vdma = false;
*tx_channel = -1;
*rx_channel = -1;
*tx_size = DEFAULT_TRANSFER_SIZE;
tx_frame->height = -1;
tx_frame->width = -1;
tx_frame->depth = -1;
*rx_size = DEFAULT_TRANSFER_SIZE;
rx_frame->height = -1;
rx_frame->width = -1;
rx_frame->depth = -1;
*num_transfers = DEFAULT_NUM_TRANSFERS;
while ((option = getopt(argc, argv, "vt:r:i:b:f:o:s:g:n:h")) != (char)-1)
{
switch (option)
{
case 'v':
*use_vdma = true;
break;
// Parse the transmit channel argument
case 't':
if (parse_int(option, optarg, &int_arg) < 0) {
print_usage(false);
return -EINVAL;
}
*tx_channel = int_arg;
break;
// Parse the transmit transfer size argument
case 'r':
if (parse_int(option, optarg, &int_arg) < 0) {
print_usage(false);
return -EINVAL;
}
*rx_channel = int_arg;
break;
// Parse the transmit transfer size argument
case 'i':
if (parse_double(option, optarg, &double_arg) < 0) {
print_usage(false);
return -EINVAL;
}
*tx_size = MIB_TO_BYTE(double_arg);
break;
// Parse the transmit transfer size argument
case 'b':
if (parse_int(option, optarg, &int_arg) < 0) {
print_usage(false);
return -EINVAL;
}
*tx_size = int_arg;
break;
// Parse the transmit frame size option
case 'f':
if (strlen(optarg) == 0) {
fprintf(stderr, "The -f option requires an argument.\n");
print_usage(false);
return -EINVAL;
} else if (parse_resolution(option, optarg, &tx_frame->height,
&tx_frame->width, &tx_frame->depth) < 0) {
评论0