关键词:DMA、sync、async、SIGIO、F_SETSIG。

DMA本身用于减轻CPU负担,进行CPU off-load搬运工作。

在DMA驱动内部实现有同步和异步模式,异步模式使用dma_async_issue_pending(),然后在callback()中发送SIGIO信号,用户空间收到SIGIO进行handler处理视为一个周期完成。

同步模式,采用dma_sync_wait()进行等待,期间并没有释放CPU给其他进程使用。

在一个项目中,发现DMA相关占用率高的问题,后来发现是因为其使用了同步模式。然后,将其改成异步模式,并对其进行详细的分析,记录如下。

那么当初为什么没有使用async IO模式呢?

原来是因为同一进程中其他线程也是用了async IO设备,由于kill_fasync()发送SIGIO信号,在一个进程内无法多个handler。

权宜措施使用了同步DMA,造成占用率高。

然后通过fcntl(fd, F_SETSIG, sig);解决了kill_fasync()发送相同SIGIO信号的冲突问题。

1. 问题发现:DMA同步模式占用率高

抓数据命令:

  1. perf record -a -e cpu-clock -- sleep 60
  2. perf report
  3. perf report -s comm

不同数据量,不同CMA处理方式下的top和perf结果:

Item 1 cma    per cma
top perf top perf
4K 25fps 15%   84.43% swapper [kernel.kallsyms] [k] __sched_text_end
11.51% main [kernel.kallsyms] [k] dma_cookie_status
2.81% main [kernel.kallsyms] [k] dma_sync_wait
0.20% main [kernel.kallsyms] [k] uart_write
0.13% swapper [kernel.kallsyms] [k] cache_op_range
0.12% swapper [kernel.kallsyms] [k] __dma_tx_complete
0.06% swapper [kernel.kallsyms] [k] dw_dma_tasklet
0.04% ksoftirqd/0 [kernel.kallsyms] [k] finish_task_switch
0.03% perf [kernel.kallsyms] [k] raw_copy_from_user
0.02% swapper [kernel.kallsyms] [k] __softirqentry_text_start
 61% 45.93% main [kernel.kallsyms] [k] dcache_wb_line
36.79% swapper [kernel.kallsyms] [k] __sched_text_end
4.86% main [kernel.kallsyms] [k] dma_cookie_status
4.06% main [kernel.kallsyms] [k] free_hot_cold_page
1.28% main [kernel.kallsyms] [k] dma_sync_wait
1.28% main [kernel.kallsyms] [k] skip_ftrace
0.66% main [kernel.kallsyms] [k] _mcount
0.58% main [kernel.kallsyms] [k] unset_migratetype_isolate
0.51% main [kernel.kallsyms] [k] __free_pages
0.41% main [kernel.kallsyms] [k] start_isolate_page_range
1080p 50fps 9% 89.82% swapper [kernel.kallsyms] [k] __sched_text_end
5.63% main [kernel.kallsyms] [k] dma_cookie_status
1.48% main [kernel.kallsyms] [k] dma_sync_wait
0.49% ksoftirqd/0 [kernel.kallsyms] [k] finish_task_switch
0.24% swapper [kernel.kallsyms] [k] dw_dma_tasklet
0.13% swapper [kernel.kallsyms] [k] __dma_tx_complete
0.10% swapper [kernel.kallsyms] [k] tasklet_action
0.10% main [kernel.kallsyms] [k] do_futex
0.06% main [kernel.kallsyms] [k] raw_copy_from_user
0.06% main [kernel.kallsyms] [k] restore_from_user_fp
44%  53.49% swapper [kernel.kallsyms] [k] __sched_text_end
30.73% main [kernel.kallsyms] [k] dcache_wb_line
3.65% main [kernel.kallsyms] [k] free_hot_cold_page
3.36% main [kernel.kallsyms] [k] dma_cookie_status
1.03% main [kernel.kallsyms] [k] skip_ftrace
0.85% main [kernel.kallsyms] [k] dma_sync_wait
0.56% main [kernel.kallsyms] [k] _mcount
0.48% main [kernel.kallsyms] [k] unset_migratetype_isolate
0.38% main [kernel.kallsyms] [k] __free_pages
0.33% main [kernel.kallsyms] [k] isolate_migratepages_range

