Perf

|

最近有一个客户报过来一个问题,说他们的Xserver变卡了。 通过回溯法,定位是到的commit是enable CLOCK_MONOTONIC

为了搞清楚原因,就得把perf请出来了。

环境

perf是和你当前内核绑定的,因此需要从内核源码里编译。

交叉编译建议是准备一个chroot的arm环境,可以参考我写在rockchip wiki的cross compile。 进入内核下tools/perf目录编译,完后把perf拷进板子就可以了。

编完后把perf文件拷到板子下

sudo apt-get install gcc build-essential flex zlib1g-dev bison libunwind-dev libbfd-dev libdw-dev libelf-dev
make

记得还要装一下你要debug程序的debug符号。

dpkg -i xserver-xorg-core-dbgsym_1.19.3-1_armhf.deb
sudo apt-get install libc6-dbg libgcc1-dbg

实验

在做实验前,先做下面的命令,把cpu频率和gpu频率定频住,保证出来的图不被干扰

echo performance > /sys/devices/platform/ffa30000.gpu/devfreq/ffa30000.gpu/governor
echo performance > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor

用下面命令测试下perf是否正常工作,以及函数符号是不是能看见

./perf record  -F 99 --call-graph dwarf -a -p $(pidof Xorg) -- sleep 60 
./perf report

实验的设计步骤如下:

  • 进入桌面, 打开terminal和chromium,使用默认size
  • 快速拖动chromium,同时输入./perf record –call-graph dwarf -a -p $(pidof Xorg) – sleep 60

获取火焰图

git clone https://github.com/brendangregg/FlameGraph.git
./perf script | ./FlameGraph/stackcollapse-perf.pl > out.perf-folded
./FlameGraph/flamegraph.pl out.perf-folded > perf-kernel.svg

总结

结果如下, 右键用新tab打开可以zoom:

两次完全没有区别嘛!被耍了,根本就不是这个的影响。
做为对比,这是待机状态下的:

这还只是其中一个小用法,perf太tm强了。(ง •̀_•́)ง
以后查performance再也不用print timestamp那种笨办法了。

其实这几个图都不好,xorg里面的stack trace都不完整,其实这是因为程序编译的时候选项fno-omit-frame-pointer没开(用的debian package,设置一下“DEB_CPPFLAGS_MAINT_APPEND”就好了),只能打印当前的指令是在哪个函数内,但不能打印整个调用函数栈。重做出的图如这个,是不是效果要好多了:

See Also

http://www.brendangregg.com/perf.html
http://blog.csdn.net/21cnbao/article/details/78527777?from=singlemessage
http://www.brendangregg.com/flamegraphs.html

顺便研究了下debug symbol的东西,放这里记录下:
http://blog.chinaunix.net/uid-13746440-id-5578048.html

差分: https://linux.cn/article-4670-1.html

直接在图片右上角搜索可以搜函数,不过默认图片太小了,也很难用。。。

Graphics User Guide(Rockchip Linux)

|

rockchip linux平台的graphic,和以往大家所习惯所不同的是,我们应该是最先全面应用上drmdmabuf的arm linux平台。优势是,通用的架构,在上面客制化会很容易,可以利用很多现有组件,现在有很多基础开源项目的开发,都开始基于rockchip平台来作为arm端的适配平台。但缺点是,确实大家都不是很理解这些东西,实际应用起来需要一个学习过程。

wiki资料点这里

hardware

vop

vop是display单元,用来显示图像 (比如输入nv12,rgb的buffer,显示到屏幕。输入1080p的图像,显示4k大小)。

rk3288有两个vop,vop有3个图层,前两个支持到4k分辨率,后一个鼠标层只有64×64。
rk3399同rk3288。
rk3036只有一个vop,2个图层,一个支持1080p,一个720p。

API

  • libdrm

gpu

gpu提供opengles api,适合做3d图形和2d图形的加速。

API

  • opengles
  • egl
  • opencl

software

先看这个结构图,有什么不理解可以留言。

重点理解libdrm,wayland和x11(compositor),mesa和libmali,qt和gtk(applcation)的关系。这张图理解了,写graphic就很轻松,不理解,就会一头雾水。

libdrm

libdrm是drm下沟通驱动和用户层的库。过去app可能是直接使用open(fb)这样的方式来和图形驱动沟通,但是在现在的硬件演化下,已经不合适了。比如硬件

  • 有多个图层怎么办?
  • 有多个屏幕怎么办?
  • 怎么处理vsync的问题,怎么同步不撕裂?
  • 怎么利用上dmabuf,做到memory zero-copy?

libdrm的存在就是用来方便用户层和驱动这些问题,提供API给X11, Wayland这样的display backend使用。如果你的程序比较简单,比如一个广告机循环播放视频,那是可以直接调用libdrm,但是不建议直接使用libdrm的api。原因很多:

  • 首先,你肯定不熟悉libdrm,因为libdrm本身是一个比较新的api,而且接触者局限在相关的drm driver developer和wayland/xserver developer这些人身上。
  • libdrm的演进比较快,比如说api还分atomic和legacy,你可能看到的资料和你现在用的完全不一样,只有熟悉演进记录的人才行。
  • 很多效果依赖于厂商的实现,甚至rockchip还有修改很多core API的表现效果来辅助我们内部产品项目,所以同个API在不同平台表现有可能完全不同的

当然,这里不是让你用x11和wayland,而是用我们封装好的东西。 比如,广告机循环播放视频,那最好是用gstreamer,然后选kmssink显示,而不是直接调用libdrm的api。

简单的理解

drm里有crtc,plane,connector这三个东西,可以理解

  • connector就是屏幕,比如一个hdmi一个connector num, 一个dsi一个connector num
  • crtc表示vop, 一个屏幕一般对应一个crtc
  • plane就是图层,比如视频层在plane2,UI在plane1, 视频在UI上面

drm里api分两套,legacy和atomic。

legacy看名字就是早期的api,我们现在大部分程序也都是用的legacy api。 里面有几个关键的funciton要注意下,drmModeSetCrtc包括了drmModeSetPlane包括了drmModePageFlip

drmModeSetCrtc一般是用来设置UI层,同时设置分辨率用,这里设下的size最后我改到屏幕的分辨率。在rockchip的bsp kernel上drmModeSetCrtc给出的buffer size不需要等于我们要设置的分辨率,这是为了实现在4k的屏幕上使用1080p的UI而做的,不过要注意,这是rockchip自己瞎改的。

drmModeSetPlane用来设置不同图层的显示,比如视频。参数上分别是要显示buffer fd,要操作的图层,要显示的大小,buffer的大小。他会缩放buffer显示到屏幕上。在rockchip平台上这个api是async的,两续调用两次,前面的就被覆盖了,可能需要drmwaitvblank一下,不过要注意,一般内核不会这样的。

为什么rockchip要改这么多地方呢。因为我们想在legacy的api上也完成多图层的显示。想下,我现在用两个图层,图层1和图层2,我现在图层1调用一次drmModeSetPlane,图层2调用一次drmModeSetPlane,然后他们都等一个vsync单位的时间,那假设屏幕刷新率60hz,我们的最大帧数是不是只有30fps了? 为了解决这个问题,上游的人又开发了atomic的api。

atomic api的实质可以理解为一个提交包括了所有的图层的更新信息。这样就不用调用两次drmModeSetPlane了,而是一次的drmModeAtomicCommit,跟上所有的参数。 atomic还有一个很有用的地方在他可以设置plane的zpos,这样就可以自由交换overlay plane和primary plane的显示层级了。之前我们在legacy api(kmssink)的时候都在kernel里hard code层级,但用atomic(mpv)的时候就不需要这样做,设置zpos后,osd(primary layer)也能在video(overlay layer)上面显示了。

资料

leagacy的实例

atomic的实例

当然最好还是看libdrm的文档和test程序。 如果你是自己写小程序,可以把mpp+libdrm那demo里的rkdrm下的文件抽出来自己用,还是挺方便的。如果只是写给rockchip平台用,就legacy api,如果还有多个平台的需求,就研究下atomic了。

