0%

此篇文章是基于高通 ODM BSP 开发做的一个简单总结,起初是用来对新人进行培训的。

我觉得学习内核驱动时,最开始只需要 ‘Know what, not know how ’。 不用去探究细节,只需要知道整体的框架,知道有哪些需要我们重视的内容即可。

何为 Linux 内核开发?

首先,初步认识下 Linux kernel

linux_intro

  • Linux 内核的框架如上图。
  • 设备子系统负责和硬件打交道。
  • 大部分工作集中在设备子系统部分。
Read more »

本文的动态图皆来自于莉迪亚·哈莉(Lydia Hallie) 的文章 CS Visualized: Useful Git Commands

VCS 的发展历史

首先,我们来聊聊 VCS, Version Control System, 即版本控制系统的发展历史。

Manual VCS

最初的时候,大家都是通过复制目录来进行版本管理,如下图:

manual vcs

这样做的缺点显而易见:

  • 难以维护
  • 难以回溯
Read more »

What is pstore?

pstore, persistent storage, 是一个存储内核日志或者内核 panic 的文件系统,内核会把相关信息存储在一个不能被其他用户重写的指定 RAM 区域,下一次启动时,这个区域会被挂载到 /pstore,一般在 /sys/fs/pstore, 这样我们就可以访问这些数据了。

pstore 在内核中的开关是 CONFIG_PSTORE,pstore 提供的是一套可扩展的机制,提供如下类型:

  • PSTORE_TYPE_DMESG, 表示内核日志
  • PSTORE_TYPE_MCE, 表示硬件错误
  • PSTORE_TYPE_CONSOLE, 表示控制台输出,所有内核信息。
  • PSTORE_TYPE_FTRACE, 表示函数调用序列, ftrace 信息。

ramoops 指的是采用 ram 保存 oops 信息的一个功能,这个功能从 3.10.40 开始采用 pstore 机制来实现,内核中的开关控制:

  • PSTORE_PMSG,用户空间信息,/dev/pmsg0,pmsg-ramoops-
  • PSTORE_CONSOLE,控制台输出,所有内核信息,console-ramoops-
  • PSTORE_FTRACE,函数调用序列, ftrace 信息。
  • PSTORE_RAM, panic/oops 信息

How to config?

Read more »

How does the repo of android source code work ?

.repo

通常情况下, Android 的 .repo 里面有如下内容:

1
2
$ ls .repo
manifests manifests.git manifest.xml project.list project-objects projects repo

manifests

manifests 路径是项目 manifest 仓的 git checkout,其中的 .gitmanifest.git 的软链接,追踪 repo init --manifest-branch 指定的分支。

1
2
3
4
5
6
7
.repo$ ls manifests/.git/
config HEAD index logs ORIG_HEAD refs shallow
description hooks info objects packed-refs rr-cache svn

.repo$ ls manifests.git/
branches description HEAD info objects refs svn
config FETCH_HEAD hooks logs packed-refs rr-cache

不管远程分支名字是什么,manifests 的本地分支命名为 default。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.repo$ cat manifests/.git/HEAD 
ref: refs/heads/default

.repo$ cat manifests.git/config
# cat manifests/.git/config
[core]
repositoryformatversion = 0
filemode = true
[filter "lfs"]
smudge = git-lfs smudge --skip -- %f
[remote "origin"]
url = https://<url>/platform/manifest.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "default"]
remote = origin
merge = refs/heads/<remote_branch_name>

manifests.git

manifests.git 是当前项目 manifest 仓的一个没有工作空间的 checkout,即只 checkout .git ,追踪repo init --manifest-url 指定的 Git 仓。不能手动修改这部分,如果需要修改的话,可重新运行 repo init 来更新设置。

.repo_config.json

缓存 manifests.git/config,用来提升 repo 的速度。

manifest.xml

repo 使用的 manifest , 此文件由 repo init --manifest-name 指定链接到 manifests 中的哪一个文件,如下:

1
manifest.xml -> manifests/<manifest-name>.xml # 指向用户希望用来同步源码的 manifest
Read more »

俗话说“雨过留痕,雁过留声”,之前因为工作需要折腾了小几个月的性能 BUG,还是得留下一点东西,这是第一篇:Android 性能调试手册,这篇文章简单聊聊工作中应该怎么进行性能分析。因为没有深入研究 Performance 相关内容,所以保留出错的权利。

0. 写在开头

在我司处理 Performance 问题时,大多数情况不会像顶级大厂那样优化每一帧,尽量榨干每一个硬件的性能。因为没有前人提供经验,全是自己总结的,如果存在有失偏颇的地方,你也只能看着。我理解的主要处理方式如下:

  • 第一种,推不解。

    • gaps 小, 个人经验是 10% 以内即可以尝试推不解,譬如:问题机 Chrome 启动时间为 800 ms, 对比机为 750 ms。
    • 分析出时间消耗,列出与对比机的对比, 详细阐述差分部分,一般来说大部分差分是原生代码引起,或者 gaps 很小。
  • 第二种嘛,当然就是想办法解决或优化了。