问题的分析:

1. skip_trace和_mcount两个是因为ftrace引入的负荷,不合理。此时不应该有这些。----需要推动csky修改成Dynamic function/function_graph。

2. dcache_wb_line/free_hot_cold_page是CMA操作引起的。-----------------------------------这里需要修改处理方式,CMA不需要重复申请释放。

3. dma_cookie_status/dma_sync_wait是DMA操作引起的。------------------------------------这里可以通过修改DMA异步信号触发来降低占用率。

分析总结:

1. 从上面的测试结果看,应该尽量避免内存申请释放。csky内存处理效率很低。

2. 同步模式效率非常低,4K单路占用率达到15%,如果4K双路就没法使用了。

所以必须要使用异步模式,这也是使用DMA的初衷。

1.1 不同DMA size对性能影响

多大的传输使用DMA获得的收益最高呢?做了个实验,结果如下,横轴单位是B,纵轴单位是MB/s、

可以看出,DMA size大小越大效率越高,size接近3MB的时候,以及以后吞吐率就比较稳定了。

2. 分析问题:让DMA异步起来

  1. int axidma_memcpy(dma_addr_t src, dma_addr_t dst, unsigned int len)
  2. {
  3. struct dma_async_tx_descriptor *tx = NULL;
  4. dma_cookie_t cookie;
  5. unsigned long flags;
  6. bool sync_wait = false;-------------------------------------------------------------------true表示同步等待模式;false表示异步模式,和callback()配合。
  7. int err = ;
  8.  
  9. flags = DMA_CTRL_ACK | DMA_PREP_INTERRUPT;
  10.  
  11. tx = xxxxxx->dma.chan->device->device_prep_dma_memcpy(xxxxxx->dma.chan, dst, src, len, flags);
  12. if (!tx)
  13. {
  14. pr_err("Fail to prepare memcpy.\n");
  15. return -;
  16. }
  17.  
  18. tx->callback = axidma_callback;
  19. tx->callback_param = xxxxxx;
  20. cookie = tx->tx_submit(tx);
  21. if (dma_submit_error(cookie))
  22. {
  23. pr_err("Fail to submit axi dma.\n");
  24. return -;
  25. }
  26. if (!sync_wait) {
  27. dma_async_issue_pending(dma_dev->dma.chan);------------------------------------------发送DMA传输请求,然后退出。这里不会等待操作结果。
  28. } else {
  29. if (dma_sync_wait(dma_dev->dma.chan, cookie) == DMA_COMPLETE) {
  30. err = ;
  31. } else {
  32. err = -EIO;
  33. }
  34. }
  35.  
  36. return err;
  37. }
  38.  
  39. enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie)
  40. {
  41. enum dma_status status;
  42. unsigned long dma_sync_wait_timeout = jiffies + msecs_to_jiffies();-------------------超时5000ms,足够大了。
  43.  
  44. dma_async_issue_pending(chan);------------------------------------------------------------和之前同样功能,发送DMA传输请求。只是下面会进行等待,并有超时动作。
  45. do {
  46. status =dma_async_is_tx_complete(chan, cookie, NULL, NULL);--------------------------pool DMA传输状态。
  47. if (time_after_eq(jiffies, dma_sync_wait_timeout)) {
  48. dev_err(chan->device->dev, "%s: timeout!\n", __func__);
  49. return DMA_ERROR;-----------------------------------------------------------------超时退出。
  50. }
  51. if (status != DMA_IN_PROGRESS)
  52. break;
  53. cpu_relax();--------------------------------------------------------------------------让出CPU执行。
  54. } while ();
  55.  
  56. return status;
  57. }
  58.  
  59. static inline enum dma_status dma_async_is_tx_complete(struct dma_chan *chan,
  60. dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used)
  61. {
  62. struct dma_tx_state state;
  63. enum dma_status status;
  64.  
  65. status = chan->device->device_tx_status(chan, cookie, &state);
  66. if (last)
  67. *last = state.last;
  68. if (used)
  69. *used = state.used;
  70. return status;
  71. }

然后在callback()中发送SIGIO信号:

  1. static void axidma_callback(void *arg)
  2. {
  3. if(dma_dev->async)
  4. {
  5. pr_debug("axidma callback: chan=%s.\n", dma_chan_name(dma_dev->dma.chan));
  6. pr_debug("axidma_callback: magic=0x%08x pid_type=%d\n", dma_dev->async->magic, dma_dev->async->fa_file->f_owner.pid_type);
  7. kill_fasync(&dma_dev->async, SIGIO, POLL_IN);--------------------------------在传输完成后,异步发送SIGIO信号。
  8. }
  9. }

3. 解决问题:DMA异步传输

为了排除其他进程影响,单独构造3个试用例:1. 4K 25fps;2. 1080p 2路 25fps;3. 1080p 4路 25fps。

然后改成DMA异步模式,CPU占用率是否明显下降?

测试程序如下:

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>
  5. #include <poll.h>
  6. #include <signal.h>
  7. #include <sys/types.h>
  8. #include <unistd.h>
  9. #include <fcntl.h>
  10. #include <time.h>
  11. #include <pthread.h>
  12. #include <sys/prctl.h>
  13. #include <sys/syscall.h>
  14. #include <sys/ioctl.h>
  15. #include "IFMS_MemCMA_API.h"
  16.  
  17. int fd;
  18. unsigned int handle_count = ;
  19. volatile unsigned int dmatest_exit = ;
  20. volatile sigio_received = ;
  21. #define LOOP_COUNT 10000
  22. #define DMA_MEMCPY 0
  23. #define DMA_FILE "/dev/dpeye1000_axidma"
  24.  
  25. #define DPEYE1000_AXIDMA_IOC_MAGIC 'd'
  26. #define DPEYE1000_AXIDMA_REQUEST_CHNN _IOW(DPEYE1000_AXIDMA_IOC_MAGIC, 1, int) //Request channel.
  27. #define DPEYE1000_AXIDMA_RELEASE_CHNN _IOW(DPEYE1000_AXIDMA_IOC_MAGIC, 2, int) //Release channel.
  28. #define DPEYE1000_AXIDMA_MEMCPY _IOW(DPEYE1000_AXIDMA_IOC_MAGIC, 3, int) //Do 1d memcpy.
  29.  
  30. //#define PERFORMANCE_DEBUG
  31.  
  32. struct axidma_dma
  33. {
  34. struct dma_chan *chan;
  35.  
  36. unsigned long src;
  37. unsigned long dst;
  38.  
  39. // for memcpy
  40. unsigned int len;
  41. unsigned int n_channels;
  42. };
  43.  
  44. struct thread_para
  45. {
  46. unsigned int size;
  47. unsigned int expries;
  48. struct cma_block cma_block1;
  49. struct cma_block cma_block2;
  50. };
  51.  
  52. static struct axidma_dma axidma_dma;
  53. struct thread_para t_para;
  54. int dmacopy_tid = ;
  55.  
  56. void trigger_dma_copy(void)
  57. {
  58. int ret;
  59. #ifdef PERFORMANCE_DEBUG
  60. struct timespec time_0, time_1;
  61. unsigned long duration;
  62. float throughput = 0.0;
  63.  
  64. clock_gettime(CLOCK_REALTIME, &time_0);
  65. #endif
  66.  
  67. axidma_dma.src = (unsigned long)t_para.cma_block1.addr_p;
  68. axidma_dma.dst = (unsigned long)t_para.cma_block2.addr_p;
  69. axidma_dma.len = t_para.size;
  70. ret = ioctl(fd, DPEYE1000_AXIDMA_MEMCPY, &axidma_dma);
  71. if(ret < )
  72. {
  73. printf("fail to ioctl DPEYE1000_AXIDMA_MEMCPY!!!\n");
  74. }
  75. #ifdef PERFORMANCE_DEBUG
  76. clock_gettime(CLOCK_REALTIME, &time_1);
  77.  
  78. duration = (time_1.tv_sec-time_0.tv_sec)* + (time_1.tv_nsec-time_0.tv_nsec);
  79. throughput = (float)t_para.size/*/duration;
  80. printf("%ld.%ld %d %d, %ld, %f\n", time_1.tv_sec, time_1.tv_nsec, handle_count, t_para.size, duration, throughput);
  81. #endif
  82. }
  83.  
  84. void sigint_handler(int sig)
  85. {
  86. if(sig == SIGINT)
  87. {
  88. printf("%s SIGINT\n", __func__);
  89. dmatest_exit = ;
  90. }
  91. }
  92.  
  93. void sigio_handler(int sig)
  94. {
  95. if(sig == SIGIO)
  96. {
  97. sigio_received = ;
  98. }
  99. }
  100.  
  101. static void pthread_func(void *arg)
  102. {
  103. int ret;
  104. int Oflags;
  105. struct f_owner_ex owner_ex;
  106. struct timespec time1, time2;
  107. struct sigaction sa, sa2;
  108. sigset_t set, oldset;
  109. long long duration;
  110. unsigned int mode = DMA_MEMCPY;
  111.  
  112. ret = IFMS_MemCMAAlloc(t_para.size, &t_para.cma_block1);
  113. if(ret<)
  114. {
  115. printf("CMA alloc failed.\n");
  116. return -;
  117. }
  118.  
  119. ret=IFMS_MemCMAAlloc(t_para.size, &t_para.cma_block2);
  120. if(ret<)
  121. {
  122. printf("CMA alloc failed.\n");
  123. return -;
  124. }
  125.  
  126. //===========================================================================================
  127.  
  128. //Set thread name.
  129. prctl(PR_SET_NAME,"sigio");
  130. dmacopy_tid = syscall(SYS_gettid);
  131. printf("sigio thread tid=%ld %ld.\n", syscall(SYS_gettid), getpid());
  132.  
  133. //Set SIGIO actiong.
  134. memset(&sa, , sizeof(sa));
  135. sa.sa_handler = sigio_handler;
  136. sa.sa_flags |= SA_RESTART;
  137. sigaction(SIGIO, &sa, NULL);
  138.  
  139. //Set proc mask.
  140. sigemptyset(&set);
  141. sigprocmask(SIG_SETMASK, &set, NULL);
  142. sigaddset(&set, SIGIO);
  143.  
  144. fd = open(DMA_FILE, O_RDWR);
  145. if (fd < )
  146. {
  147. printf("Can't open %s!\n", DMA_FILE);
  148. }
  149.  
  150. //If set F_SETOWN_EX, SIGIO will send to this thread only.
  151. owner_ex.pid = syscall(SYS_gettid);
  152. owner_ex.type = F_OWNER_TID;
  153. fcntl(fd, F_SETOWN_EX, &owner_ex);
  154. Oflags = fcntl(fd, F_GETFL);
  155. fcntl(fd, F_SETFL, Oflags | FASYNC);
  156.  
  157. clock_gettime(CLOCK_REALTIME, &time1);
  158.  
  159. ret = ioctl(fd, DPEYE1000_AXIDMA_REQUEST_CHNN, &mode);
  160. if(ret < )
  161. {
  162. printf("fail to ioctl DPEYE1000_AXIDMA_REQUEST_CHNN!!!\n");
  163. }
  164.  
  165. while(!dmatest_exit)
  166. {
  167. if(t_para.expries > )
  168. usleep(t_para.expries);
  169. trigger_dma_copy(); //Send DMA copy request. while(!sigio_received)
  170. while(!sigio_received)
  171. {
  172.  
  173. pthread_sigmask(SIG_BLOCK, &set, &oldset);
  174. //sigprocmask(SIG_BLOCK, &set, &oldset);
  175. sigsuspend(&oldset); //Will pause here, and will be waked up by SIGIO.
  176. pthread_sigmask(SIG_UNBLOCK, &set, NULL);
  177. //sigprocmask(SIG_UNBLOCK, &set, NULL);
  178. handle_count++;
  179. }
  180. sigio_received = ;
  181. }
  182. clock_gettime(CLOCK_REALTIME, &time2);
  183. duration = (long long)(time2.tv_sec-time1.tv_sec)* + (time2.tv_nsec-time1.tv_nsec);
  184. sleep();
  185. printf("End time %lld.%09lld count=%d fps=%lld.\n", duration/, duration%, handle_count, (long long)handle_count*/duration);
  186.  
  187. ioctl(fd, DPEYE1000_AXIDMA_RELEASE_CHNN, NULL);
  188. if(ret < )
  189. {
  190. printf("fail to ioctl DPEYE1000_AXIDMA_RELEASE_CHNN!!!\n");
  191. }
  192. close(fd);
  193.  
  194. //===========================================================================================
  195.  
  196. ret=IFMS_MemCMAFree(t_para.cma_block1);
  197. if(ret<)
  198. {
  199. printf("CMA free failed.\n");
  200. return -;
  201. }
  202.  
  203. ret=IFMS_MemCMAFree(t_para.cma_block2);
  204. if(ret<)
  205. {
  206. printf("CMA free failed.\n");
  207. return -;
  208. }
  209. pthread_exit();
  210. }
  211.  
  212. void main(int argc, char **argv)
  213. {
  214. pthread_t tidp;
  215. sigset_t set;
  216. unsigned int size = , expries = ;
  217. struct sigaction sa;
  218.  
  219. if(argc != )
  220. {
  221. printf("Usage: %s size(B) expries(us).\n", argv[]);
  222. return -;
  223. }
  224. size = atoi(argv[]);
  225. if(!size)
  226. {
  227. printf("Please input right size.\n");
  228. return -;
  229. }
  230.  
  231. expries = atoi(argv[]);
  232. if(!expries)
  233. {
  234. printf("Please input right expries time.\n");
  235. return -;
  236. }
  237. t_para.size = size;
  238. t_para.expries = expries;
  239.  
  240. memset(&sa, , sizeof(sa));
  241. sa.sa_handler = sigint_handler;
  242. sa.sa_flags |= SA_RESTART;
  243. sigaction(SIGINT, &sa, NULL);
  244.  
  245. sigemptyset(&set);
  246. sigaddset(&set, SIGIO);
  247. sigprocmask(SIG_BLOCK, &set, NULL);
  248.  
  249. if(pthread_create(&tidp, NULL, pthread_func, NULL) == -)
  250. {
  251. printf("Create pthread error.\n");
  252. return;
  253. }
  254.  
  255. if(pthread_join(tidp, NULL))
  256. {
  257. printf("Join pthread error.\n");
  258. return;
  259. }
  260. printf("Main exit.\n");
  261.  
  262. return;
  263. }

3.1 DMA异步和同步在不同场景下对比测试

dma_thread测试不同分辨率、不同帧率下的性能对比:

Case 同步DMA 异步DMA
top -d 5

perf record -a -e cpu-clock -- sleep 60

top -d 5 perf record -a -e cpu-clock -- sleep 60

1080p 50fps

dma_thread 3110400 20000

7.5%

单次耗时:1.6ms

91.12% swapper [kernel.kallsyms] [k] __sched_text_end
6.29% main [kernel.kallsyms] [k] dma_cookie_status
1.70% main [kernel.kallsyms] [k] dma_sync_wait
0.05% swapper [kernel.kallsyms] [k] tick_nohz_idle_enter
0.04% perf [kernel.kallsyms] [k] skip_ftrace
0.04% perf [kernel.kallsyms] [k] raw_copy_from_user

91.22% swapper

8.04% main
0.43% perf
0.11% jbd2/mmcblk1p2-
0.08% mmcqd/1

dma_sigio 3110400 20000

0.3%

单次耗时:135us

98.57% swapper
0.53% perf
0.46% sleep
0.21% mmcqd/1
0.15% jbd2/mmcblk1p2-
0.04% kworker/u2:2
0.03% sigio

1080p 100fps

dma_thread 3110400 10000

14.1%

单次耗时:1.6ms

84.27% swapper [kernel.kallsyms] [k] __sched_text_end
11.78% main [kernel.kallsyms] [k] dma_cookie_status
3.13% main [kernel.kallsyms] [k] dma_sync_wait
0.04% perf [kernel.kallsyms] [k] skip_ftrace
0.03% perf [kernel.kallsyms] [k] raw_copy_from_user

84.30% swapper
14.98% main
0.45% perf
0.10% jbd2/mmcblk1p2-
0.09% mmcqd/1

dma_sigio 3110400 10000

0.5%

单次耗时:135us

98.48% swapper
0.63% perf
0.50% sleep
0.21% mmcqd/1
0.11% jbd2/mmcblk1p2-
0.05% kworker/u2:1
0.02% sigio

4k 25fps

dma_thread 13271040 40000

14.5%

单次耗时:6.7ms

84.71% swapper [kernel.kallsyms] [k] __sched_text_end
11.35% main [kernel.kallsyms] [k] dma_cookie_status
2.88% main [kernel.kallsyms] [k] dma_sync_wait
0.04% perf [kernel.kallsyms] [k] skip_ftrace

84.75% swapper
14.53% main
0.43% perf
0.10% jbd2/mmcblk1p2-
0.07% mmcqd/1

dma_sigio 13271040 40000

0.2%

单次耗时:135us

98.51% swapper
0.56% perf
0.48% sleep
0.23% mmcqd/1
0.15% jbd2/mmcblk1p2-
0.04% kworker/u2:0
0.03% sigio

分析总结:

1. 同步模式下,CPU占用率跟数据量大小强相关,基本成正比;影响CPU占用率的最大因素是DMA传输同步等待,即上面dma_sync_wait()和dma_cookie_status()两个函数。

2. 异步模式下,请求发送后,交出CPU,在收到信号后继续下一次发送,期间不会占用CPU。CPU占用率跟DMA请求次数强相关,主要是发送请求,以及sigsuspend()和SIGIO信号处理占用。

3. 帧的吞吐率受DMA传输的帧大小影响。

3.2 那么异步模式的极限在哪里?

明显DMA的异步极限帧率,同样受限于DMA传输效率,并不会增大吞吐率。

那么看看不同帧率下的CPU情况:

Case 异步DMA
top -d 5 perf record -a -e cpu-clock -- sleep 60

1080p 550 fps

(max)

2.6%

96.50% swapper
1.93% sigio
0.62% perf
0.57% sleep
0.21% mmcqd/1

1080p 375 fps  1.8

98.44% swapper
0.56% perf
0.51% sleep
0.22% mmcqd/1
0.16% jbd2/mmcblk1p2-
0.08% sigio

 1080p 273 fps 1.2% 

98.43% swapper
0.58% perf
0.51% sleep
0.24% mmcqd/1
0.14% jbd2/mmcblk1p2-
0.05% sigio

4K 145 fps

(max)

0.8%

98.45% swapper
0.55% perf
0.45% sleep
0.23% mmcqd/1
0.14% sigio

所以DMA极限帧率,主要受DMA传输大小和传输速度影响。

3.3 kernelshark对比DMA同步/异步模式

分别看看上面3个场景下同步模式下,kernelshark输出可以看出1080p执行时间是1.67ms,4k时间是6.88ms;每次时间间隔跟fps设置也对应。

1080p 50fps、1080p 100fps、4k 25fps三种占用率应该是1.67/21.67=7.7%、1.67/11.67=14.3%、6.88/46.88=14.7%。