libmali

libmali单独拉出来讲一下,这个东西就是arm提供的userspace gpu驱动。

前面说了,gpu是提供opengles,egl,opencl api的,所以你要这几个工作,就需要把libmali加进rootfs里。

默认的binary我们都会传github上: https://github.com/rockchip-linux/libmali

命名规则: gpu型号-软件版本-硬件版本(如果有的话,比如说r1p0区分3288和3288w)-编译选项。

要注意编译选项

  • 不带后缀。是x11-gbm,注意gbm是配置drm使用的memory机制,如果不是3.10的kernel,不要用fbdev的。
  • gbm。 是给qteglfs这样的程序用的,不依赖x11,wayland。
  • wayland。 wayland-gbm, 给wayaland使用

需要替换的系统链接: x11 or none: https://github.com/rockchip-linux/libmali/blob/rockchip/debian/libmali-rk-midgard-t76x-r14p0-r0p0.links wayland: https://github.com/rockchip-linux/libmali/blob/rockchip/debian/libmali-rk-midgard-t76x-r14p0-r0p0-wayland.links

zero-copy

用mali显示dmabuf的数据,比如说摄像头,视频,其实是可以用dmabuf zero-copy机制优化的。 不然载入texture还要cpu去拷贝。

参考:

x11

就和一般桌面平台差不多,不过要x11要有个gpu性能缺陷的问题。

https://en.wikipedia.org/wiki/X.Org_Server http://www.comptechdoc.org/os/linux/howlinuxworks/linux_hlxwindows.html https://dri.freedesktop.org/wiki/DDX/ https://www.freedesktop.org/wiki/Software/Glamor/

wayland

建议使用yocto sdk做wayland的开发。 不然不回答怎么编译,怎么运行的问题。

效率上wayland要比x11好点,主要是兼容性问题。如果不需要桌面,又要多窗口,可以wayland试试看。

zero-copy

wayland也有zero-copy的配置,可以搜下相关的wayland dmabuf。

资料

https://en.wikipedia.org/wiki/Wayland

none

不使用x11和wayland就是none啦,这也是我们嵌入式上接触比较多的。 什么minigui啊,sdl啦都是这样的。

不过要支持到drm和opengl这种的,就只有qt了。

qteglfs

QT EGLFS是qt自己实现的一个gui系统,不支持多窗口,但也因此少了window compoiste。
QT EGLFS和dri2的方式也差不多,区别就在于,qt eglfs的font buffer在自己用gpu compoiste后,是直接送给drm去显示,而X里是送Window manager去做compoiste,所以EGLFS在效率上是有优势的。

FAQ

输出4k,但是UI只想1080p

目前只支持qteglfs实现这种需求。 http://blog.iotwrt.com/tips/2017/06/04/swap-layer/

推荐下怎么选display

At present, the recommended choices for fullscreen window are :

  • qt with eglfs plugin
  • EGL program + x11
  • wayland
  • x11

The recommended choices for multi window are :

  • wayland
  • x11

The recommended choices for desktop are :

  • x11

The recommended choices for 4K playback + fullscreen window are :

  • qt with eglfs plugin
  • x11

The recommended choices for 4K playback + multi window are :

  • x11

Gstreamer学习

|

接触Gstreamer有一段时间了,但一直没有系统的了解过Gstreamer的结构,只是停留在”打补丁“这样的一种开发思维上。 虽然不是很喜欢gobject的风格,但毕竟开发不能总是没有头绪,还是需要系统的了解一下。

gobject

gstreamer是基于gobject开发的一个库,所以学习gstreamer前,需要先了解下gobject相关的基础。

中文 : https://www.ibm.com/developerworks/cn/linux/l-gobject/

一开始,可以先简单的看看这篇中文文章,对gobject有一个基础的认识。

英文 : https://developer.gnome.org/gobject/stable/

在后面的学习过程中,如果有遇到不理解,可以再回来check官方的manual

What is Gstreamer

https://gstreamer.freedesktop.org/documentation/application-development/introduction/index.html

这里的链接介绍了什么是gstreamer,他的结构是什么样。一般大家印象里,一个提供视频编解码的库,应该是ffmpeg那样,而gstreamer有点反这种印象。其实gstreamer不能说是一个库,而应该算是一种嵌入小程序。

关于gstreamer对使用者最主要的用处,见这段话:

The application programmer who wants to build a media pipeline. The programmer can use an extensive set of powerful tools to create media pipelines without writing a single line of code. Performing complex media manipulations becomes very easy.

Foundations里解释了一些在使用gstreamer的时候会遇到的名词,比如什么是elements,什么是pads。

Application

https://gstreamer.freedesktop.org/documentation/application-development/basics/index.html

过一遍即可,不过如果还没用过gstreamer的话,最好先用gst-launch多输几条命令玩玩先。 这里主要是进一步了解什么是elements, bins, pads, buffer以及你该如何在应用中使用。

Player

如果你是要做一个player,同时又是要直接使用gstreamer的话,看这里:
https://gstreamer.freedesktop.org/documentation/application-development/highlevel/index.html

使用playbin和decodebin来简化程序。

Advance

https://gstreamer.freedesktop.org/documentation/application-development/advanced/index.html

Plugin

https://gstreamer.freedesktop.org/documentation/plugin-development/index.html

Memory

https://gstreamer.freedesktop.org/documentation/plugin-development/advanced/allocation.html 关于memory的部分可以多看看,有助于编写程序。

Others

如果你的App不满足于media pipeline,你不会也不想写gstreamer plugin,那可以看看博客里的另一篇gstreamer+opencv,可以了解下如果使用appsink和appsrc,来达到类似ffmpeg输入输出的效果。

tips

看playbin选了什么plugin

export GST_DEBUG=decodebin:6

会报出选中的plugin。

Camera(Rockchip Linux)

|

rockchip-isp1

Moved to wiki.

http://opensource.rock-chips.com/wiki_Rockchip-isp1

3A

对没有商业支持的客户来说,用内置的ISP跑3A是用不起来的。因为每一种批次的模组,都需要经过tuning,得到参数才能用,而这个tuning是需要排队的。 所以你只能把他当成一个bypass的mipi-csi host,使用自带isp的sensor模组。

当然出于学习目的,我们也可以尝试下自己利用内置ISP去写3A的算法。

See also

http://www.360doc.com/content/16/1019/17/496343_599664458.shtml

Remote Wake Up from Deep Sleep with USB

|

PM Code have support keeping power for USB.

You just need to apply below pacthes to avoid usb phy being disabled.

    From ba76095e25daa35220f681aaccbcd54f2940b222 Mon Sep 17 00:00:00 2001
    From: Jacob Chen <jacob-chen@iotwrt.com>
    Date: Thu, 7 Sep 2017 15:06:13 +0800
    Subject: [PATCH] USB: dwc2: Don't turn off the usbphy in suspend

    Change-Id: I0dc42678f44664dfc2bbbc67bbfdf851bb87369a
    Signed-off-by: Jacob Chen <jacob-chen@iotwrt.com>
    ---
    drivers/usb/dwc2/platform.c | 4 ++++
    1 file changed, 4 insertions(+)

    diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
    index 60ffcb6..113bea0 100644
    --- a/drivers/usb/dwc2/platform.c
    +++ b/drivers/usb/dwc2/platform.c
    @@ -641,6 +641,8 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
            if (dwc2_is_device_mode(dwc2))
                    dwc2_hsotg_suspend(dwc2);
    
    +	return 0;
    +
            if (dwc2->ll_hw_enabled)
                    ret = __dwc2_lowlevel_hw_disable(dwc2);
    
    @@ -652,6 +654,8 @@ static int __maybe_unused dwc2_resume(struct device *dev)
            struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
            int ret = 0;
    
    +	return 0;
    +
            if (dwc2->ll_hw_enabled) {
                    ret = __dwc2_lowlevel_hw_enable(dwc2);
                    if (ret)
    -- 
    2.7.4

Comments