T330N性能优化总结

来源:互联网 发布:网络电视如何回看 编辑:程序博客网 时间:2024/05/21 03:25
 t330n最初状态:app程序从fpga抓取视频数据送到一个fifo,video_pes_pack线程在该fifo中取出视频数据,将数据整理成一帧一帧的pes视频数据,然后将每一帧的视频数据打碎成固定188字节的长度送到array fifo中去,然后还有一个线程从这个fifo中将数据取出来通过udp socket发送到cmu_3g_app。
在最开始的时候效果很不好,3M情况下会有码流丢失,且cpu占用率很高,6M码率情况下50%左右。
     为了对3M码流下的效果进行优化,首先怀疑进程间的udp socket传递码流时会丢失数据,因为udp并不是基于连接的,属于不可靠的传递数据的方式。linux进程间的传递数据的方式还有pipe方式,并且pipe管道的方式是可靠的,因此采用pipe方式来传递数据,此时在3M的情况下画面可以确保基本不卡。但是提升码率的情况下还是会卡。
     为了找数据在什么地方丢失,有两个可以怀疑的地方,一个是fpga的fifo很小,有64K,因此当码率大的情况下可能会来不及去读取这个fpga中的视频数据。造成数据丢失。另一个就是pipe实际上也是fifo,pipe的fifo是否会溢出。
首先研究了一下pipe的fifo大小,网上有说4k的,有说64k的,具体的确定不了,总之很小,当码率大的时候是可能会发生数据丢失(阻塞)的情况。
     接着网上搜索了一下linux进程间传递数据的方式,发现有个unix domain socket,是基于可靠连接的,但是比tcp少了一层协议,比socket的效率高很多。 因此果断采用之,并且丢数据的时候加上打印信息,一旦丢失立马发现。果然效果比pipe要好很多,但是当在6M码率的情况下还是会卡。
     接着就在read fpga这里加上打印信息发现每出现一次video fpga fifo full一次,视频就会卡一次,因此这时解决问题的焦点便聚集在读fpga视频数据这了。
     现在问题的焦点是当视频码率高的时候来不及读fpga中的视频数据,因此fpga fifo满,造成之前的数据被覆盖,进而造成视频数据丢失。因此解决的方法从两个方面来考虑:一是优化app程序,降低cpu的占用率,提高读fpga线程的优先级,使cpu有更多的机会来读fpga,二是提高读fpga视频数据的效率。
     第一种方法可以考虑使用renice命令提升线程的优先级,优先级范围是-20~20,值越低优先级越高。这样读fpga线程便有更多的机会去执行。紧接着就是降低cpu的占用率了。首先优化了分析视频数据,找视频帧的地方,一次没找着记录下位置,下次接着在记录的地方找,这个属于算法的优化。另一方面由于历史原因现在的t330n跑了两个程序,因此视频数据在两个程序之间传输需要借助于第三方工具,使用了domain_socket。在T330n的项目中,跑两个程序是没有必要的,因为这两个程序完全属于前后级的关系,将t330的app程序做成库的方式给cmu_3g_app来调用的话,cmu_3g_app可以直接在内存中访问t3的fifo,这样可以省掉几个线程以及fifo(通过实验证明,当有大数据在内存中流动的时候,会加重cpu的负担),经过这两个方面的优化,将cpu占用率降低了10%。在编译内核的时候也有个选项,之前我们的内核都是编译成debug模式,若编译成(release模式?),我们的程序又降低了10%。
     第二个是关于读fpga视频的效率问题,之前是一个字节一个字节在fpga上的地址读出来的,我们将读fpga的线程移植到驱动层去做,并且一次读取32字节,(经过实验,一次处理多个字节比每次读1个字节的效率要高),由于驱动层的执行优先级比应用层要高,加上32字节复制一次,效果又有了一次明显的进展。cpu占用率降低了至少5%。
     经过上面的优化,目前的情况是9M的码率通过6张的wifi发送,cpu占用率55%左右。但此时还是有优化的空间。这个项目的根本问题在于fpga的视频fifo比较小,我们来不及读视频数据,因此我们做的所有的努力都是尽可能的让cpu更多的去读fpga的视频数据。即读fpga视频数据的实时性要求是最高的。在linux中能实现最高的实时性手段就是中断。
     我们可以通过中断,来强迫cpu来读fpga视频数据。因此最后的解决方案是当fpga中的数据有16K的时候便给cpu一个中断,此时cpu在驱动中将视频数据读取到一个fifo中去。用户层读视频数据时,就读这个kfifo中的数据,kfifo的大小可以我们人工指定,因此问题解决~~~

     最后总结一下:
     1.linux本机进程间通信的最好方法是domain socket。(不能跨机器)。
     2.对实时性要求比较高的工作可以移到驱动层通过中断来做。
     3.在linux下(非实时性内核)可以通过renice命令加上线程id的方式提高线程优先级。
     4.内核通过debug方式编译的效率比较低,因此正式使用的时候尽量不要通过debug模式来编译。

原创粉丝点击