再来看一下异步情况下的输出,这时候越是大尺寸DMA传输CPU占用率的收益越大。4k的时候

下面以1080p和4k对比看一下异步的收益。

1080p的DMA传输占用时间从1.65,降到了1.65-1.57=0.08,收益率95%。

可以看出4k情况下异步DMA的CPU占用时间从6.70,降到6.70-6.64=0.06,收益率达到99%。

4. 同进程多SIGIO冲突解决

当测试通过,进入方案的时候遇到SIGIO无法接收到的问题。

检查得知,原来是存在多个设备kill_fasync()。而一个进程范围内,SIGIO只能有一个handler。

通过fcntl()设置F_SETSIG可以定义sig代提SIGIO发送信号。

操作如下:

  1. #define SIGDMA (SIGRTMIN+1)--------------------------定义一个实时信号
  2.  
  3. fcntl(fd, F_SETSIG, SIGDMA);---------------------使用SIGDMA代提SIGIO作为async信号。
  4.  
  5. memset(&sa, , sizeof(sa));
  6. sa.sa_sigaction = sigdma_handler;----------------一定要修改为sa_sigaction,对应的sigdma_handler参数也需要修改。
  7. sa.sa_flags = SA_RESTART | SA_SIGINFO;-----------一定要增加SA_SIGINFO
  8. sigaction(SIGDMA, &sa, NULL);

除了有上面的好处之外,实时信号还能排队,这就比非实时信号更不会丢失。除非队列溢出。

5. 实际场景提升效果

在实际场景中,每40ms来一帧数据进行DMA搬运,

那么这段时间内,整个线程占用多少时间呢?2.303-0.225=2.078ms,对应的CPU占用率应该是5.2%。

再看看异步DMA实际效果如何?可以看出copy线程,中间调度出去的时间增大不小。

那么此时CPU占用率多少呢?2.288-1.177-0.431=0.68ms,对应的CPU占用率应该是1.7%。

从计算来看CPU占用率能降低3%左右。

6. 其他方案

1. 使用AXI DMA两通道,能否提高DMA吞吐率?相当于DMA并发,copy双线程?------------硬件双通道,如何构造同时触发的双通道case?

2. 如何标识每一次DMA传输,通过netlink port端口?--------------------------------------------------修改异步触发方式,port和channel绑定

