From 5e5663a1af29eba5b25ee74d89fe9598db012112 Mon Sep 17 00:00:00 2001 From: wangjiexun Date: Sun, 17 Sep 2023 21:23:53 +0800 Subject: [PATCH 1/5] add article 20230917-licheepi4a-rt-test.md --- articles/20230917-licheepi4a-rt-test.md | 202 ++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100755 articles/20230917-licheepi4a-rt-test.md diff --git a/articles/20230917-licheepi4a-rt-test.md b/articles/20230917-licheepi4a-rt-test.md new file mode 100755 index 0000000..bcc8bb5 --- /dev/null +++ b/articles/20230917-licheepi4a-rt-test.md @@ -0,0 +1,202 @@ +> Author: 王杰迅
+> Date: 2023/09/17
+> Revisor: falcon
+> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
+> Sponsor: PLCT Lab, ISCAS + +# LicheePi 4A 实时性测试实践 + +## 前言 + +在 [之前的文章][1] 中介绍了 LicheePi 4A 开发板构建并运行 Linux v6.5-rc1 的过程,当时实现的效果为:内核可以成功启动并进入 initramfs 命令行界面。 + +在本文中,将介绍为 LicheePi 4A 开发板添加 eMMC 支持的过程,使得内核可以从 eMMC 上的 rootfs 启动,同时将内核版本更新到 v6.5,打入对应的 PREEMPT_RT 补丁。 + +除此之外,本文还将介绍使用 cyclictest 和 ftrace 进行延迟追踪的小技巧。 + +## 软件版本 + +| Software | Version | +|------------|------------------------------------------| +| Linux | 6.5 | +| U-Boot | 2020.01 | +| OpenSBI | thead-opensbi | +| Buildroot | 2023.02.2 | + +## 添加 eMMC 支持 + +LicheePi 4A 开发板提供了 eMMC 作为外部存储, eMMC 是 Flash 的一种,在嵌入式系统中使用广泛。 + +官方 Linux 内核从 v6.5 版本开始添加了对 LicheePi 4A 开发板的设备树支持,具体见 `arch/riscv/boot/dts/thead` 文件夹下的各文件。但其中的设备树目前不够完善,主要的外设只实现了串口,没有办法使用外部存储。因此想要使用 LicheePi 4A 的 eMMC,必须借助社区中其他开发者提供的补丁。 + +[Drew Fustini 的补丁][2] 为开发板 Beaglev-Ahead 添加了 eMMC 支持。由于 Beaglev-Ahead 和 LicheePi 4A 都是使用 TH1520 作为主控芯片,因此该补丁也可适用于 LicheePi 4A。 + +该补丁添加了对 eMMC 的设备树支持,并修改了驱动文件 `drivers/mmc/host/sdhci-of-dwcmshc.c`,在开启内核配置项 `CONFIG_MMC_SDHCI_OF_DWCMSHC=y` 之后,可以实现对 eMMC 外设的基本读写。但目前该驱动还没有支持 DMA,效率较低,仍在迭代开发中。 + +将 eMMC 驱动和设备树替换完毕后,仍出现了多个小问题,最终通过选择合适的 OpenSBI,才实现了稳定地使用 eMMC 进行读写。 + +### load access fault + +最初时,由于使用的 OpenSBI 版本过低,没有支持设备树中的 "thead,c900-clint" ,在进行初始化时会出现如下报错: + +``` +[ 0.000000] Oops - load access fault [#1] +... +[ 0.000000] epc : __plic_toggle+0x6a/0x72 +[ 0.000000] ra : __plic_init.constprop.0+0x31e/0x4ac +``` + +更换为较新版本的 OpenSBI(v1.2 及以上)后,报错消失,可以正常启动。 + +### illegal instruction + +当尝试给 eMMC 施加压力测试时,如使用如下命令: + +``` +$ while true; do /bin/dd if=/dev/zero of=bigfile bs=1024000 count=1024; done & +``` + +会出现如下报错导致系统崩溃: + +``` +sbi_trap_error: hart1: illegal instruction handler failed (error -2) +``` + +经 Jisheng Zhang 老师提醒,使用 [最新的 thead-opensbi][3] 后,eMMC 在压力测试下也可以稳定使用,不再报错。猜测该报错产生的原因为:TH1520 芯片的部分指令没有被官方 OpenSBI 实现。 + +总之,目前应使用 [最新的 thead-opensbi][3],以保证系统正常运行。 + +### rootfs + +当 eMMC 可以正常使用后,就可以不再使用 initramfs。将 rootfs 烧写到 eMMC 后,系统就可以从 eMMC 的 rootfs 启动。使用 Buildroot 的 menuconfig,选择构建的 rootfs 文件系统类型为 ext4: + +``` +Filesystem images ---> + [*] ext2/3/4 root filesystem + ext2/3/4 variant (ext4) ---> + (rootfs) filesystem label + (60M) exact size +``` + +LicheePi 4A 提供的烧录工具最大可以将 4GB 的 rootfs 烧录到 eMMC 中,但实际的 rootfs 可能并没有那么大,在制作 rootfs 时可以选择较小的大小,如 60MB。在系统启动后,可以使用 resize2fs 命令对 rootfs 进行扩容: + +``` +$ resize2fs /dev/mmcblk0p3 +``` + +使用该命令会自动将 rootfs 扩容,将 eMMC 的未使用存储空间全部并入其中。 + +## 编译 PREEMPT_RT v6.5 内核 + +为了提高系统实时性,首先打入和 Linux 内核版本对应的 [官方 PREEMPT_RT 补丁][4]。同时,由于 LicheePi 4A 开发板基于 RISC-V 架构,因此还需要打入 [针对 RISC-V 架构的 PREEMPT_RT 补丁][5]。 + +### 解决 redefinition 错误 + +在将 Linux 内核更新到 v6.5,打入 PREEMPT_RT 补丁并配置抢占模式为 PREEMPT_RT 后,尝试编译时出现报错: + +``` +arch/riscv/kernel/irq.c:64:6: error: redefinition of 'do_softirq_own_stack' + 64 | void do_softirq_own_stack(void) + | ^~~~~~~~~~~~~~~~~~~~ +In file included from ./arch/riscv/include/generated/asm/softirq_stack.h:1, + from arch/riscv/kernel/irq.c:15: +./include/asm-generic/softirq_stack.h:8:20: note: previous definition of 'do_softirq_own_stack' was here + 8 | static inline void do_softirq_own_stack(void) + | ^~~~~~~~~~~~~~~~~~~~ +``` + +经过查看后发现,在 `arch/riscv/kernel/irq.c` 和 `include/asm-generic/softirq_stack.h` 文件中出现了对 `do_softirq_own_stack` 函数的重复定义。 + +该错误与以下两个配置项有关: + +``` +CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK +CONFIG_SOFTIRQ_ON_OWN_STACK +``` + +正常的逻辑是,如果内核配置 `CONFIG_SOFTIRQ_ON_OWN_STACK=y`,则该函数由 `include/asm-generic/softirq_stack.h` 文件负责实现。 + +如果内核配置 `CONFIG_SOFTIRQ_ON_OWN_STACK=n`,则该函数在 `include/asm-generic/softirq_stack.h` 文件中只负责声明,而由特定架构负责具体实现,如 RISC-V 架构就在 `arch/riscv/kernel/irq.c` 文件中实现。 + +但在 `arch/riscv/kernel/irq.c` 文件中,错把实现 `do_softirq_own_stack` 函数的条件 `SOFTIRQ_ON_OWN_STACK` 写成了 `HAVE_SOFTIRQ_ON_OWN_STACK` 选项,当内核配置项如下时: + +``` +CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y +CONFIG_SOFTIRQ_ON_OWN_STACK=n +``` + +两个文件都会实现 `do_softirq_own_stack` 函数,出现 redefinition 错误。 + +值得一提的是,当没有开启 PREEMPT_RT 时,开启 `HAVE_SOFTIRQ_ON_OWN_STACK` 时默认会开启 `SOFTIRQ_ON_OWN_STACK`,因此不会暴露出错误,只有当开启 PREEMPT_RT 时,才会导致编译失败。 + +目前,该补丁已发送至 [邮件列表][6]。 + +## 延迟追踪技巧 + +在优化系统实时性能时,首先需要分析产生最大延迟的原因。常用的延迟测试及追踪工具为 cyclictest 和 ftrace。这两个软件的基本用法,可以参考泰晓科技的往期直播分享 [RISC-V 实时抢占优化实践][7] 及 [对应 PPT][8]。 + +实际测试时,容易遇到的一个问题是:测试得到的最大延迟并不是 cyclictest 产生的,这对优化实时性能没有任何帮助。例如: + +``` +# wakeup_rt latency trace v1.1.5 on 6.5.0-rt6-r1208-00003-g999d221864bf-dirty +# -------------------------------------------------------------------- +# latency: 12086 us, #6/6, CPU#0 | (M:preempt_rt VP:0, KP:0, SP:0 HP:0 #P:4) +# ----------------- +# | task: irq/12-ttyS0-74 (uid:0 nice:0 policy:1 rt_prio:50) +# ----------------- +…… +``` + +而实际希望得到的最大延迟和调用栈应该是由 cyclictest 产生的,例如: + +``` +# wakeup_rt latency trace v1.1.5 on 6.5.0-rt6-r1208-00003-g999d221864bf-dirty +# -------------------------------------------------------------------- +# latency: 879 us, #6/6, CPU#2 | (M:preempt_rt VP:0, KP:0, SP:0 HP:0 #P:4) +# ----------------- +# | task: cyclictest-212 (uid:0 nice:0 policy:1 rt_prio:99) +# ----------------- +…… +``` + +如果进行了较长时间的测试之后,查看 ftrace 的结果发现没有任何帮助,难免会令人大失所望。因此需要使用一些技巧保证最大延迟和调用栈是由 cyclictest 产生的。 + +cyclictest 提供了参数 `--breaktrace=` 和 `--tracemark` 以更好地锁定最大延迟的产生原因。`--breaktrace` 表示,如果测试时 cyclictest 的最大延迟超过给定的数值,就中断测试。`--tracemark` 表示保存产生最大延迟的函数调用栈。在 cyclictest 超过指定延迟后立即中断测试并记录,基本可以保证最大延迟是由 cyclictest 产生的。 + +在使用 `--tracemark` 参数前首先要保证 ftrace 挂载好,并在 current_tracer 文件中选择合适的 tracer。测试前无需手动将 tracing_on 文件置 1,cyclictest 在测试时会自动将 tracing_on 文件置 1,测试结束会自动置 0。测试因超过设定数值而中断后,不会自动打印调用栈,需要自己手动打印 ftrace 中的 trace 文件查看。 + +下面是一个简单的示例脚本,在 cyclictest 产生的最大延迟大于 100μs 时,会自动中断测试,并打印产生的最大延迟和函数调用栈: + +```sh +#!/bin/sh +mount -t tracefs none /sys/kernel/tracing +cd /sys/kernel/tracing +echo wakeup_rt > current_tracer +cyclictest --breaktrace=100 --tracemark +cat trace +``` + +## 总结 + +本文介绍了为 LicheePi 4A 开发板添加 eMMC 支持的过程,使得内核可以从 eMMC 上的 rootfs 启动,还为 v6.5 版本的内核打入了 PREEMPT_RT 补丁,并解决了 redefinition 编译错误。除此之外,本文还介绍了使用 cyclictest 和 ftrace 追踪延迟的小技巧。 + +## 参考资料 + +- [为 LicheePi 4A 开发板构建运行 Linux v6.5-rc1][1] +- [Drew Fustini 开发的 eMMC 补丁][2] +- [thead-opensbi][3] +- [适用于 Linux v6.5 的 官方 PREEMPT_RT 补丁][4] +- [针对 RISC-V 架构的 PREEMPT_RT 补丁][5] +- [[PATCH v3] RISC-V: Fix wrong use of CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK][6] +- [RISC-V 实时抢占优化实践 直播分享视频回放][7] +- [RISC-V 实时抢占优化实践 直播分享 PPT][8] + +[1]: https://gitee.com/tinylab/riscv-linux/blob/master/articles/20230726-licheepi4a-linux.md +[2]: https://lore.kernel.org/all/20230724-th1520-emmc-v2-0-132ed2e2171e@baylibre.com/ +[3]: https://github.com/xhackerustc/thead-opensbi +[4]: https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.5/ +[5]: https://lore.kernel.org/linux-riscv/20230510162406.1955-1-jszhang@kernel.org/ +[6]: https://lore.kernel.org/linux-riscv/20230913052940.374686-1-wangjiexun@tinylab.org/ +[7]: https://www.bilibili.com/video/BV1Xz4y1u7pp/?spm_id_from=333.999.0.0 +[8]: https://gitee.com/tinylab/riscv-linux/blob/master/ppt/riscv-licheepi4a-rt-intro.pdf + -- Gitee From 49171dbdcc3025fecc66335fe498832b585de79c Mon Sep 17 00:00:00 2001 From: wangjiexun Date: Sun, 17 Sep 2023 21:36:07 +0800 Subject: [PATCH 2/5] licheepi4a-rt-test.md: commit correct result of tinycorrect-tounix Signed-off-by: wangjiexun --- articles/20230917-licheepi4a-rt-test.md | 405 ++++++++++++------------ 1 file changed, 203 insertions(+), 202 deletions(-) diff --git a/articles/20230917-licheepi4a-rt-test.md b/articles/20230917-licheepi4a-rt-test.md index bcc8bb5..efc314f 100755 --- a/articles/20230917-licheepi4a-rt-test.md +++ b/articles/20230917-licheepi4a-rt-test.md @@ -1,202 +1,203 @@ -> Author: 王杰迅
-> Date: 2023/09/17
-> Revisor: falcon
-> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
-> Sponsor: PLCT Lab, ISCAS - -# LicheePi 4A 实时性测试实践 - -## 前言 - -在 [之前的文章][1] 中介绍了 LicheePi 4A 开发板构建并运行 Linux v6.5-rc1 的过程,当时实现的效果为:内核可以成功启动并进入 initramfs 命令行界面。 - -在本文中,将介绍为 LicheePi 4A 开发板添加 eMMC 支持的过程,使得内核可以从 eMMC 上的 rootfs 启动,同时将内核版本更新到 v6.5,打入对应的 PREEMPT_RT 补丁。 - -除此之外,本文还将介绍使用 cyclictest 和 ftrace 进行延迟追踪的小技巧。 - -## 软件版本 - -| Software | Version | -|------------|------------------------------------------| -| Linux | 6.5 | -| U-Boot | 2020.01 | -| OpenSBI | thead-opensbi | -| Buildroot | 2023.02.2 | - -## 添加 eMMC 支持 - -LicheePi 4A 开发板提供了 eMMC 作为外部存储, eMMC 是 Flash 的一种,在嵌入式系统中使用广泛。 - -官方 Linux 内核从 v6.5 版本开始添加了对 LicheePi 4A 开发板的设备树支持,具体见 `arch/riscv/boot/dts/thead` 文件夹下的各文件。但其中的设备树目前不够完善,主要的外设只实现了串口,没有办法使用外部存储。因此想要使用 LicheePi 4A 的 eMMC,必须借助社区中其他开发者提供的补丁。 - -[Drew Fustini 的补丁][2] 为开发板 Beaglev-Ahead 添加了 eMMC 支持。由于 Beaglev-Ahead 和 LicheePi 4A 都是使用 TH1520 作为主控芯片,因此该补丁也可适用于 LicheePi 4A。 - -该补丁添加了对 eMMC 的设备树支持,并修改了驱动文件 `drivers/mmc/host/sdhci-of-dwcmshc.c`,在开启内核配置项 `CONFIG_MMC_SDHCI_OF_DWCMSHC=y` 之后,可以实现对 eMMC 外设的基本读写。但目前该驱动还没有支持 DMA,效率较低,仍在迭代开发中。 - -将 eMMC 驱动和设备树替换完毕后,仍出现了多个小问题,最终通过选择合适的 OpenSBI,才实现了稳定地使用 eMMC 进行读写。 - -### load access fault - -最初时,由于使用的 OpenSBI 版本过低,没有支持设备树中的 "thead,c900-clint" ,在进行初始化时会出现如下报错: - -``` -[ 0.000000] Oops - load access fault [#1] -... -[ 0.000000] epc : __plic_toggle+0x6a/0x72 -[ 0.000000] ra : __plic_init.constprop.0+0x31e/0x4ac -``` - -更换为较新版本的 OpenSBI(v1.2 及以上)后,报错消失,可以正常启动。 - -### illegal instruction - -当尝试给 eMMC 施加压力测试时,如使用如下命令: - -``` -$ while true; do /bin/dd if=/dev/zero of=bigfile bs=1024000 count=1024; done & -``` - -会出现如下报错导致系统崩溃: - -``` -sbi_trap_error: hart1: illegal instruction handler failed (error -2) -``` - -经 Jisheng Zhang 老师提醒,使用 [最新的 thead-opensbi][3] 后,eMMC 在压力测试下也可以稳定使用,不再报错。猜测该报错产生的原因为:TH1520 芯片的部分指令没有被官方 OpenSBI 实现。 - -总之,目前应使用 [最新的 thead-opensbi][3],以保证系统正常运行。 - -### rootfs - -当 eMMC 可以正常使用后,就可以不再使用 initramfs。将 rootfs 烧写到 eMMC 后,系统就可以从 eMMC 的 rootfs 启动。使用 Buildroot 的 menuconfig,选择构建的 rootfs 文件系统类型为 ext4: - -``` -Filesystem images ---> - [*] ext2/3/4 root filesystem - ext2/3/4 variant (ext4) ---> - (rootfs) filesystem label - (60M) exact size -``` - -LicheePi 4A 提供的烧录工具最大可以将 4GB 的 rootfs 烧录到 eMMC 中,但实际的 rootfs 可能并没有那么大,在制作 rootfs 时可以选择较小的大小,如 60MB。在系统启动后,可以使用 resize2fs 命令对 rootfs 进行扩容: - -``` -$ resize2fs /dev/mmcblk0p3 -``` - -使用该命令会自动将 rootfs 扩容,将 eMMC 的未使用存储空间全部并入其中。 - -## 编译 PREEMPT_RT v6.5 内核 - -为了提高系统实时性,首先打入和 Linux 内核版本对应的 [官方 PREEMPT_RT 补丁][4]。同时,由于 LicheePi 4A 开发板基于 RISC-V 架构,因此还需要打入 [针对 RISC-V 架构的 PREEMPT_RT 补丁][5]。 - -### 解决 redefinition 错误 - -在将 Linux 内核更新到 v6.5,打入 PREEMPT_RT 补丁并配置抢占模式为 PREEMPT_RT 后,尝试编译时出现报错: - -``` -arch/riscv/kernel/irq.c:64:6: error: redefinition of 'do_softirq_own_stack' - 64 | void do_softirq_own_stack(void) - | ^~~~~~~~~~~~~~~~~~~~ -In file included from ./arch/riscv/include/generated/asm/softirq_stack.h:1, - from arch/riscv/kernel/irq.c:15: -./include/asm-generic/softirq_stack.h:8:20: note: previous definition of 'do_softirq_own_stack' was here - 8 | static inline void do_softirq_own_stack(void) - | ^~~~~~~~~~~~~~~~~~~~ -``` - -经过查看后发现,在 `arch/riscv/kernel/irq.c` 和 `include/asm-generic/softirq_stack.h` 文件中出现了对 `do_softirq_own_stack` 函数的重复定义。 - -该错误与以下两个配置项有关: - -``` -CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK -CONFIG_SOFTIRQ_ON_OWN_STACK -``` - -正常的逻辑是,如果内核配置 `CONFIG_SOFTIRQ_ON_OWN_STACK=y`,则该函数由 `include/asm-generic/softirq_stack.h` 文件负责实现。 - -如果内核配置 `CONFIG_SOFTIRQ_ON_OWN_STACK=n`,则该函数在 `include/asm-generic/softirq_stack.h` 文件中只负责声明,而由特定架构负责具体实现,如 RISC-V 架构就在 `arch/riscv/kernel/irq.c` 文件中实现。 - -但在 `arch/riscv/kernel/irq.c` 文件中,错把实现 `do_softirq_own_stack` 函数的条件 `SOFTIRQ_ON_OWN_STACK` 写成了 `HAVE_SOFTIRQ_ON_OWN_STACK` 选项,当内核配置项如下时: - -``` -CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y -CONFIG_SOFTIRQ_ON_OWN_STACK=n -``` - -两个文件都会实现 `do_softirq_own_stack` 函数,出现 redefinition 错误。 - -值得一提的是,当没有开启 PREEMPT_RT 时,开启 `HAVE_SOFTIRQ_ON_OWN_STACK` 时默认会开启 `SOFTIRQ_ON_OWN_STACK`,因此不会暴露出错误,只有当开启 PREEMPT_RT 时,才会导致编译失败。 - -目前,该补丁已发送至 [邮件列表][6]。 - -## 延迟追踪技巧 - -在优化系统实时性能时,首先需要分析产生最大延迟的原因。常用的延迟测试及追踪工具为 cyclictest 和 ftrace。这两个软件的基本用法,可以参考泰晓科技的往期直播分享 [RISC-V 实时抢占优化实践][7] 及 [对应 PPT][8]。 - -实际测试时,容易遇到的一个问题是:测试得到的最大延迟并不是 cyclictest 产生的,这对优化实时性能没有任何帮助。例如: - -``` -# wakeup_rt latency trace v1.1.5 on 6.5.0-rt6-r1208-00003-g999d221864bf-dirty -# -------------------------------------------------------------------- -# latency: 12086 us, #6/6, CPU#0 | (M:preempt_rt VP:0, KP:0, SP:0 HP:0 #P:4) -# ----------------- -# | task: irq/12-ttyS0-74 (uid:0 nice:0 policy:1 rt_prio:50) -# ----------------- -…… -``` - -而实际希望得到的最大延迟和调用栈应该是由 cyclictest 产生的,例如: - -``` -# wakeup_rt latency trace v1.1.5 on 6.5.0-rt6-r1208-00003-g999d221864bf-dirty -# -------------------------------------------------------------------- -# latency: 879 us, #6/6, CPU#2 | (M:preempt_rt VP:0, KP:0, SP:0 HP:0 #P:4) -# ----------------- -# | task: cyclictest-212 (uid:0 nice:0 policy:1 rt_prio:99) -# ----------------- -…… -``` - -如果进行了较长时间的测试之后,查看 ftrace 的结果发现没有任何帮助,难免会令人大失所望。因此需要使用一些技巧保证最大延迟和调用栈是由 cyclictest 产生的。 - -cyclictest 提供了参数 `--breaktrace=` 和 `--tracemark` 以更好地锁定最大延迟的产生原因。`--breaktrace` 表示,如果测试时 cyclictest 的最大延迟超过给定的数值,就中断测试。`--tracemark` 表示保存产生最大延迟的函数调用栈。在 cyclictest 超过指定延迟后立即中断测试并记录,基本可以保证最大延迟是由 cyclictest 产生的。 - -在使用 `--tracemark` 参数前首先要保证 ftrace 挂载好,并在 current_tracer 文件中选择合适的 tracer。测试前无需手动将 tracing_on 文件置 1,cyclictest 在测试时会自动将 tracing_on 文件置 1,测试结束会自动置 0。测试因超过设定数值而中断后,不会自动打印调用栈,需要自己手动打印 ftrace 中的 trace 文件查看。 - -下面是一个简单的示例脚本,在 cyclictest 产生的最大延迟大于 100μs 时,会自动中断测试,并打印产生的最大延迟和函数调用栈: - -```sh -#!/bin/sh -mount -t tracefs none /sys/kernel/tracing -cd /sys/kernel/tracing -echo wakeup_rt > current_tracer -cyclictest --breaktrace=100 --tracemark -cat trace -``` - -## 总结 - -本文介绍了为 LicheePi 4A 开发板添加 eMMC 支持的过程,使得内核可以从 eMMC 上的 rootfs 启动,还为 v6.5 版本的内核打入了 PREEMPT_RT 补丁,并解决了 redefinition 编译错误。除此之外,本文还介绍了使用 cyclictest 和 ftrace 追踪延迟的小技巧。 - -## 参考资料 - -- [为 LicheePi 4A 开发板构建运行 Linux v6.5-rc1][1] -- [Drew Fustini 开发的 eMMC 补丁][2] -- [thead-opensbi][3] -- [适用于 Linux v6.5 的 官方 PREEMPT_RT 补丁][4] -- [针对 RISC-V 架构的 PREEMPT_RT 补丁][5] -- [[PATCH v3] RISC-V: Fix wrong use of CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK][6] -- [RISC-V 实时抢占优化实践 直播分享视频回放][7] -- [RISC-V 实时抢占优化实践 直播分享 PPT][8] - -[1]: https://gitee.com/tinylab/riscv-linux/blob/master/articles/20230726-licheepi4a-linux.md -[2]: https://lore.kernel.org/all/20230724-th1520-emmc-v2-0-132ed2e2171e@baylibre.com/ -[3]: https://github.com/xhackerustc/thead-opensbi -[4]: https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.5/ -[5]: https://lore.kernel.org/linux-riscv/20230510162406.1955-1-jszhang@kernel.org/ -[6]: https://lore.kernel.org/linux-riscv/20230913052940.374686-1-wangjiexun@tinylab.org/ -[7]: https://www.bilibili.com/video/BV1Xz4y1u7pp/?spm_id_from=333.999.0.0 -[8]: https://gitee.com/tinylab/riscv-linux/blob/master/ppt/riscv-licheepi4a-rt-intro.pdf - +> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [tounix]
+> Author: 王杰迅
+> Date: 2023/09/17
+> Revisor: falcon
+> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
+> Sponsor: PLCT Lab, ISCAS + +# LicheePi 4A 实时性测试实践 + +## 前言 + +在 [之前的文章][1] 中介绍了 LicheePi 4A 开发板构建并运行 Linux v6.5-rc1 的过程,当时实现的效果为:内核可以成功启动并进入 initramfs 命令行界面。 + +在本文中,将介绍为 LicheePi 4A 开发板添加 eMMC 支持的过程,使得内核可以从 eMMC 上的 rootfs 启动,同时将内核版本更新到 v6.5,打入对应的 PREEMPT_RT 补丁。 + +除此之外,本文还将介绍使用 cyclictest 和 ftrace 进行延迟追踪的小技巧。 + +## 软件版本 + +| Software | Version | +|------------|------------------------------------------| +| Linux | 6.5 | +| U-Boot | 2020.01 | +| OpenSBI | thead-opensbi | +| Buildroot | 2023.02.2 | + +## 添加 eMMC 支持 + +LicheePi 4A 开发板提供了 eMMC 作为外部存储, eMMC 是 Flash 的一种,在嵌入式系统中使用广泛。 + +官方 Linux 内核从 v6.5 版本开始添加了对 LicheePi 4A 开发板的设备树支持,具体见 `arch/riscv/boot/dts/thead` 文件夹下的各文件。但其中的设备树目前不够完善,主要的外设只实现了串口,没有办法使用外部存储。因此想要使用 LicheePi 4A 的 eMMC,必须借助社区中其他开发者提供的补丁。 + +[Drew Fustini 的补丁][2] 为开发板 Beaglev-Ahead 添加了 eMMC 支持。由于 Beaglev-Ahead 和 LicheePi 4A 都是使用 TH1520 作为主控芯片,因此该补丁也可适用于 LicheePi 4A。 + +该补丁添加了对 eMMC 的设备树支持,并修改了驱动文件 `drivers/mmc/host/sdhci-of-dwcmshc.c`,在开启内核配置项 `CONFIG_MMC_SDHCI_OF_DWCMSHC=y` 之后,可以实现对 eMMC 外设的基本读写。但目前该驱动还没有支持 DMA,效率较低,仍在迭代开发中。 + +将 eMMC 驱动和设备树替换完毕后,仍出现了多个小问题,最终通过选择合适的 OpenSBI,才实现了稳定地使用 eMMC 进行读写。 + +### load access fault + +最初时,由于使用的 OpenSBI 版本过低,没有支持设备树中的 "thead,c900-clint" ,在进行初始化时会出现如下报错: + +``` +[ 0.000000] Oops - load access fault [#1] +... +[ 0.000000] epc : __plic_toggle+0x6a/0x72 +[ 0.000000] ra : __plic_init.constprop.0+0x31e/0x4ac +``` + +更换为较新版本的 OpenSBI(v1.2 及以上)后,报错消失,可以正常启动。 + +### illegal instruction + +当尝试给 eMMC 施加压力测试时,如使用如下命令: + +``` +$ while true; do /bin/dd if=/dev/zero of=bigfile bs=1024000 count=1024; done & +``` + +会出现如下报错导致系统崩溃: + +``` +sbi_trap_error: hart1: illegal instruction handler failed (error -2) +``` + +经 Jisheng Zhang 老师提醒,使用 [最新的 thead-opensbi][3] 后,eMMC 在压力测试下也可以稳定使用,不再报错。猜测该报错产生的原因为:TH1520 芯片的部分指令没有被官方 OpenSBI 实现。 + +总之,目前应使用 [最新的 thead-opensbi][3],以保证系统正常运行。 + +### rootfs + +当 eMMC 可以正常使用后,就可以不再使用 initramfs。将 rootfs 烧写到 eMMC 后,系统就可以从 eMMC 的 rootfs 启动。使用 Buildroot 的 menuconfig,选择构建的 rootfs 文件系统类型为 ext4: + +``` +Filesystem images ---> + [*] ext2/3/4 root filesystem + ext2/3/4 variant (ext4) ---> + (rootfs) filesystem label + (60M) exact size +``` + +LicheePi 4A 提供的烧录工具最大可以将 4GB 的 rootfs 烧录到 eMMC 中,但实际的 rootfs 可能并没有那么大,在制作 rootfs 时可以选择较小的大小,如 60MB。在系统启动后,可以使用 resize2fs 命令对 rootfs 进行扩容: + +``` +$ resize2fs /dev/mmcblk0p3 +``` + +使用该命令会自动将 rootfs 扩容,将 eMMC 的未使用存储空间全部并入其中。 + +## 编译 PREEMPT_RT v6.5 内核 + +为了提高系统实时性,首先打入和 Linux 内核版本对应的 [官方 PREEMPT_RT 补丁][4]。同时,由于 LicheePi 4A 开发板基于 RISC-V 架构,因此还需要打入 [针对 RISC-V 架构的 PREEMPT_RT 补丁][5]。 + +### 解决 redefinition 错误 + +在将 Linux 内核更新到 v6.5,打入 PREEMPT_RT 补丁并配置抢占模式为 PREEMPT_RT 后,尝试编译时出现报错: + +``` +arch/riscv/kernel/irq.c:64:6: error: redefinition of 'do_softirq_own_stack' + 64 | void do_softirq_own_stack(void) + | ^~~~~~~~~~~~~~~~~~~~ +In file included from ./arch/riscv/include/generated/asm/softirq_stack.h:1, + from arch/riscv/kernel/irq.c:15: +./include/asm-generic/softirq_stack.h:8:20: note: previous definition of 'do_softirq_own_stack' was here + 8 | static inline void do_softirq_own_stack(void) + | ^~~~~~~~~~~~~~~~~~~~ +``` + +经过查看后发现,在 `arch/riscv/kernel/irq.c` 和 `include/asm-generic/softirq_stack.h` 文件中出现了对 `do_softirq_own_stack` 函数的重复定义。 + +该错误与以下两个配置项有关: + +``` +CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK +CONFIG_SOFTIRQ_ON_OWN_STACK +``` + +正常的逻辑是,如果内核配置 `CONFIG_SOFTIRQ_ON_OWN_STACK=y`,则该函数由 `include/asm-generic/softirq_stack.h` 文件负责实现。 + +如果内核配置 `CONFIG_SOFTIRQ_ON_OWN_STACK=n`,则该函数在 `include/asm-generic/softirq_stack.h` 文件中只负责声明,而由特定架构负责具体实现,如 RISC-V 架构就在 `arch/riscv/kernel/irq.c` 文件中实现。 + +但在 `arch/riscv/kernel/irq.c` 文件中,错把实现 `do_softirq_own_stack` 函数的条件 `SOFTIRQ_ON_OWN_STACK` 写成了 `HAVE_SOFTIRQ_ON_OWN_STACK` 选项,当内核配置项如下时: + +``` +CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK=y +CONFIG_SOFTIRQ_ON_OWN_STACK=n +``` + +两个文件都会实现 `do_softirq_own_stack` 函数,出现 redefinition 错误。 + +值得一提的是,当没有开启 PREEMPT_RT 时,开启 `HAVE_SOFTIRQ_ON_OWN_STACK` 时默认会开启 `SOFTIRQ_ON_OWN_STACK`,因此不会暴露出错误,只有当开启 PREEMPT_RT 时,才会导致编译失败。 + +目前,该补丁已发送至 [邮件列表][6]。 + +## 延迟追踪技巧 + +在优化系统实时性能时,首先需要分析产生最大延迟的原因。常用的延迟测试及追踪工具为 cyclictest 和 ftrace。这两个软件的基本用法,可以参考泰晓科技的往期直播分享 [RISC-V 实时抢占优化实践][7] 及 [对应 PPT][8]。 + +实际测试时,容易遇到的一个问题是:测试得到的最大延迟并不是 cyclictest 产生的,这对优化实时性能没有任何帮助。例如: + +``` +# wakeup_rt latency trace v1.1.5 on 6.5.0-rt6-r1208-00003-g999d221864bf-dirty +# -------------------------------------------------------------------- +# latency: 12086 us, #6/6, CPU#0 | (M:preempt_rt VP:0, KP:0, SP:0 HP:0 #P:4) +# ----------------- +# | task: irq/12-ttyS0-74 (uid:0 nice:0 policy:1 rt_prio:50) +# ----------------- +…… +``` + +而实际希望得到的最大延迟和调用栈应该是由 cyclictest 产生的,例如: + +``` +# wakeup_rt latency trace v1.1.5 on 6.5.0-rt6-r1208-00003-g999d221864bf-dirty +# -------------------------------------------------------------------- +# latency: 879 us, #6/6, CPU#2 | (M:preempt_rt VP:0, KP:0, SP:0 HP:0 #P:4) +# ----------------- +# | task: cyclictest-212 (uid:0 nice:0 policy:1 rt_prio:99) +# ----------------- +…… +``` + +如果进行了较长时间的测试之后,查看 ftrace 的结果发现没有任何帮助,难免会令人大失所望。因此需要使用一些技巧保证最大延迟和调用栈是由 cyclictest 产生的。 + +cyclictest 提供了参数 `--breaktrace=` 和 `--tracemark` 以更好地锁定最大延迟的产生原因。`--breaktrace` 表示,如果测试时 cyclictest 的最大延迟超过给定的数值,就中断测试。`--tracemark` 表示保存产生最大延迟的函数调用栈。在 cyclictest 超过指定延迟后立即中断测试并记录,基本可以保证最大延迟是由 cyclictest 产生的。 + +在使用 `--tracemark` 参数前首先要保证 ftrace 挂载好,并在 current_tracer 文件中选择合适的 tracer。测试前无需手动将 tracing_on 文件置 1,cyclictest 在测试时会自动将 tracing_on 文件置 1,测试结束会自动置 0。测试因超过设定数值而中断后,不会自动打印调用栈,需要自己手动打印 ftrace 中的 trace 文件查看。 + +下面是一个简单的示例脚本,在 cyclictest 产生的最大延迟大于 100μs 时,会自动中断测试,并打印产生的最大延迟和函数调用栈: + +```sh +#!/bin/sh +mount -t tracefs none /sys/kernel/tracing +cd /sys/kernel/tracing +echo wakeup_rt > current_tracer +cyclictest --breaktrace=100 --tracemark +cat trace +``` + +## 总结 + +本文介绍了为 LicheePi 4A 开发板添加 eMMC 支持的过程,使得内核可以从 eMMC 上的 rootfs 启动,还为 v6.5 版本的内核打入了 PREEMPT_RT 补丁,并解决了 redefinition 编译错误。除此之外,本文还介绍了使用 cyclictest 和 ftrace 追踪延迟的小技巧。 + +## 参考资料 + +- [为 LicheePi 4A 开发板构建运行 Linux v6.5-rc1][1] +- [Drew Fustini 开发的 eMMC 补丁][2] +- [thead-opensbi][3] +- [适用于 Linux v6.5 的 官方 PREEMPT_RT 补丁][4] +- [针对 RISC-V 架构的 PREEMPT_RT 补丁][5] +- [[PATCH v3] RISC-V: Fix wrong use of CONFIG_HAVE_SOFTIRQ_ON_OWN_STACK][6] +- [RISC-V 实时抢占优化实践 直播分享视频回放][7] +- [RISC-V 实时抢占优化实践 直播分享 PPT][8] + +[1]: https://gitee.com/tinylab/riscv-linux/blob/master/articles/20230726-licheepi4a-linux.md +[2]: https://lore.kernel.org/all/20230724-th1520-emmc-v2-0-132ed2e2171e@baylibre.com/ +[3]: https://github.com/xhackerustc/thead-opensbi +[4]: https://cdn.kernel.org/pub/linux/kernel/projects/rt/6.5/ +[5]: https://lore.kernel.org/linux-riscv/20230510162406.1955-1-jszhang@kernel.org/ +[6]: https://lore.kernel.org/linux-riscv/20230913052940.374686-1-wangjiexun@tinylab.org/ +[7]: https://www.bilibili.com/video/BV1Xz4y1u7pp/?spm_id_from=333.999.0.0 +[8]: https://gitee.com/tinylab/riscv-linux/blob/master/ppt/riscv-licheepi4a-rt-intro.pdf + -- Gitee From f74f40353a00ff95de6bb7d4f6ba9a789c87240c Mon Sep 17 00:00:00 2001 From: wangjiexun Date: Sun, 17 Sep 2023 21:37:31 +0800 Subject: [PATCH 3/5] licheepi4a-rt-test.md: commit correct result of tinycorrect-spaces Signed-off-by: wangjiexun --- articles/20230917-licheepi4a-rt-test.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/articles/20230917-licheepi4a-rt-test.md b/articles/20230917-licheepi4a-rt-test.md index efc314f..e19afef 100755 --- a/articles/20230917-licheepi4a-rt-test.md +++ b/articles/20230917-licheepi4a-rt-test.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [tounix]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [tounix spaces]
> Author: 王杰迅
> Date: 2023/09/17
> Revisor: falcon
@@ -26,7 +26,7 @@ ## 添加 eMMC 支持 -LicheePi 4A 开发板提供了 eMMC 作为外部存储, eMMC 是 Flash 的一种,在嵌入式系统中使用广泛。 +LicheePi 4A 开发板提供了 eMMC 作为外部存储,eMMC 是 Flash 的一种,在嵌入式系统中使用广泛。 官方 Linux 内核从 v6.5 版本开始添加了对 LicheePi 4A 开发板的设备树支持,具体见 `arch/riscv/boot/dts/thead` 文件夹下的各文件。但其中的设备树目前不够完善,主要的外设只实现了串口,没有办法使用外部存储。因此想要使用 LicheePi 4A 的 eMMC,必须借助社区中其他开发者提供的补丁。 @@ -38,7 +38,7 @@ LicheePi 4A 开发板提供了 eMMC 作为外部存储, eMMC 是 Flash 的一 ### load access fault -最初时,由于使用的 OpenSBI 版本过低,没有支持设备树中的 "thead,c900-clint" ,在进行初始化时会出现如下报错: +最初时,由于使用的 OpenSBI 版本过低,没有支持设备树中的 "thead,c900-clint",在进行初始化时会出现如下报错: ``` [ 0.000000] Oops - load access fault [#1] @@ -87,7 +87,7 @@ $ resize2fs /dev/mmcblk0p3 使用该命令会自动将 rootfs 扩容,将 eMMC 的未使用存储空间全部并入其中。 -## 编译 PREEMPT_RT v6.5 内核 +## 编译 PREEMPT_RT v6.5 内核 为了提高系统实时性,首先打入和 Linux 内核版本对应的 [官方 PREEMPT_RT 补丁][4]。同时,由于 LicheePi 4A 开发板基于 RISC-V 架构,因此还需要打入 [针对 RISC-V 架构的 PREEMPT_RT 补丁][5]。 @@ -200,4 +200,3 @@ cat trace [6]: https://lore.kernel.org/linux-riscv/20230913052940.374686-1-wangjiexun@tinylab.org/ [7]: https://www.bilibili.com/video/BV1Xz4y1u7pp/?spm_id_from=333.999.0.0 [8]: https://gitee.com/tinylab/riscv-linux/blob/master/ppt/riscv-licheepi4a-rt-intro.pdf - -- Gitee From bc2c1398f3e8505824c525f35d88495da95949cc Mon Sep 17 00:00:00 2001 From: wangjiexun Date: Sun, 17 Sep 2023 21:38:06 +0800 Subject: [PATCH 4/5] licheepi4a-rt-test.md: commit correct result of tinycorrect-header Signed-off-by: wangjiexun --- articles/20230917-licheepi4a-rt-test.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/articles/20230917-licheepi4a-rt-test.md b/articles/20230917-licheepi4a-rt-test.md index e19afef..d5ddde4 100755 --- a/articles/20230917-licheepi4a-rt-test.md +++ b/articles/20230917-licheepi4a-rt-test.md @@ -1,9 +1,9 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [tounix spaces]
-> Author: 王杰迅
-> Date: 2023/09/17
-> Revisor: falcon
-> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
-> Sponsor: PLCT Lab, ISCAS +> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [tounix spaces header]
+> Author: 王杰迅
+> Date: 2023/09/17
+> Revisor: falcon
+> Project: [RISC-V Linux 内核剖析](https://gitee.com/tinylab/riscv-linux)
+> Sponsor: PLCT Lab, ISCAS # LicheePi 4A 实时性测试实践 -- Gitee From 3f28482a3ec24f00e4235cd3c5eb245dbd18f6ec Mon Sep 17 00:00:00 2001 From: wangjiexun Date: Sun, 17 Sep 2023 21:38:21 +0800 Subject: [PATCH 5/5] licheepi4a-rt-test.md: commit correct result of tinycorrect-tables Signed-off-by: wangjiexun --- articles/20230917-licheepi4a-rt-test.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/articles/20230917-licheepi4a-rt-test.md b/articles/20230917-licheepi4a-rt-test.md index d5ddde4..6bfa8f3 100755 --- a/articles/20230917-licheepi4a-rt-test.md +++ b/articles/20230917-licheepi4a-rt-test.md @@ -1,4 +1,4 @@ -> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [tounix spaces header]
+> Corrector: [TinyCorrect](https://gitee.com/tinylab/tinycorrect) v0.2-rc2 - [tounix spaces header tables]
> Author: 王杰迅
> Date: 2023/09/17
> Revisor: falcon
@@ -17,12 +17,12 @@ ## 软件版本 -| Software | Version | -|------------|------------------------------------------| -| Linux | 6.5 | -| U-Boot | 2020.01 | -| OpenSBI | thead-opensbi | -| Buildroot | 2023.02.2 | +| Software | Version | +|-----------|---------------| +| Linux | 6.5 | +| U-Boot | 2020.01 | +| OpenSBI | thead-opensbi | +| Buildroot | 2023.02.2 | ## 添加 eMMC 支持 -- Gitee