1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2020 HiSilicon Limited. 4 */ 5 6 #include <fcntl.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include <sys/ioctl.h> 12 #include <sys/mman.h> 13 #include <linux/types.h> 14 #include <linux/map_benchmark.h> 15 16 #define NSEC_PER_MSEC 1000000L 17 18 static char *directions[] = { 19 "BIDIRECTIONAL", 20 "TO_DEVICE", 21 "FROM_DEVICE", 22 }; 23 24 int main(int argc, char **argv) 25 { 26 struct map_benchmark map; 27 int fd, opt; 28 /* default single thread, run 20 seconds on NUMA_NO_NODE */ 29 int threads = 1, seconds = 20, node = -1; 30 /* default dma mask 32bit, bidirectional DMA */ 31 int bits = 32, xdelay = 0, dir = DMA_MAP_BIDIRECTIONAL; 32 /* default granule 1 PAGESIZE */ 33 int granule = 1; 34 35 int cmd = DMA_MAP_BENCHMARK; 36 37 while ((opt = getopt(argc, argv, "t:s:n:b:d:x:g:")) != -1) { 38 switch (opt) { 39 case 't': 40 threads = atoi(optarg); 41 break; 42 case 's': 43 seconds = atoi(optarg); 44 break; 45 case 'n': 46 node = atoi(optarg); 47 break; 48 case 'b': 49 bits = atoi(optarg); 50 break; 51 case 'd': 52 dir = atoi(optarg); 53 break; 54 case 'x': 55 xdelay = atoi(optarg); 56 break; 57 case 'g': 58 granule = atoi(optarg); 59 break; 60 default: 61 return -1; 62 } 63 } 64 65 if (threads <= 0 || threads > DMA_MAP_MAX_THREADS) { 66 fprintf(stderr, "invalid number of threads, must be in 1-%d\n", 67 DMA_MAP_MAX_THREADS); 68 exit(1); 69 } 70 71 if (seconds <= 0 || seconds > DMA_MAP_MAX_SECONDS) { 72 fprintf(stderr, "invalid number of seconds, must be in 1-%d\n", 73 DMA_MAP_MAX_SECONDS); 74 exit(1); 75 } 76 77 if (xdelay < 0 || xdelay > DMA_MAP_MAX_TRANS_DELAY) { 78 fprintf(stderr, "invalid transmit delay, must be in 0-%ld\n", 79 DMA_MAP_MAX_TRANS_DELAY); 80 exit(1); 81 } 82 83 /* suppose the mininum DMA zone is 1MB in the world */ 84 if (bits < 20 || bits > 64) { 85 fprintf(stderr, "invalid dma mask bit, must be in 20-64\n"); 86 exit(1); 87 } 88 89 if (dir != DMA_MAP_BIDIRECTIONAL && dir != DMA_MAP_TO_DEVICE && 90 dir != DMA_MAP_FROM_DEVICE) { 91 fprintf(stderr, "invalid dma direction\n"); 92 exit(1); 93 } 94 95 if (granule < 1 || granule > 1024) { 96 fprintf(stderr, "invalid granule size\n"); 97 exit(1); 98 } 99 100 fd = open("/sys/kernel/debug/dma_map_benchmark", O_RDWR); 101 if (fd == -1) { 102 perror("open"); 103 exit(1); 104 } 105 106 memset(&map, 0, sizeof(map)); 107 map.seconds = seconds; 108 map.threads = threads; 109 map.node = node; 110 map.dma_bits = bits; 111 map.dma_dir = dir; 112 map.dma_trans_ns = xdelay; 113 map.granule = granule; 114 115 if (ioctl(fd, cmd, &map)) { 116 perror("ioctl"); 117 exit(1); 118 } 119 120 printf("dma mapping benchmark: threads:%d seconds:%d node:%d dir:%s granule: %d\n", 121 threads, seconds, node, dir[directions], granule); 122 printf("average map latency(us):%.1f standard deviation:%.1f\n", 123 map.avg_map_100ns/10.0, map.map_stddev/10.0); 124 printf("average unmap latency(us):%.1f standard deviation:%.1f\n", 125 map.avg_unmap_100ns/10.0, map.unmap_stddev/10.0); 126 127 return 0; 128 } 129