Commit ca947482 authored by Xiang Chen's avatar Xiang Chen Committed by Christoph Hellwig

dma-mapping: benchmark: Add support for multi-pages map/unmap

Currently it only support one page map/unmap once a time for dma-map
benchmark, but there are some other scenaries which need to support for
multi-page map/unmap: for those multi-pages interfaces such as
dma_alloc_coherent() and dma_map_sg(), the time spent on multi-pages
map/unmap is not the time of a single page * npages (not linear) as it
may use block description instead of page description when it is satified
with the size such as 2M/1G, and also it can send a single TLB invalidation
command to invalidate multi-pages instead of multi-times when RIL is
enabled (which will short the time of unmap). So it is necessary to add
support for multi-pages map/unmap.

Add a parameter "-g" to support multi-pages map/unmap.
Signed-off-by: default avatarXiang Chen <chenxiang66@hisilicon.com>
Acked-by: default avatarBarry Song <song.bao.hua@hisilicon.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent 42e4eefb
...@@ -38,7 +38,8 @@ struct map_benchmark { ...@@ -38,7 +38,8 @@ struct map_benchmark {
__u32 dma_bits; /* DMA addressing capability */ __u32 dma_bits; /* DMA addressing capability */
__u32 dma_dir; /* DMA data direction */ __u32 dma_dir; /* DMA data direction */
__u32 dma_trans_ns; /* time for DMA transmission in ns */ __u32 dma_trans_ns; /* time for DMA transmission in ns */
__u8 expansion[80]; /* For future use */ __u32 granule; /* how many PAGE_SIZE will do map/unmap once a time */
__u8 expansion[76]; /* For future use */
}; };
struct map_benchmark_data { struct map_benchmark_data {
...@@ -58,9 +59,11 @@ static int map_benchmark_thread(void *data) ...@@ -58,9 +59,11 @@ static int map_benchmark_thread(void *data)
void *buf; void *buf;
dma_addr_t dma_addr; dma_addr_t dma_addr;
struct map_benchmark_data *map = data; struct map_benchmark_data *map = data;
int npages = map->bparam.granule;
u64 size = npages * PAGE_SIZE;
int ret = 0; int ret = 0;
buf = (void *)__get_free_page(GFP_KERNEL); buf = alloc_pages_exact(size, GFP_KERNEL);
if (!buf) if (!buf)
return -ENOMEM; return -ENOMEM;
...@@ -76,10 +79,10 @@ static int map_benchmark_thread(void *data) ...@@ -76,10 +79,10 @@ static int map_benchmark_thread(void *data)
* 66 means evertything goes well! 66 is lucky. * 66 means evertything goes well! 66 is lucky.
*/ */
if (map->dir != DMA_FROM_DEVICE) if (map->dir != DMA_FROM_DEVICE)
memset(buf, 0x66, PAGE_SIZE); memset(buf, 0x66, size);
map_stime = ktime_get(); map_stime = ktime_get();
dma_addr = dma_map_single(map->dev, buf, PAGE_SIZE, map->dir); dma_addr = dma_map_single(map->dev, buf, size, map->dir);
if (unlikely(dma_mapping_error(map->dev, dma_addr))) { if (unlikely(dma_mapping_error(map->dev, dma_addr))) {
pr_err("dma_map_single failed on %s\n", pr_err("dma_map_single failed on %s\n",
dev_name(map->dev)); dev_name(map->dev));
...@@ -93,7 +96,7 @@ static int map_benchmark_thread(void *data) ...@@ -93,7 +96,7 @@ static int map_benchmark_thread(void *data)
ndelay(map->bparam.dma_trans_ns); ndelay(map->bparam.dma_trans_ns);
unmap_stime = ktime_get(); unmap_stime = ktime_get();
dma_unmap_single(map->dev, dma_addr, PAGE_SIZE, map->dir); dma_unmap_single(map->dev, dma_addr, size, map->dir);
unmap_etime = ktime_get(); unmap_etime = ktime_get();
unmap_delta = ktime_sub(unmap_etime, unmap_stime); unmap_delta = ktime_sub(unmap_etime, unmap_stime);
...@@ -112,7 +115,7 @@ static int map_benchmark_thread(void *data) ...@@ -112,7 +115,7 @@ static int map_benchmark_thread(void *data)
} }
out: out:
free_page((unsigned long)buf); free_pages_exact(buf, size);
return ret; return ret;
} }
...@@ -203,7 +206,6 @@ static long map_benchmark_ioctl(struct file *file, unsigned int cmd, ...@@ -203,7 +206,6 @@ static long map_benchmark_ioctl(struct file *file, unsigned int cmd,
struct map_benchmark_data *map = file->private_data; struct map_benchmark_data *map = file->private_data;
void __user *argp = (void __user *)arg; void __user *argp = (void __user *)arg;
u64 old_dma_mask; u64 old_dma_mask;
int ret; int ret;
if (copy_from_user(&map->bparam, argp, sizeof(map->bparam))) if (copy_from_user(&map->bparam, argp, sizeof(map->bparam)))
...@@ -234,6 +236,11 @@ static long map_benchmark_ioctl(struct file *file, unsigned int cmd, ...@@ -234,6 +236,11 @@ static long map_benchmark_ioctl(struct file *file, unsigned int cmd,
return -EINVAL; return -EINVAL;
} }
if (map->bparam.granule < 1 || map->bparam.granule > 1024) {
pr_err("invalid granule size\n");
return -EINVAL;
}
switch (map->bparam.dma_dir) { switch (map->bparam.dma_dir) {
case DMA_MAP_BIDIRECTIONAL: case DMA_MAP_BIDIRECTIONAL:
map->dir = DMA_BIDIRECTIONAL; map->dir = DMA_BIDIRECTIONAL;
......
...@@ -40,7 +40,8 @@ struct map_benchmark { ...@@ -40,7 +40,8 @@ struct map_benchmark {
__u32 dma_bits; /* DMA addressing capability */ __u32 dma_bits; /* DMA addressing capability */
__u32 dma_dir; /* DMA data direction */ __u32 dma_dir; /* DMA data direction */
__u32 dma_trans_ns; /* time for DMA transmission in ns */ __u32 dma_trans_ns; /* time for DMA transmission in ns */
__u8 expansion[80]; /* For future use */ __u32 granule; /* how many PAGE_SIZE will do map/unmap once a time */
__u8 expansion[76]; /* For future use */
}; };
int main(int argc, char **argv) int main(int argc, char **argv)
...@@ -51,11 +52,13 @@ int main(int argc, char **argv) ...@@ -51,11 +52,13 @@ int main(int argc, char **argv)
int threads = 1, seconds = 20, node = -1; int threads = 1, seconds = 20, node = -1;
/* default dma mask 32bit, bidirectional DMA */ /* default dma mask 32bit, bidirectional DMA */
int bits = 32, xdelay = 0, dir = DMA_MAP_BIDIRECTIONAL; int bits = 32, xdelay = 0, dir = DMA_MAP_BIDIRECTIONAL;
/* default granule 1 PAGESIZE */
int granule = 1;
int cmd = DMA_MAP_BENCHMARK; int cmd = DMA_MAP_BENCHMARK;
char *p; char *p;
while ((opt = getopt(argc, argv, "t:s:n:b:d:x:")) != -1) { while ((opt = getopt(argc, argv, "t:s:n:b:d:x:g:")) != -1) {
switch (opt) { switch (opt) {
case 't': case 't':
threads = atoi(optarg); threads = atoi(optarg);
...@@ -75,6 +78,9 @@ int main(int argc, char **argv) ...@@ -75,6 +78,9 @@ int main(int argc, char **argv)
case 'x': case 'x':
xdelay = atoi(optarg); xdelay = atoi(optarg);
break; break;
case 'g':
granule = atoi(optarg);
break;
default: default:
return -1; return -1;
} }
...@@ -110,6 +116,11 @@ int main(int argc, char **argv) ...@@ -110,6 +116,11 @@ int main(int argc, char **argv)
exit(1); exit(1);
} }
if (granule < 1 || granule > 1024) {
fprintf(stderr, "invalid granule size\n");
exit(1);
}
fd = open("/sys/kernel/debug/dma_map_benchmark", O_RDWR); fd = open("/sys/kernel/debug/dma_map_benchmark", O_RDWR);
if (fd == -1) { if (fd == -1) {
perror("open"); perror("open");
...@@ -123,14 +134,15 @@ int main(int argc, char **argv) ...@@ -123,14 +134,15 @@ int main(int argc, char **argv)
map.dma_bits = bits; map.dma_bits = bits;
map.dma_dir = dir; map.dma_dir = dir;
map.dma_trans_ns = xdelay; map.dma_trans_ns = xdelay;
map.granule = granule;
if (ioctl(fd, cmd, &map)) { if (ioctl(fd, cmd, &map)) {
perror("ioctl"); perror("ioctl");
exit(1); exit(1);
} }
printf("dma mapping benchmark: threads:%d seconds:%d node:%d dir:%s\n", printf("dma mapping benchmark: threads:%d seconds:%d node:%d dir:%s granule: %d\n",
threads, seconds, node, dir[directions]); threads, seconds, node, dir[directions], granule);
printf("average map latency(us):%.1f standard deviation:%.1f\n", printf("average map latency(us):%.1f standard deviation:%.1f\n",
map.avg_map_100ns/10.0, map.map_stddev/10.0); map.avg_map_100ns/10.0, map.map_stddev/10.0);
printf("average unmap latency(us):%.1f standard deviation:%.1f\n", printf("average unmap latency(us):%.1f standard deviation:%.1f\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment