我们基于2004的gstreamer版本在1.16.2/1.16.3上,为了提高gstreamer的可用性,我们跟进了rk的补丁,这样gstreamer可以良好的运行在系统上,所以我们需要升级gstreamer到1.20上,然后提供1.20的测试命令
针对1.20.1的版本选择,我们需要根据ubuntu的发行release来进行跟进,这里跟进基于jammy上,所以是1.20.1。如下以gstreamer1.0-plugins-bad为示例
针对此,我们所有的代码溯源来自于
https://launchpad.net/ubuntu/
内的release源地址的gstreamer包,这个包的版本是1.20.1-1系列
为了使得这个版本能够合入rk的补丁,我们需要找到rk补丁地址如下:
https://github.com/JeffyCN/meta-rockchip/tree/master/recipes-multimedia/gstreamer
针对此,我们需要找到1.20.7的版本补丁来进行1.20.1的微调,如下:
对于补丁的批量合入,我们如下脚本:
for p in *.patch; do patch -p1 < $p done
这里需要留意的是,如果出现了rej,请格外小心,注意合入
如果出现了orig,则对照上下文,判断自动合入是否存在问题
对于上述包的升级,我们还需要针对依赖来进行依赖包的rebuild操作,这里来源仍是https://launchpad.net/ubuntu/
内的release源地址
根据ppa的本地构建,这里已经完成了构建,ppa地址如下:
https://dev.kylinos.cn/~tangfeng/+archive/kylin-desktop/gstreamer-rk-patch
具体包和依赖图示如下:
至此,gstreamer已经完全正常,我们只需要将源更新如下,即可升级1.20.1-1的gstreamer源码
deb http://ppa.launchpad.dev/tangfeng/gstreamer-rk-patch/kylin-desktop v101 main
我们良好的构建了gstreamer后,需要进行一系列的命令测试,如下:
为了支持kms,例如开机动画等操作,我们可以如下:
gst-launch-1.0 videotestsrc ! kmssink force-modesetting=true fullscreen=true
如有测试视频,可以如下:
gst-play-1.0 -q --no-interactive --audiosink=fakesink --videosink="kmssink force-modesetting=true fullscreen=true" /usr/local/test.mp4
简单的测试一个视频的命令如下:
gst-play-1.0 --flags=3 /usr/local/test.mp4
如果需要看到fps值,如下:
GST_DEBUG=fpsdisplaysink:7 gst-launch-1.0 uridecodebin uri=file:///usr/local/test.mp4 ! fpsdisplaysink video-sink="xvimagesink" text-overlay=false signal-fps-measurements=true
如果测试最大fps值,则如下:
GST_DEBUG=fpsdisplaysink:7 gst-launch-1.0 uridecodebin uri=file:///usr/local/test.mp4 ! fpsdisplaysink video-sink="fakesink" text-overlay=false signal-fps-measurements=true sync=false
测试isp摄像头,因为出图是NV12的,所以需要指定:
gst-launch-1.0 v4l2src device=/dev/video-camera0 ! video/x-raw,format=NV12,width=640,height=480,framerate=30/1 ! xvimagesink
测试usb摄像头,因为出图是mjpeg的,所以命令如下
gst-launch-1.0 v4l2src device=/dev/video0 ! image/jpeg ! jpegparse ! mppjpegdec ! xvimagesink sync=false
如果需要rkximagesink,如下:
GST_DEBUG=rkximagesink:2 gst-launch-1.0 uridecodebin uri=file:///usr/local/test.mp4 ! fpsdisplaysink video-sink="rkximagesink" text-overlay=false signal-fps-measurements=true
注意,如果使用rkximagesink,请内核提供良好的图层让其分配,否则会提示no window。
本文以初学者的角色对glibc的malloc进行简单的解析,从而了解malloc的简要知识,根据此文章,可以知道什么是fastbin,smallbin,largebin等等。
我们需要知道的是,通过glibc的malloc申请的内存,其返回的指针地址只是整个内存的chunk的userdata,其整体布局应该如下:
根据上图,我们可以知道如下信息:
我们需要知道的是,通过glibc的free释放的内存,它不会直接返还给操作系统从而让其他程序使用,而是简单的标记这块地址为reused,只有程序的内存到达一定的阈值情况下,或者程序申请内存时当前chunk不足以满足的情况下,触发glibc的consolidate。如下是free时的指针布局情况,如下:
根据上图,结合
https://sourceware.org/glibc/wiki/MallocInternals
,我们可以知道如下信息:
根据上面的信息,我们提到了各类的bin,当我们在malloc和free时,其实对应的是每个chunk,而每个chunk都根据chunk_size代表一个bin类型。注意,这里的chunk_size是包含chunk结构体的size大小,而不是给用户的内存地址和偏移下的大小。
对于常规bin,例如smallbin,largebin等一共是126个,如下:
对于fastbin,一个10个,所以总共有136个bin,如下:
这里我们谈论的bin的个数其实是bin的数组,实际上不同的bin数组内部是用不同的链表实现。例如fastbin使用单链表,其他bin使用双向循环链表
因为fastbin是单链表,所以结构体中的bck指针是没用的,只用到了fwd指针,如下:
对于其他的bin,它使用了双向循环链表,如下:
这里比较清晰的是,在free chunk中,fwd和bck指针都用到了。
除了各种bin的链表管理方式不同之外,我们还需要知道区分其bin的方式,通过内存大小,如下:
32 <= fastbin_size <= 128 128 < smallbin_size <= 1024 1024 < largebin_size <= 128*1024
注意,根据上面提到的,这个chunk size是包括chunk struct的size,而不是用户malloc的size。
至此,我们可以知道,通过malloc和free管理的内存,分为多个bin,有fastbin,smallbin,largebin等等。下面通过代码的方式来验证一下
我们想要写一个测试程序,用来验证我们上述情况,首先,我们需要拿到chunk struct,这里以glibc 2.31为例,其结构体如下
struct malloc_chunk { size_t mchunk_prev_size; /* Size of previous chunk (if free). */ size_t mchunk_size; /* Size in bytes, including overhead. */ struct malloc_chunk* fd; /* double links -- used only if free. */ struct malloc_chunk* bk; /* Only used for large blocks: pointer to next larger size. */ struct malloc_chunk* fd_nextsize; /* double links -- used only if free. */ struct malloc_chunk* bk_nextsize; };
根据上面我们可以看到,在64位系统上malloc_chunk的大小是48(6*8)
为了解析chunk,我编写了inpect_chunk函数,如下
static void inspect_chunk(void *ptr) { struct malloc_chunk *chunk = (struct malloc_chunk *)((char *)ptr - 2*sizeof(size_t)); size_t chunk_size = chunk->mchunk_size & ~0x7; // Mask out the metadata bits int prev_inuse = chunk->mchunk_size & 1; int is_mmapped = chunk->mchunk_size & 2; int main_arena = chunk->mchunk_size & 4; printf("Chunk address=%p. ", (void *)chunk); printf("size=%zu. AMP=%#lx: \n\t", chunk_size, chunk->mchunk_size & 0x7); printf("main-arena=%s. ", main_arena ? "[No]" : "[Yes]"); printf("with_mmap=%s. ", is_mmapped ? "[Yes]" : "[No]"); printf("prev_in_use=%s. ", prev_inuse ? "[Yes]" : "[No]"); if (chunk_size <= 128) { printf("is fast bin.\n"); } else if (chunk_size <= 1024) { printf("is small bin.\n"); } else { printf("is large bin.\n"); } }
我对用户malloc的指针向前推进了16字节,此时我们得到一个chunk指针,它的类型是malloc_chunk。然后我用chunk来进行判断
为了进行一系列的bin测试,我编写了测试函数如下:
void main() { malloc_stats(); int* a = malloc(sizeof(int)); inspect_chunk(a); free(a); a = malloc(0); inspect_chunk(a); free(a); a = malloc(128-8); inspect_chunk(a); free(a); a = malloc(128-7); inspect_chunk(a); free(a); a = malloc(1024-8); inspect_chunk(a); free(a); a = malloc(1024-7); inspect_chunk(a); free(a); a = malloc(128*1024-23); inspect_chunk(a); free(a); printf("%ld <= fastbin_size <= %ld\n", MIN_CHUNK_SIZE, DEFAULT_MXFAST); printf("%ld < smallbin_size <= %ld\n", DEFAULT_MXFAST, MIN_LARGE_SIZE); printf("%ld < largebin_size <= 128*1024 \n", MIN_LARGE_SIZE); malloc_stats(); }
我分别malloc了0,128,1024,128*1024等相关字节
为了让这个代码正常运行,需要包含malloc.h头文件和必要的宏定义,宏定义需要从glibc源码中摘抄如下:
#include <stdio.h> #include <malloc.h> #include <string.h> #include <stdlib.h> #include <stddef.h> # define INTERNAL_SIZE_T size_t #define SIZE_SZ (sizeof (INTERNAL_SIZE_T)) #define MALLOC_ALIGNMENT (2 * SIZE_SZ < __alignof__ (long double) \ ? __alignof__ (long double) : 2 * SIZE_SZ) #define NSMALLBINS 64 #define SMALLBIN_WIDTH MALLOC_ALIGNMENT #define SMALLBIN_CORRECTION (MALLOC_ALIGNMENT > 2 * SIZE_SZ) #define MIN_LARGE_SIZE ((NSMALLBINS - SMALLBIN_CORRECTION) * SMALLBIN_WIDTH) #define MIN_CHUNK_SIZE (offsetof(struct malloc_chunk, fd_nextsize)) #define DEFAULT_MXFAST (64 * SIZE_SZ / 4)
至此,我们可以轻松的运行这个程序,如下:
gcc test_malloc_chunk.c -o test_malloc_chunk && ./test_malloc_chunk
从而得到输出如下:
Arena 0: system bytes = 135168 in use bytes = 3680 Total (incl. mmap): system bytes = 135168 in use bytes = 3680 max mmap regions = 0 max mmap bytes = 0 --------------------------------------------- Chunk address=0x559f9f0270. size=32. AMP=0x1: main-arena=[Yes]. with_mmap=[No]. prev_in_use=[Yes]. is fast bin. Chunk address=0x559f9f0270. size=32. AMP=0x1: main-arena=[Yes]. with_mmap=[No]. prev_in_use=[Yes]. is fast bin. Chunk address=0x559f9f0290. size=128. AMP=0x1: main-arena=[Yes]. with_mmap=[No]. prev_in_use=[Yes]. is fast bin. Chunk address=0x559f9f0310. size=144. AMP=0x1: main-arena=[Yes]. with_mmap=[No]. prev_in_use=[Yes]. is small bin. Chunk address=0x559f9f03a0. size=1024. AMP=0x1: main-arena=[Yes]. with_mmap=[No]. prev_in_use=[Yes]. is small bin. Chunk address=0x559f9f07a0. size=1040. AMP=0x1: main-arena=[Yes]. with_mmap=[No]. prev_in_use=[Yes]. is large bin. Chunk address=0x7f96c52000. size=135168. AMP=0x2: main-arena=[Yes]. with_mmap=[Yes]. prev_in_use=[No]. is large bin. 32 <= fastbin_size <= 128 128 < smallbin_size <= 1024 1024 < largebin_size <= 128*1024 --------------------------------------------- Arena 0: system bytes = 135168 in use bytes = 7088 Total (incl. mmap): system bytes = 135168 in use bytes = 7088 max mmap regions = 1 max mmap bytes = 135168
注意,这里我使用了glibc的malloc信息函数malloc_stats,它能够打印当前的malloc信息,我解析如下:
Arena 0: //Arena ID. There is only one thread. system bytes = 135168 //Dynamic memory obtained by the thread from the OS. in use bytes = 7088 //Dynamic memory used by the thread. Total (incl. mmap): //Total usage of the dynamic memory, that is, the accumulated dynamic memory used by each thread. system bytes = 135168 //Dynamic memory obtained by the process from the OS. in use bytes = 7088 //Dynamic memory used by the process. max mmap regions = 1 //Maximum number of mmap regions max mmap bytes = 135168 //Size of the memory corresponding to mmap regions
这里值得注意的是
1. 为什么in use bytes差8字节,这8字节在哪里?
这里7088 - 3680 = 2408,但实际上 1024+1040+144+128+32+32=2400。多了一个8字节
这是因为最开始的chunk,我们需要一个空的prev_size,这个prev_size的类型是size_t,也就是8。
2. 为什么是135168,系统字节是135168,mmap字节是135168
这里我们知道一个常识是,当内存超过128k时,系统通过mmap系统调用来分配内存,这时候是128*1024=131072
但是管理mmap这么多内存需要一个结构体,这样同时知道分配内存的最小单位是4k,那么4k为4*1024=4096
那么131072+4096=135168。
另一方面,我们在使用glibc程序时,默认程序启动时,glibc的内存管理提供你128k内存供你使用,这里还需要附带1个4k页。然后程序的malloc行为实际上是通过top chunk来进行分配即可。
所以一个程序运行时,默认glibc管理程序会给这个程序提供135168字节的system bytes
作为程序员,我们每天都在和git打交道,无论是自己在编写代码时和同事的协作情况下还是在合并别人的提交的时候,都很容易出现冲突的情况,我们在将整个操作系统进行同步上游的时候,冲突几乎是必定出现,这里介绍一下出现冲突应该怎么应对
当我们敲入
git merge tangfeng
将tangfeng分钟merge到自己分支的时候,如果代码存在不能自动合并的情况下,我们需要自己解决冲突,主要情况如下:
# git status 位于分支 egf/v101-tablet-dev 您的分支与上游分支 'origin/egf/v101-tablet-dev' 一致。 您有尚未合并的路径。 (解决冲突并运行 "git commit") (使用 "git merge --abort" 终止合并) 要提交的变更: 修改: windowsview/qml/AppArea.qml 修改: windowsview/qml/AppPreviewWindow.qml 修改: windowsview/qml/TabletPreviewWindow.qml 修改: windowsview/qml/TabletViewMain.qml 修改: windowsview/qml/multitaskview.qml 修改: windowsview/ukui-window-switch_bo_CN.ts 修改: windowsview/ukui-window-switch_zh_CN.ts 未合并的路径: (使用 "git add <文件>..." 标记解决方案) 双方修改: debian/changelog
我们留意两方面的信息
# git diff debian/changelog diff --cc debian/changelog index 9bb9968,f1c60be..0000000 --- a/debian/changelog +++ b/debian/changelog @@@ -1,14 -1,15 +1,29 @@@ ++<<<<<<< HEAD +ukui-window-switch (3.1.0.1-0k0.1tablet7rk1.egf0.1) v101; urgency=medium + + * No-Change rebuild for ci. + + -- yangquan <yangquan@kylinos.cn> Thu, 14 Mar 2024 15:16:56 +0800 + +ukui-window-switch (3.1.0.1-0k0.1tablet7rk1) v101; urgency=medium + + * Support RK3588 + + -- tangfeng <tangfeng@kylinos.cn> Wed, 09 Aug 2023 12:56:59 +0800 ++======= + ukui-window-switch (3.1.0.1-0k0.1tablet8) v101; urgency=medium + + * BUG: + - 209242 【多任务视图】【TM】改变系统字体,多任务视图未随之变化 + - 209246 【多任务视图】【TM】改变系统字号,多任务视图中字号无变化 + - 209264 【多任务视图】PC模式,传书和计算器在多任务视图中显示为尖角 + - 209266 【多任务视图】PC模式,应用缩略图左右两端显示不完整 + * 需求号: + * 其他改动说明: + * 其他改动影响域:自身 + + -- jiaodian <jiaodian@kylinos.cn> Mon, 15 Jan 2024 09:02:51 +0800 ++>>>>>>> up
第一次看到这些信息先不要害怕,我们接下来介绍
我们首先看下面这个图
这里我标注了1,2,3。也就是说,任意的冲突,我们都可以拆分为1,2,3三个框架
<<<<<<< local branch
=======
>>>>>>> upstream branch
至此,我们知道了冲突的格式,接下来是解决
涉及到冲突的解决,我们需要根据上下文代码来分析, 这里我们举例的是changelog,所以以这里来看
首先,我们知道,我们的版本号是逐步递增的,所以我们不能一味的选中HEAD或者up分支的内容,也就是我们需要都合并
其次,我们合并需要有顺序关系,也就是3.1.0.1-0k0.1tablet7--->3.1.0.1-0k0.1tablet7rk1--->3.1.0.1-0k0.1tablet7rk1.egf0.1--->3.1.0.1-0k0.1tablet8
再者,我们的changelog有明确的命名规范,3.1.0.1-0k0.1tablet8应该修改成3.1.0.1-0k0.1tablet8rk1.egf0.1
至此我们应该修改如下:
diff --cc debian/changelog index 9bb9968,f1c60be..0000000 --- a/debian/changelog +++ b/debian/changelog @@@ -1,15 -1,16 +1,28 @@@ -ukui-window-switch (3.1.0.1-0k0.1tablet8) v101; urgency=medium ++ukui-window-switch (3.1.0.1-0k0.1tablet8rk1.egf0.1) v101; urgency=medium + + * BUG: + - 209242 【多任务视图】【TM】改变系统字体,多任务视图未随之变化 + - 209246 【多任务视图】【TM】改变系统字号,多任务视图中字号无变化 + - 209264 【多任务视图】PC模式,传书和计算器在多任务视图中显示为尖角 + - 209266 【多任务视图】PC模式,应用缩略图左右两端显示不完整 + * 需求号: + * 其他改动说明: + * 其他改动影响域:自身 + + -- jiaodian <jiaodian@kylinos.cn> Mon, 15 Jan 2024 09:02:51 +0800 + +ukui-window-switch (3.1.0.1-0k0.1tablet7rk1.egf0.1) v101; urgency=medium + + * No-Change rebuild for ci. + + -- yangquan <yangquan@kylinos.cn> Thu, 14 Mar 2024 15:16:56 +0800 + +ukui-window-switch (3.1.0.1-0k0.1tablet7rk1) v101; urgency=medium + + * Support RK3588 + + -- tangfeng <tangfeng@kylinos.cn> Wed, 09 Aug 2023 12:56:59 +0800 + ukui-window-switch (3.1.0.1-0k0.1tablet7) v101; urgency=medium * BUG:
改好之后,我们通过git add来提交,代表我们解决了冲突
git add debian/changelog
然后我们需要使用git commit来执行合并
git commit
接下来我们先不提交pr,需要本地编译用于此测试验证
dpkg-buildpackage -uc -us
我们知道ukui-window-switch用作系统的多任务窗口的程序,所以我们自测如下:
scp ../ukui-kwin-effects_3.1.0.1-0k0.1tablet8rk1.egf0.1_all.deb ../ukui-window-switch_3.1.0.1-0k0.1tablet8rk1.egf0.1_arm64.deb root@172.25.83.91:~
然后机器上安装
dpkg -i ukui-kwin-effects_3.1.0.1-0k0.1tablet8rk1.egf0.1_all.deb ukui-window-switch_3.1.0.1-0k0.1tablet8rk1.egf0.1_arm64.deb
然后重启开始自测
systemctl restart lightdm
在平板模式和桌面模式上都点击多任务,这里不展示每个自测,只展示如下bug的自测:
PC模式,应用缩略图左右两端显示不完整 改变系统字体,多任务视图未随之变化 改变系统字号,多任务视图中字号无变化 传书和计算器在多任务视图中显示为尖角
自测完毕之后,直接提交branch,如下:
git branch -m tangfeng git push origin tangfeng
此时我们登录网页提交对egf/v101-tablet-dev的pr请求后提交ci
待ci完成之后,我们填写集成单,事情即完成。
我们在合入分支的时候,并不是每一笔都能够正常合入,所以我们必须要根据合入的代码进行review和理解,这同样对于代码的提交者和审核者都具备此要求。
但是我们在git merge的时候,还是会出现了大量无法合并的情况,或者我们针对上下文无法进行分析或代码能力不够的前提下,不清楚补丁改了什么的时候,这时候更建议按照一个一个补丁的方式合入,如下:
首先切到上游分支
git checkout up
然后我们得在上游分支上看领先了多少提交
commit cd205b17db39334e2f07a9cc474822015b705ddd (HEAD -> up, tag: build/3.1.0.1-0k0.1tablet8, origin_upstream/yhkylin/v101-tablet) Author: jiaodian <jiaodian@kylinos.cn> Date: Mon Jan 15 09:03:44 2024 +0800 [Chore]: xctablet changelog 3.1.0.1-0k0.1tablet8 commit 3c993741e0fd5edcb5bf939fd99c727e03611abd Merge: 954a1c6 ad3c421 Author: 庞毅 <pangyi@kylinos.cn> Date: Wed Jan 10 02:36:08 2024 +0000 Merge branch 'yhkylin/v101-tablet-font' into 'yhkylin/v101-tablet' 平板模式增加适配字体字号变化的功能 See merge request kylinos-src/ukui-window-switch!131 commit 954a1c671a355ac6335274b9355e59fac081fb83 Merge: 75404f5 deaf58a Author: 庞毅 <pangyi@kylinos.cn> Date: Wed Jan 10 02:35:10 2024 +0000 Merge branch 'yhkylin/v101-tablet' into 'yhkylin/v101-tablet' 同步主线缩略图的大小以及圆角改动 See merge request kylinos-src/ukui-window-switch!130 commit ad3c421e7e3dd74030cd755a72e39d5e6118e3f3 Author: jiaodian <jiaodian@kylinos.cn> Date: Wed Jan 10 09:52:18 2024 +0800 平板模式增加适配字体字号变化的功能 commit deaf58a71bf71367490a5550f1ee2d3b97416c1f Author: pang_yi <pangyi@kylinos.cn> Date: Fri Nov 17 15:25:17 2023 +0800 Fix: bug 209264 传书和计算器缩略图不是圆角 commit 9b3deeb06f75dd22b862fda2f3b2d4545968b92f Author: jiaodian <jiaodian@kylinos.cn> Date: Wed Jul 5 14:31:04 2023 +0800 修改缩略图大小 commit 75404f571fd82fe35085395804289036a9d39bed (tag: build/3.1.0.1-0k0.1tablet7, origin/yhkylin/v101-tablet)
这里我们留意最后一行:
commit 75404f571fd82fe35085395804289036a9d39bed (tag: build/3.1.0.1-0k0.1tablet7, origin/yhkylin/v101-tablet)
可以知道,我们的提交领先到这里了,此时我们生成patch,如下:
git format-patch 75404f571fd82fe35085395804289036a9d39bed
此时我们会提供HEAD到75404f571fd82fe35085395804289036a9d39bed的所有patch文件,我们逐一合入:
patch -p1 < 0001-xxx.patch patch -p1 < 0002-xxx.patch patch -p1 < 0003-xxx.patch patch -p1 < 0004-xxx.patch
此时我们可以把之前的git merge的冲突拆解为这四笔提交的冲突,相当于将问题一分为四。
如果我们发现上游更新太多了,理解代码太困难了,我们可以先合上游,再提交自己的补丁,如下:
此时我们在tangfeng分支 查看日志如下:
commit f5eb14a05d9f1bdaa8527317d8c6d2b6c1868430 (tag: build/3.1.0.1-0k0.1tablet7rk1, origin/3588-tablet) Author: Your Name <you@example.com> Date: Wed Aug 9 12:57:51 2023 +0800 支持RK3588平台 commit 381dee6e9d9e417404be791f041daf62ab4bf884 Merge: 7cf2d58 75404f5 Author: Your Name <you@example.com> Date: Wed Aug 9 10:53:51 2023 +0800 Merge branch 'tablet' into 3588 commit 75404f571fd82fe35085395804289036a9d39bed (tag: build/3.1.0.1-0k0.1tablet7, origin/yhkylin/v101-tablet)
这里可以看到从origin/yhkylin/v101-tablet到build/3.1.0.1-0k0.1tablet7rk1我们总共两笔提交,其中一笔是merge的日志。也就是一笔提交,我们可以将其生成补丁,如下:
git format-patch 75404f571fd82fe35085395804289036a9d39bed
此时我们存在一个patch,如下:
0001-xxx.patch
然后我们将代码直接reset/revert,如下:
如果是reset,则:
git reset 75404f571fd82fe35085395804289036a9d39bed git checkout .
如果是revert,则
git revert f5eb14a05d9f1bdaa8527317d8c6d2b6c1868430
至此,我们回到了和主线分支完全一致的状态,然后我们合入主线
git merge up
这里因为没有我们的任何一笔改动,所以merge一定是成功的。
然后我们合入自己的补丁,如下
patch -p1 < 0001-xxx.patch
此时我们的补丁会产生冲突,我们解决自己的冲突即可。
在解决好冲突之后,我们需要rebase来解决问题。如下:
git rebase git push -f
值得注意的是,我们在敲git rebase的时候请与管理员先沟通,再git push -f强推。
本文描述了我们通常情况下在合入补丁时的解决方法,我们提供了三种思路,处理问题的优先级按照描述的优先级
我们在做openharmony的时候,关于lfs推送的时候,经常出现错误,本文提供解决办法
git push -u origin --all Locking support detected on remote "origin". Consider enabling it with: $ git config lfs.https://gitlab2.kylin.com/sh-product-Embedded/openharmony/device_soc_rockchip.git/info/lfs.locksverify true Locking support detected on remote "origin". Consider enabling it with: $ git config lfs.https://gitlab2.kylin.com/sh-product-Embedded/openharmony/device_soc_rockchip.git/info/lfs.locksverify true LFS upload failed:cts: 50% (4/8), 172 MB | 0 B/s (missing) rk3568/hardware/gpu/lib/libmali-bifrost-g52-g2p0-ohos.so (ad12817eb634607e114fa6fcf2b4fc18244b20172664f9f374ed1ef844df7cda) (missing) rk3568/hardware/gpu/lib64/libmali-bifrost-g52-g2p0-ohos.so (e7902e8a59cec7211f3ca2dcc53cb8a1e94b8328023025d7fcc2fb2dacf07e41) hint: Your push was rejected due to missing or corrupt local objects. hint: You can disable this check with: 'git config lfs.allowincompletepush true' error: 无法推送一些引用到 'git@gitlab2.kylin.com:sh-product-Embedded/openharmony/device_soc_rockchip.git'
此原因是推送git的时候,lfs 的object不完善,需要单独拉一下
git lfs fetch --all origin OpenHarmony-4.0-Release
这样再通过git push的仓库的lfs是完善的
git push -u origin --all
ftrace是内核的一套框架,它将内核多种trace整合在一起,之前我们提到的tracepoint,trace event,kprobe等等都是ftrace base的。ftrace 提供了一个tracefs基本框架。本文介绍ftrace的基本使用 一、ftrace 框架 为了了解ftrace框架,我们需要把其他几个trace都介绍进来,主要如下所示:
如上图所示
如果关系社区文档的,可以查看如下:
https://lwn.net/Articles/370423/
这样我们就对整个ftrace框架有了一个比较清晰的了解了,接下来介绍ftrace的使用
对于function trace,我们需要关注如下几个文件,目录是在:/sys/kernel/debug/tracing
set_ftrace_filter set_ftrace_notrace
这里以usbhid鼠标事件为例,开展一个示例。
我们知道,usb事件通过urb提交数据,对于usbhid而言,提交数据的函数是usb_submit_urb,我们此时跟踪usb_submit_urb函数,如下:
cd /sys/kernel/debug/tracing echo 0 > tracing_on echo usb_submit_urb > set_ftrace_filter echo function > current_tracer echo 1 > tracing_on cat trace_pipe
此时我们晃动鼠标,可以知道trace信息如下:
<idle>-0 [000] .Ns. 802.924876: usb_submit_urb <-hid_irq_in <idle>-0 [000] .Ns. 802.928922: usb_submit_urb <-hid_irq_in <idle>-0 [000] .Ns. 802.932923: usb_submit_urb <-hid_irq_in <idle>-0 [000] .Ns. 802.936922: usb_submit_urb <-hid_irq_in <idle>-0 [000] .Ns. 802.940922: usb_submit_urb <-hid_irq_in <idle>-0 [000] .Ns. 802.944876: usb_submit_urb <-hid_irq_in
我们能够准确的抓到usb_submit_urb事件信息,其是hid_irq_in调用。但是缺点是我并不知道是如何传入的,所以我们还需要开一个特性,如下:
echo 1 > options/func_stack_trace
此时我们再晃动鼠标,可以看到信息如下:
<idle>-0 [000] .Ns. 879.322927: usb_submit_urb <-hid_irq_in <idle>-0 [000] .Ns. 879.322929: <stack trace> => usb_submit_urb => hid_irq_in => __usb_hcd_giveback_urb => usb_giveback_urb_bh => tasklet_action_common.isra.0 => tasklet_hi_action => __do_softirq => irq_exit => __handle_domain_irq => gic_handle_irq => el1_irq => cpuidle_enter_state => cpuidle_enter => call_cpuidle => do_idle => cpu_startup_entry => rest_init => arch_call_rest_init => start_kernel
这里我们就清楚的知道,系统idle进程在等待gic中断,也就是我鼠标晃动,然后在gic_handle_irq中根据注册的中断调用回调。我们关注hid_irq_in是谁注册的就知道整个代码调用过程了。
如果不用,则关闭即可。
echo 0 > tracing_on echo nop > current_tracer
function graph trace改进了function trace,可以将整个函数调用堆栈打印出来,并且按照括号给折叠查看,对于排查代码框架问题上比trace更好用
对于function graph trace,主要关注如下文件:
set_graph_function set_graph_notrace
这里还是以usbhid为例,开展示例:
cd /sys/kernel/debug/tracing echo 0 > tracing_on echo function_graph > current_tracer echo usb_submit_urb > set_graph_function echo 0 > max_graph_depth
晃动鼠标
echo 1 > tracing_on cp /sys/kernel/debug/tracing/trace ~/ echo 0 > tracing_on
我们可以拿到如下日志
# tracer: function_graph # # CPU DURATION FUNCTION CALLS # | | | | | | | ------------------------------------------ 0) ukui-po-2485 => <idle>-0 ------------------------------------------ 0) | usb_submit_urb() { 0) | usb_hcd_submit_urb() { 0) | usb_get_urb() { 0) 0.875 us | usb_get_urb.part.0(); 0) 2.625 us | } 0) 0.875 us | usb_hcd_map_urb_for_dma(); 0) | ehci_urb_enqueue() { 0) | qh_urb_transaction() { 0) | ehci_qtd_alloc() { 0) | dma_pool_alloc() { 0) | _raw_spin_lock_irqsave() { 0) 0.583 us | do_raw_spin_lock(); 0) 1.750 us | } 0) | _raw_spin_unlock_irqrestore() { 0) 0.584 us | do_raw_spin_unlock(); 0) 1.750 us | } 0) 5.541 us | } 0) 6.709 us | } 0) 0.583 us | qtd_fill.isra.0(); 0) 9.625 us | } 0) | _raw_spin_lock_irqsave() { 0) 0.583 us | do_raw_spin_lock(); 0) 1.750 us | } 0) | usb_hcd_link_urb_to_ep() { 0) | _raw_spin_lock() { 0) 0.584 us | do_raw_spin_lock(); 0) 1.458 us | } 0) | _raw_spin_unlock() { 0) 0.583 us | do_raw_spin_unlock(); 0) 1.459 us | } 0) 6.416 us | } 0) 0.875 us | qh_append_tds(); 0) 1.750 us | qh_append_tds(); 0) | _raw_spin_unlock_irqrestore() { 0) 0.583 us | do_raw_spin_unlock(); 0) 1.750 us | } 0) + 26.542 us | } 0) + 32.375 us | } 0) + 37.916 us | }
我们可以看到usb_submit_urb的调用流程了,便于分析解决usb_submit_urb函数内部存在的问题。
这里,我们发现能够直接追到usb_submit_urb后面所有的调用和运行的时间了,但是这些括号匹配起来很麻烦,所以我们应该打开如下:
echo 1 > options/funcgraph-tail
此时日志不一样了,如下:
0) | usb_submit_urb() { 0) | usb_hcd_submit_urb() { 0) | usb_get_urb() { 0) 0.583 us | usb_get_urb.part.0(); 0) 1.750 us | } /* usb_get_urb */ 0) 0.583 us | usb_hcd_map_urb_for_dma(); 0) | ehci_urb_enqueue() { 0) | qh_urb_transaction() { 0) | ehci_qtd_alloc() { 0) | dma_pool_alloc() { 0) | _raw_spin_lock_irqsave() { 0) 0.583 us | do_raw_spin_lock(); 0) 1.458 us | } /* _raw_spin_lock_irqsave */ 0) | _raw_spin_unlock_irqrestore() { 0) 0.583 us | do_raw_spin_unlock(); 0) 1.750 us | } /* _raw_spin_unlock_irqrestore */ 0) 4.666 us | } /* dma_pool_alloc */ 0) 5.834 us | } /* ehci_qtd_alloc */ 0) 0.583 us | qtd_fill.isra.0(); 0) 8.458 us | } /* qh_urb_transaction */ 0) | _raw_spin_lock_irqsave() { 0) 0.583 us | do_raw_spin_lock(); 0) 1.750 us | } /* _raw_spin_lock_irqsave */ 0) | usb_hcd_link_urb_to_ep() { 0) | _raw_spin_lock() { 0) 0.583 us | do_raw_spin_lock(); 0) 1.750 us | } /* _raw_spin_lock */ 0) | _raw_spin_unlock() { 0) 0.292 us | do_raw_spin_unlock(); 0) 2.625 us | } /* _raw_spin_unlock */ 0) 5.834 us | } /* usb_hcd_link_urb_to_ep */ 0) 0.583 us | qh_append_tds(); 0) 1.750 us | qh_append_tds(); 0) | _raw_spin_unlock_irqrestore() { 0) 0.583 us | do_raw_spin_unlock(); 0) 1.458 us | } /* _raw_spin_unlock_irqrestore */ 0) + 23.625 us | } /* ehci_urb_enqueue */ 0) + 28.292 us | } /* usb_hcd_submit_urb */
可以发现括号后面带注释了
但是这还不满足,我想要折叠function graph的信息。
内核有一个vim配置脚本,如下:
scp Documentation/trace/function-graph-fold.vim root@172.25.xx.xx:~
我们用vim打开trace文件的时候执行这个脚本如下:
vim -S function-graph-fold.vim trace
此时日志长这样了:
# tracer: function_graph # # CPU DURATION FUNCTION CALLS # | | | | | | | 6) $ 115370075 us | } /* schedule */ + 0) | usb_submit_urb() {-------------------------------------------------------------------------------------------------------------------------------------
我们在折叠的地方按下L即可展开。
ftrace是一个黑盒测试调试的很好的工具,基本上所有调试过内核的人都知道使用,本文作为普及的目的说了一下ftrace的使用。