1. 怎么开始?

针对任何性能问题,我觉得第一步都先需要做如下三个确认:

  1. 确认问题现象,最好自己复现一次。
  2. 确认有没有大量 crash 发生。
  3. 查看 kernel footprint(config), 确认是否使用 perf config: msmxxx-perf_defconfig。
    Read more »

“雨过留痕,雁过留声”的第二篇:APP 启动,触摸事件和 UI 绘制的简单分析示例,此文通过 systrace 分析一个示例 APP 的启动、触摸事件和 UI 绘制的流程和时间消耗。本文的示例 APP (SimpleApplication.apk)只有一个简单的按钮, 点击按钮时会改变屏幕的颜色。同样因为没有深入研究 Performance 相关内容,所以保留出错的权利。

如果对第一篇感兴趣,请查看: Android 性能调试手册.

0. 写在开头

我一开始看到 systrace 文件时,是一脸懵逼的,所以在开始正文之前先简单说一下 systrace 文件中的一些基本信息,如下:

  • Frames: 一个圆圈代表一帧。
    • 绿色:正常;
    • 黄色、红色: 异常,如卡顿、掉帧(Jank) 等,可能是它的渲染时间超过了 16.67ms(60fps)。
    • 点击圆圈可查看详细信息
  • Alerts: 右侧标签,跟踪记录中出现的问题以及这些问题导致出现卡顿的频率
  • system_server iq: 第一帧的触发
  • gfx3d_clk : GPU 频率
  • iq in systemsever : 触发中断
  • bindApplication, activityStart ...: 表示冷启动, 热启动不会有这些信息。
  • surfaceflinger->UI Thread->HIDL::IComposerClient:setPowerMode_2_2:client: 代表 LCD 上电时间

    一般使用 Chrome 打开 systrace.html, 右上角的 也可以提供一些基本的帮助

1. 获取 systrace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
a. python systrace.py gfx input view sched am wm dalvik freq idle power video app -b 40960 -t 10 -o traceout.html

Explaination of these categories:
gfx - Graphics
input - Input
view - View System
wm - Window Manager
am - Activity Manager
hal - Hardware Modules
res - Resource Loading
dalvik - Dalvik VM
power - Power Management
sched - CPU Scheduling
freq - CPU Frequency
idle - CPU Idle

b. Motion: Click icon of SimpleApplication to open it, click first time to change background as white, click sencond time to change background as black.

2. 找到点击事件

查看 system_serveriq 去定位点击事件发生的时间,如下:

image

查看 InputResponse 确认点击事件,如下:

image

3. 查看 UI thread 和 Frames

粗略看一下 Frames,发现有一个红色的 frame,红色表示 jank, 即卡顿。

image

上诉红点也就是代表帧率少于了 60 fps,我们需要去点击红色的圆点查看详细信息,并查看下 UI thread,看看是否有无用的耗时或者阻塞发生。此案例中有 11 ms 左右的 sleep,如下:

image

4. 查看线程状态

4.1 Orange: Uninterruptible sleep, I/O Block

此状态表示线程正在等待硬盘 I/O 操作完成,如果有太多的橙色阻塞状态,通常存在低内存的问题。此案例中阻塞状态很短,判断为正常状态,如下:

image

4.2 Blue: runnable

表明线程处于可运行状态,等待 CPU 调度。如果线程处于可运行状态时间太长,通常 CPU 忙于调度,需要查看这些时间 CPU 忙于哪些任务。比较常见的问题场景如下:

  • 后台任务太多。
  • CPU 被限频。
  • 任务运行于特定的 cpuset,而此 CPU 已经满载。

此案例中处于可运行状态的时间很短,如下:

image

4.3 Green: running

接下来查看下线程的运行的时间,如果耗时异常,通常需要注意如下场景:

  • 是否被限制频率。
  • 线程跑在大核上还是小核上。
  • 是否频繁切换线程状态。
  • 此线程是否运行在错误的核上面。

此案例中线程运行在大核上,即频率最高的 CPU7,亦无其他异常,如下:
image

## 4.4 White: Sleeping

此状态表示线程无事可做,处于休眠状态,一个概率比较大的情况是被 mutex 阻塞。

image

4.5 Summary

如上所示,我们可以看到大部分时间是消耗在运行状态,且没有频繁切换状态,所以这部分问题不是太大,当然如果想要追求更佳的性能,我们可以针对上面说的场景做更深入的调查。

5. 启动时间

从系统角度来看,在 Activity 完成 onCreate/onStart/onResume阶段后,ViewRootImpl 将调用两次 performTraversals 去初始化 Egl、measure、layout、draw等,最后完成界面显示。

个人认为很难在 systrace 中获得准确的 APP 启动时间,但是我们可以在 activityResume 之后选择一个点来估算相对准确的时间。如下:

image

Launcher 调用 startingWindow 去等待第一帧的绘制,如下:

image

在如下指定位置,第一帧绘制已经完成。

image

在 SystemSever 中查看绘制流程。

image

6. systrace 中的 input

InputReader 获取 input 事件,然后移交给 InputDispatcher. InputDispatcher 再将输入事件传递给对应的 App,然后请求 Vsync 去绘制第一帧。

  • InputReader 负责从 EventHub 读取 Input 事件,然后将其移交给 InputDispatcher 进行事件分发。
  • InputDispatcher 打包并分发事件。
  • OutboundQueue 存有将分派到相应 AppConnection 的事件
  • WaitQueue 记录已分派到 AppConnection,但 App 仍在处理尚未返回处理成功的事件。 如果主线程 freezed 而无法处理输入事件,则 WaitQueue 的值将递增。
  • PendingInputEventQueue 记录应用程序需要处理的 Input 事件。
  • deliveryInputEvent 标识被输入事件唤醒的 App UI 线程。

6.1 Input response

image

6.2 OutboundQueue and WaitQueue

image

6.3 Native threads which Reads and dispatchs input event

image

6.4 PendingInputEventQueue

image
image

7. 查看 CPU 信息

主要检查 CPU 使用率、C-stage、时钟频率和时钟频率的限制,以及每个核正在跑什么应用。SimpleApplication 主要运行在大核 cpu7 上,有时运行在中核上, 都是最大频率。所以 CPU 部分没有什么问题。

image

8. 第一次点击事件

前面主要是通过全局视图和启动视图来分析 systrace,下面将分析单击事件。但是我将跳过与前面类似的分析步骤, 只重点查看一些可能会影响 UI 切换速度的差异点。

8.1 CPU 情况

SimpleApplication 在现阶段也主要运行在大核 cpu7 上且以最大频率运行,但是部分时间运行在限频状态下的大核和中核,如果需要对其进行优化,这是需要考虑的一点。

image

8.2 UI thread

第一次单击时睡眠太久,也许这是一个可以优化的点。

image

9. 结论

9.1 启动阶段

  • 存在卡顿,可能需要查看下是否存在异常的耗时或阻塞的代码。
  • UI 线程的状态还不错,如果要提高性能,可以尝试检查下内存状态和后台任务。

image

9.2 第一次点击事件

  • CPU 频率有在某些阶段被限制,我们可以尝试对其进行优化。
  • 第一次点击时睡眠太久,也许这是一个可以优化的地方。 为了对其进行优化,我们需要检查 SimpleApplication 的代码,是否被互斥锁阻塞,等等。

image

之前折腾局域网搭建 Gitbook,并写了一篇简易教程:Gitbook + Jenkins + Gitlab 搭建内网自动构建的 Gitbook。最近兴趣使然又用 docker 搭建了一套方便部署的内网 Gitbook 镜像,因此也总结一篇简易教程如下。

Install Docker

1
sudo apt install docker

Gitbook

Gitbook Image

下载 Gitbook Docker 镜像,我选择了 billryan/gitbook 镜像

1
docker pull billryan/gitbook

mkdir gitbook 创建一个 gitbook 路径,我们也可以将启动的镜像存储为另一个镜像:

1
2
3
4
5
6
7
8
# init
docker run --rm -v "$PWD/gitbook:/gitbook" -p 4000:4000 billryan/gitbook gitbook init
# serve
docker run --rm -v "$PWD/gitbook:/gitbook" -p 4000:4000 billryan/gitbook gitbook serve


docker ps # Get CONTAINER ID of gitbook
docker commit <CONTAINER ID> andylee/gitbook:1.0
Read more »

detached HEAD is a common situation, sometimes useful, sometimes dangerous. It doesn’t point to any branches, so it will be cleaned by git.

The current commit history is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ git log --oneline --all --graph
* 5ea3cec (HEAD -> master) Modify README.md of src
* 2b6e826 Same file, same blob
* 1ff08f2 Modify README.md.
* 8c19a38 Add Copyright notice.
* 318c11a Copy css to lib.
| * 1134f9e (dev) Make graph more readability
| * 71c40d3 Modify README.md in dev branch.
|/
* ce4297f Add image.
| * 2cb23ac (dev-1.0) README for dev-1.0 branch.
|/
* 6fc4b44 (tag: kikoff_tag) Copy doc README.md
* 726c6c0 Add source README.md
* c8ff9c5 Add README
Read more »