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 <unistd.h> 10 #include <sys/ioctl.h> 11 #include <sys/mman.h> 12 #include <linux/types.h> 13 14 #define DMA_MAP_BENCHMARK _IOWR('d', 1, struct map_benchmark) 15 #define DMA_MAP_MAX_THREADS 1024 16 #define DMA_MAP_MAX_SECONDS 300 17 18 #define DMA_MAP_BIDIRECTIONAL 0 19 #define DMA_MAP_TO_DEVICE 1 20 #define DMA_MAP_FROM_DEVICE 2 21 22 static char *directions[] = { 23 "BIDIRECTIONAL", 24 "TO_DEVICE", 25 "FROM_DEVICE", 26 }; 27 28 struct map_benchmark { 29 __u64 avg_map_100ns; /* average map latency in 100ns */ 30 __u64 map_stddev; /* standard deviation of map latency */ 31 __u64 avg_unmap_100ns; /* as above */ 32 __u64 unmap_stddev; 33 __u32 threads; /* how many threads will do map/unmap in parallel */ 34 __u32 seconds; /* how long the test will last */ 35 __s32 node; /* which numa node this benchmark will run on */ 36 __u32 dma_bits; /* DMA addressing capability */ 37 __u32 dma_dir; /* DMA data direction */ 38 __u64 expansion[10]; /* For future use */ 39 }; 40 41 int main(int argc, char **argv) 42 { 43 struct map_benchmark map; 44 int fd, opt; 45 /* default single thread, run 20 seconds on NUMA_NO_NODE */ 46 int threads = 1, seconds = 20, node = -1; 47 /* default dma mask 32bit, bidirectional DMA */ 48 int bits = 32, dir = DMA_MAP_BIDIRECTIONAL; 49 50 int cmd = DMA_MAP_BENCHMARK; 51 char *p; 52 53 while ((opt = getopt(argc, argv, "t:s:n:b:d:")) != -1) { 54 switch (opt) { 55 case 't': 56 threads = atoi(optarg); 57 break; 58 case 's': 59 seconds = atoi(optarg); 60 break; 61 case 'n': 62 node = atoi(optarg); 63 break; 64 case 'b': 65 bits = atoi(optarg); 66 break; 67 case 'd': 68 dir = atoi(optarg); 69 break; 70 default: 71 return -1; 72 } 73 } 74 75 if (threads <= 0 || threads > DMA_MAP_MAX_THREADS) { 76 fprintf(stderr, "invalid number of threads, must be in 1-%d\n", 77 DMA_MAP_MAX_THREADS); 78 exit(1); 79 } 80 81 if (seconds <= 0 || seconds > DMA_MAP_MAX_SECONDS) { 82 fprintf(stderr, "invalid number of seconds, must be in 1-%d\n", 83 DMA_MAP_MAX_SECONDS); 84 exit(1); 85 } 86 87 /* suppose the mininum DMA zone is 1MB in the world */ 88 if (bits < 20 || bits > 64) { 89 fprintf(stderr, "invalid dma mask bit, must be in 20-64\n"); 90 exit(1); 91 } 92 93 if (dir != DMA_MAP_BIDIRECTIONAL && dir != DMA_MAP_TO_DEVICE && 94 dir != DMA_MAP_FROM_DEVICE) { 95 fprintf(stderr, "invalid dma direction\n"); 96 exit(1); 97 } 98 99 fd = open("/sys/kernel/debug/dma_map_benchmark", O_RDWR); 100 if (fd == -1) { 101 perror("open"); 102 exit(1); 103 } 104 105 map.seconds = seconds; 106 map.threads = threads; 107 map.node = node; 108 map.dma_bits = bits; 109 map.dma_dir = dir; 110 if (ioctl(fd, cmd, &map)) { 111 perror("ioctl"); 112 exit(1); 113 } 114 115 printf("dma mapping benchmark: threads:%d seconds:%d node:%d dir:%s\n", 116 threads, seconds, node, dir[directions]); 117 printf("average map latency(us):%.1f standard deviation:%.1f\n", 118 map.avg_map_100ns/10.0, map.map_stddev/10.0); 119 printf("average unmap latency(us):%.1f standard deviation:%.1f\n", 120 map.avg_unmap_100ns/10.0, map.unmap_stddev/10.0); 121 122 return 0; 123 } 124