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