一款DMA性能优化记录:异步传输和指定实时信号做async IO的更多相关文章

  1. React性能优化记录(不定期更新)

    React性能优化记录(不定期更新) 1. 使用PureComponent代替Component 在新建组件的时候需要继承Component会用到以下代码 import React,{Componen ...

  2. Mysql 性能优化记录

    记录工作中有关mysql性能优化的心得和经验 1. where条件中的字段 尽量建立索引 2. where条件中的查询条件等号左边尽量不做处理 如查询日期相关字段,尽量不使用date_fromat 或 ...

  3. web性能优化之--合理使用http缓存和localStorage做资源缓存

    一.前言 开始先扯点别的: 估计很多前端er的同学应该遇到过:在旧项目中添加新的功能模块.或者修改一些静态文件时候,当代码部署到线上之后,需求方验收OK,此时你送了一口气,当你准备开始得意于自己的ma ...

  4. SSD性能优化记录

    在上一篇博文中,我设计了一个优化方法,方法从业务角度出发,将切图操作涉及到的性能路径剖析出来,分别进行优化,效果显著. 眼下的情况是:一张ArcGIS武汉市城市影像图.该操作由79小时缩短至当前的67 ...

  5. Webpack 性能优化 (一)(使用别名做重定向)

    前言 Webpack 是 OneAPM 前端技术栈中非常重要的一部分.它非常好用,假设你还不了解它,建议你阅读这篇Webpack 入门指迷,在 OneAPM 我们用它完毕静态资源打包.ES6 代码的转 ...

  6. Yslow网站性能优化工具

    Yslow是一款网站性能优化的插件:

  7. 前端性能优化(三)——传统 JavaScript 优化的误区

    注:本文是纯技术探讨文,无图无笑点,希望您喜欢 一.前言 软件行业极其缺乏前端人才这是圈内的共识了,某种程度上讲,同等水平前端的工资都要比后端高上不少,而圈内的另一项共识则是--网页是公司的脸面! 几 ...

  8. Oracle性能优化1-总体思路和误区

    最近在看梁敬彬老师关于Oracle性能优化的一些案例,在这里做一些简单的总结 1.COUNT(*)与COUNT(列)哪个更快 drop table t purge; create table t as ...

  9. Yahoo关于性能优化的N条规则

    本来这是个老生常谈的问题,上周自成又分享了一些性能优化的建议,我这里再做一个全面的Tips整理,谨作为查阅型的文档,不妥之处,还请指正: 一. Yahoo的规则条例: 谨记:80%-90%的终端响应时 ...

随机推荐

  1. 说说不知道的Golang中参数传递

    本文由云+社区发表 导言 几乎每一个C++开发人员,都被面试过有关于函数参数是值传递还是引用传递的问题,其实不止于C++,任何一个语言中,我们都需要关心函数在参数传递时的行为.在golang中存在着m ...

  2. 为容器化的 Go 程序搭建 CI

    本文介绍如何使用 Jenkins 的声明式 pipeline 为一个简单的 Golang web 应用搭建 CI 环境.如果你还不太了解 Jenkins 及其声明式 pipeline,请先参考笔者的 ...

  3. Mybatis学习(六)————— Spring整合mybatis

    一.Spring整合mybatis思路 非常简单,这里先回顾一下mybatis最基础的根基, mybatis,有两个配置文件 全局配置文件SqlMapConfig.xml(配置数据源,全局变量,加载映 ...

  4. MySQL递归查询_函数语法检查_GROUP_CONCAT组合结果集的使用

    1-前言: 在Mysql使用递归查询是很不方便的,不像Sqlserver可以直接使用声明变量,使用虚拟表等等.如:DECLARE,BEGIN ...  END   ,WHILE ,IF 等等. 在My ...

  5. Java Calendar类的使用总结

    在实际项目当中,我们经常会涉及到对时间的处理,例如登陆网站,我们会看到网站首页显示XXX,欢迎您!今天是XXXX年....某些网站会记录下用户登陆的时间,比如银行的一些网站,对于这些经常需要处理的问题 ...

  6. Java开发笔记(六十一)Lambda表达式

    前面介绍了匿名内部类的简单用法,通过在sort方法中运用匿名内部类,不但能够简化代码数量,还能保持业务代码的连续性.只是匿名内部类的结构仍显啰嗦,虽然它省去了内部类的名称,但是花括号里面的方法定义代码 ...

  7. Android开发——使用intent传递对象

    intent传递对象有两种方法: 方式一:Serializable 方式 方式二:Parcelable方式 在这里不多介绍了,这一篇就是快速上手使用教程,至于详细原理介绍的,请看这一篇http://w ...

  8. Cesium 之简介以及离线部署运行篇

    前言 cesium 官网的api文档介绍地址cesium官网api,里面详细的介绍 cesium 各个类的介绍,还有就是在线例子:cesium 官网在线例子,这个也是学习 cesium 的好素材. C ...

  9. 解决一个Ubuntu中编译NEON优化的OpenCV的错误

    在Ubuntu 16中编译开启NEON优化的Opencv时,遇到libpng编译是使用汇编代码的错误,完整错误见文章末尾.通过查询发现解决方案是安装跨平台编译器,安装代码如下: sudo apt-ge ...

  10. HttpWebRequest 改为 HttpClient 踩坑记-请求头设置

    HttpWebRequest 改为 HttpClient 踩坑记-请求头设置 Intro 这两天改了一个项目,原来的项目是.net framework 项目,里面处理 HTTP 请求使用的是 WebR ...