LWN: printk()的难点以及解决方案

告别printk:用Linux内核Tracepoint给你的驱动调试换个活法(附ext4实战代码) 本文探讨了Linux内核调试中printk的局限性,并介绍了Tracepoint技术的优势。通过ext4文件系统的实战代码,展示了Tracepoint如何实现高性能、低开销的内核调试,包括动态监控、精准过滤和用户空间工具trace-cmd的使用。文章还提供了自定义Tracepoint的进阶技巧和性能对比数据,帮助开发者提升调试效率。 阅读详情
640
点击上方蓝色“Linux News搬运工”关注我们~

Why printk() is so complicated (and how to fix it)

By Jonathan Corbet


LPC

内核的printk()函数在普通人想象中应该是个非常简单的函数,只要处理好字符串格式化然后输出到kernel log里就好。其实这里隐藏着非常多的复杂问题,28年过去了,kernel开发者对printk()仍然非常不满意。在2019 Linux Plumbers Conference会议上,John Ogness介绍了printk()的实现复杂在什么地方,以及近期的相关工作。

这里的核心问题是kernel代码必须要能在任何上下文(context)都可以调用printk()。在atomic context调用的话需要确保printk()不能导致阻塞,而在non-maskable interrupts (NMIs)上下文调用的话甚至连spinlock也不能用了。同时,系统出错时printk()的输出内容非常重要,开发者不愿意丢掉任何一行信息,哪怕系统就要crash或者hang住了。这些信息要在console设备上打印出来,通常是一个串口,或者是经过显卡显示在屏幕上,或者通过网络连接送出来。此外,printk()不应该干扰系统的正常执行过程。

他总结说,printk()看起来简单并且到处都在用,而它的底层实现其实跟系统的方方面面都搅在一起。

The path to the present

Ogness介绍了printk()的发展史,可以参见他的ppt(https://www.linuxplumbersconf.org/event/4/contributions/290/attachments/276/463/lpc2019_jogness_printk.pdf)。第一版kernel v0.0.1发布时就包含了printk(),当时这个函数是同步行为(synchronous),会直接把信息利用一些汇编代码写入TTY端口。这种行为很可靠,不过无法扩展,今后kernel开始支持多CPU之后就必须要更改这里的行为了。

内核 0.99.7a版本里就增加了console registration(注册机制)。在0.99.13k版本里增加了“log level”设置。在2.4.0里面增加了bust_spinlocks()机制,用来避免系统crash以至于无法正常工作的时候还要进行不必要的等待spinlock操作。从2.4.10开始,printk()也支持异步(asynchronous)工作模式了。2.6.24版本之前,printk()时不时会导致偶发的特别高的延迟,在这个版本里面大家会在latency tracer里面忽略printk(),避免干扰人们的分析。3.4版本里增加了structured logging,sequence numbers,以及/dev/kmsg接口。4.10里面增加了"safe buffers"机制,用来在NMI context上下文来做输出。在4.15版本里,修复了一个bug可能导致CPU不停地输出信息。在5.0版本里,加入了caller identifier(调用者标记)功能。

也就是说这么多年来printk()一直在持续改进,不过仍然有很多遗留问题。其中之一就是关于用来保护ring buffer的raw spinlock,它没法在NMI上下文调用,因此printk()必须要先输出到不依赖lock的safe buffer里。这样会导致message最终被copy到真正的ring buffer的时候更新的timestamp不精确,也可能会导致message丢失,或者导致CPU异常offline的时候buffer没有被刷出去。

此外console驱动这边也有麻烦,因为它不仅很慢,并且还是在关中断模式下调用的。大多数console device设计时都没有考虑过kernel panic的场景,在这种最需要它的场景下表现得不够可靠。

其他还有个问题是printk()对各个级别的log一视同仁。某些频繁输出的信息如果被错误设置成urgent级别,可能会导致latency问题,从而让大家会调整level来导致丢失其他的urgent信息。虽然我们修复了一个CPU被卡住持续输出log的bug,不过最后一个CPU来接管log输出的时候也可能会被大量工作塞满。这时可能每个printk()调用都会费不少时间。而bust_spinlocks()机制其实就是忽略所有lock,寄希望于系统仍能正常工作。他觉得应该还有更好的方案解决这个问题。

The better way

Ogness认为过去多年printk()所面临的这些问题现在已经聚焦在了“非侵入性”(Non-interference,不干扰系统运行)和“可靠性”这两方面的矛盾了。大家已经明白了没法在同一个地方满足这两方面的需求。那么一个比较好的方案就是把它们分开。非侵入性的实现,要求让printk()变得可以被抢占,ring buffer要在各个context下都可靠,还有把console处理移到专用的kernel thread上去。而可靠性要求,则需要提供一个synchronous channel来放重要的信息,以及一个“atomic console"概念,还有要着重处理"emergency messages"紧急消息。

两个目标都依赖printk()的ring buffer。这个buffer有多个同时进行的reader,仅有一个writer。这个buffer在一片连续内存里,通过一个特别的可以在一个CPU上获取多次的spinlock("CPU lock")来保护着。这个锁他觉得更像是以前旧版本kernel里非常著名的那个big kernel lock。

printk()开发时也按照kernel开发里面比较好的工作模式来做,首先创建了一个新的ring buffer来解决当前方案里的问题。这个ring buffer是完全不用锁保护的,支持多个reader和writer,在任意上下文进行访问。metadata则会通过一个单独的描述机制来记录,包括记录时间戳以及message的序列号等。这个ring buffer有很多优势,不过也非常复杂,使用了至少9对memory-barrier操作,很难写好相关的文档,也很难review,他也没觉得这里实现的支持多个writer(导致复杂性大增)有什么现实需求。

新增了每个console都有一个独立的kernel thread,用来把printk()调用者和console相关处理工作分隔开。每个console现在都可以按自己的速度尽快打印,每个都有自己独立的log level设置。这样就把console的责任简化了很多,不过还是有一些lock相关的问题,以及大家有点怀疑这种基于线程的实现方式是否能保证任何情况都把message输出出去。不过Ogness提醒说,可靠性是靠其它机制保证的,这里每个console的独立线程是用来改善非侵入性(non-interference)需求的机制。

对于可靠性,他的计划是增加一个"atomic console"概念。支持这个功能的console都会有一个write_atomic()功能函数,可以在任何上下文调用都不会出错。这个函数内部实现是完全同步的操作,也就是说会大大拖慢系统,因此只有emergency(紧急)信息才应该用它。不过好处就是不再需要bust_spinlocks(),也不需要依赖oops_in_progress这个全局变量了。

这里的难点在于在console驱动里面正确实现write_atomic()。他基于8250 UART实现了一个console驱动,工作量不小。肯定会有不少系统上完全没有atomic-console功能,这样就需要其他一些方案了,例如创建一个特殊的console来写入一块内存区域,或者试着在atomic context上下文之外才进行synchronous打印,或者干脆就回退到原来的方案进行打印。

之所要使用atomic console,主要是为了能正确处理“emergency message”。这里最大的问题就是要判断哪些消息是重要信息。log level有点算是一个灰色地带,不是一个可靠的翻案。还有其他一些情况下printk()的输出是非常重要的,正确的实现方法应该是跟BUG()等这些函数关联起来。

Ogness指出这个工作在今年2月份开始,目前的版本是8月份发布的。上面提到的绝大多数功能都已经实现出来了,开发者们可以上手把玩一下了。

Further discussion

后来的一个session,LWN编辑没能参加。Ogness发出来的总结(https://lwn.net/ml/linux-kernel/87k1acz5rx.fsf@linutronix.de/)里面包含了大家达成一致的一些观点。他也感谢大家参与这个会议,认为“省下了需要用来读写邮件的几百个小时”。

从上述总结来看,后面会用Petr Mladek实现的另一种ring buffer方案,这个ring buffer实现更加简单,review也更容易做。Ogness把他的工作也移植到这个ring buffer上,证明是可行的。而每个console独立的内核线程会继续使用。

这里提到的“emergency message"概念,最后被“emergency state”观点取代了,它可以反应整个系统的状态。当kernel在这个状态市,所有信息都会通过尽可能地使用write_atomic()函数来输出出来。CPU lock会继续使用,不过目的变成了当系统在emergency state状态时,同步(synchronize)所有console线程。

还有其他一些改动,包括增加了pr_flush()函数,用来等待直到所有信息都被输出给console了。目前修改后的patch还没有发出来,不过会很快了。

[Your editor thanks the Linux Foundation, LWN's travel sponsor, for supporting his travel to this event.]

全文完

LWN文章遵循CC BY-SA 4.0许可协议。

极度欢迎将文章分享到朋友圈 
热烈欢迎转载以及基于现有协议修改再创作~

长按下面二维码关注:Linux News搬运工,希望每周的深度文章以及开源社区的各种新近言论,能够让大家满意~

640?wx_fmt=jpeg

RV1109与hi3861L SD卡槽WiFi驱动移植实战:内核适配与调试技巧 本文详细介绍了将海思hi3861L WiFi模块移植到瑞芯微RV1109平台的实战经验,重点解决SD卡槽SDIO协议适配、内核版本差异(4.9到4.19)带来的结构体变更、定时器接口更新等技术难题,并分享设备树配置、中断处理及性能调优等关键技巧,为嵌入式WiFi驱动移植提供实用参考。 阅读详情

相关推荐

printk函数分析 - 中断关闭原理探究

但是,如果中断被关闭了,它就会尝试获取锁,并立即释放该锁。这样的行为导致了一个问题:如果printk函数被调用时中断是开启的,那么在函数执行过程中,由于中断被关闭了,所以可能会导致重要的中断处理被延迟。总结一下,printk函数在内部调用vprintk函数,在vprintk函数中会判断当前中断是否被关闭,如果中断被关闭,则尝试获取锁并立即释放该锁。可以看到,在printk函数中,它实际上是调用了另外一个函数vprintk,这个函数才是真正的输出函数。在printk函数中,它的参数为。

qq_37934722的博客 650

linux内核调试和性能优化

Linux内核调试和性能优化

个人学习记录 4500

DrissionPage实战:5分钟搞定京东滑块验证码自动登录(附完整轨迹生成代码)

本文详细介绍了如何使用DrissionPage工具实现京东滑块验证码的自动化登录,包括环境配置、滑块缺口识别、拟人化轨迹生成算法及完整登录流程。通过物理运动学模型和智能识别技术,有效提升验证码破解成功率,适用于电商自动化场景。

weixin_29229055的博客 243

Linux之“死”

人固有一死或重于泰山或轻于鸿毛,死法不一殊途同归,留下的是后人的精神瞻仰。linux系统在某些异常情况产生之后会选择“死去”,来看下它是如何死去的。 linux version:4.14.224 arch:mips file:arch\mips\kernel\traps.c traps.c有个die函数: void __noreturn die(const char *str, struct pt_regs *regs) { static int die_counter; //die函数

Suvine的专栏 1081

Hcaptcha验证码破解深度解析:从环境检测到n值算法的攻防实战

本文深入解析Hcaptcha验证码的攻防技术,从环境检测到n值算法的全面突破策略。详细介绍了浏览器指纹模拟、图像识别工程化解决方案及协议层逆向分析,为安全研究人员提供高效破解Hcaptcha的实战指南。

weixin_42563415的博客 371

【从零搭建到实战运行】基于PX4-1.13与XTDrone的FAST-LIVO2 Gazebo仿真全流程解析

本文详细解析了从零开始搭建基于PX4-1.13飞控、XTDrone仿真框架与Gazebo的FAST-LIVO2无人机仿真平台的全流程。内容涵盖环境配置、Livox雷达插件定制、算法部署与参数调试,旨在帮助开发者快速构建完整的激光-惯性-视觉SLAM仿真环境,并解决集成过程中的常见问题。

weixin_29218509的博客 520

printk问题

环形缓冲区是Linux内核的核心部分。驱动程序,子系统和很多通用功能用printk()共享错误和普通消息。输入dmesg或sudo dmesg在终端中查看其内容。 John Ogness提供了长达57分钟的视频,标题为“为什么printk()如此复杂? ” (https://linuxreviews.org/Why_is_printk()_so_complicated%3F),详细介绍了Linux内核的环形缓冲区的历史,自1991年Linux 0.01以来,2019 Linux会议上,他指出了print

地推 410

MT4量化交易入门:手把手教你用MQL4编写第一个外汇EA(含完整代码)

本文详细介绍了如何使用MQL4在MT4平台上编写第一个外汇EA,涵盖从开发环境配置到均线交叉策略实现的完整流程。通过手把手教学和完整代码示例,帮助量化交易新手快速掌握外汇自动化交易的核心技术,实现高效的MT4量化交易系统。

mmm90的博客 526

printk打印消息机制

2.1.4  printk打印消息机制 在内核中,函数printk将消息打印到环形缓冲区__log_buf中,并将消息传给控制台进行显示。控制台驱动程序根据控制台的日志级别显示日志消息。 应用程序通过系统调用sys_syslog管理环形缓冲区__log_buf,它可以读取数据、清除缓冲区、设置日志级别、开/关控制台等。 当系统调用sys_syslog从环形缓冲区__log_buf读取数据时,

wxie的Linux人生 1630

从 0 到 1 构建 Graph RAG 系统:本地图谱 + 通义千问落地实践

本文介绍了一个基于知识图谱的检索增强生成系统(Graph RAG),该系统结合领域知识图谱、语义检索和大模型问答,旨在提供结构化、精准的技术问答服务。文章详细说明了项目背景、目标、核心技术架构以及实现方法,包括本地图谱构建、Neo4j数据库接入、语义检索和大模型集成等关键环节。该系统支持混合检索、多轮问答和知识图谱关联理解,能够有效减少大模型幻觉,提升问答的准确性和可解释性。文中还展示了核心代码结构和流程图,呈现了从文档加载到图谱构建再到问答生成的完整流程。该系统适用于需要处理复杂领域知识的研发和数据分析场

m0_58378112的博客 1399

SystemC实战:用C++搞芯片建模的5个典型场景(含代码示例)

本文通过五个典型实战场景,详细介绍了如何使用SystemC这一基于C++的硬件建模库进行芯片设计与系统级建模。内容涵盖从基础并发模块构建、事务级总线建模、跨时钟域验证,到与ModelSim协同仿真及多核系统性能探索,并提供了完整的代码示例,帮助软件工程师利用熟悉的C++工具链高效参与硬件架构设计与验证。

weixin_29191761的博客 314

LWN:关于printk()的讨论!

关注了就能看到更多这么棒的文章哦~A discussion on printk()By Jake EdgeOctober 4, 2022LPCDeepL assisted translationhttps://lwn.net/Articles/909980/出于各种原因,内核的打印函数 printk() 多年来一直有许多与之相关的改进工作。printk() 的一个顽固问题是它带来的 latency...

Linux News搬运工 479

常学常新:《Attention Is All You Need》万字解读!

常学常新:《Attention Is All You Need》万字解读!

hunteritself的博客 3644

LWN:对print()输出消息生成索引列表!

关注了就能看到更多这么棒的文章哦~printk() indexingBy Jonathan CorbetMay 27, 2021DeepL assisted translationhttp...

Linux News搬运工 250

基于FPGA的IIR数字滤波器设计

一种是在直接法的基础上,采用预见的算法,目的是提高系统的吞吐量(指对于网络、端口设备或者其他的设施,单位时间内成功传输数据的数量,比特、字节和分组是吞吐量常用的单位),带有预见算法编程实现的IIR数字滤波器有更多的优点,例如:数据传送速度快,效率高等等;设计模拟滤波器时,它的电路一般都很复杂,而且分析起来也很麻烦,电路的复杂性就决定了使用的器件必定很多,很复杂,就这一方面看来,数字滤波器的设计要更加简单灵活,并且模拟电路不容易改变系统的参数,它的性能还很容易受到温度环境的影响,使得噪声很大。

毕业设计区博客 2107

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

LWN:实时抢占真的快要完工了!

关注了就能看到更多这么棒的文章哦~The real realtime preemption end gameBy Jonathan CorbetNovember 16, 2023LPCChatGPT translationhttps://lwn.net/Articles/951337/Linux 实时性支持的加入是一个漫长的故事;它首次在 2004 年的 LWN 文章中亮相。在很长一段时间里,似乎...

Linux News搬运工 919

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

printk 续行问题

最近在代码工程升级kernel版本后发现 代码中使用for循环dump 一些值的时候printk(“0x%x ”,temp_data)不能续行打印,导致每个没有换行\n结束的printk在打印时自动换行。 查看后发现kernel4.9之后printk续行打印需要强制加上KERN_CONT flag. 参考 https://lwn.net/Articles/732420/有详细介绍。 加完KERN_CONT后 续行问题是解决了,但是发现了一些奇怪的现象。 example1: printk("txt..

u014044624的博客 2455

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

LWN:关于realtime patch的一次问答!

关注了就能看到更多这么棒的文章哦~A Q&A about the realtime patchesBy Jake EdgeJuly 18, 2023EOSSChatGPT assisted translationhttps://lwn.net/Articles/938236/在 2023 年实时 Linux 峰会上,Thomas Gleixner 回答了关于内核实时特性、其现状以及 Rea...

Linux News搬运工 1166

LWN:利用BPF来检查kernel数据结构内容!

关注了就能看到更多这么棒的文章哦~Dumping kernel data structures with BPFByJonathan CorbetApril 27, 2020原文来自:...

Linux News搬运工 793

LWN:要提供更好的 OOM 调试工具!

关注了就能看到更多这么棒的文章哦~Better tools for out-of-memory debuggingBy Jonathan CorbetMay 11, 2022LSFMMDeepL assisted translationhttps://lwn.net/Articles/894546/Out-of-memory(OOM)的情况是用户、系统管理员以及内核开发人...

Linux News搬运工 400

LWN:5.15 合并周期后半部分!

关注了就能看到更多这么棒的文章哦~The rest of the 5.15 merge windowBy Jonathan CorbetSeptember 13, 2021DeepL as...

Linux News搬运工 448

内核开发工具链实战:从printk到eBPF的高效调试指南

Linux内核作为复杂并发系统,其开发对工具链有着极高要求。传统printk调试已难以应对内存越界、数据竞争等隐蔽问题,开发者需要掌握从静态分析到动态观测的完整工具体系。构建阶段通过ccache、并行编译与配置裁剪可显著提升迭代效率;运行时借助ftrace、perf与eBPF实现细粒度性能追踪和故障定位;测试环节则利用KUnit和kselftest实现自动化回归。从稀疏检查到动态调试,从QEMU快速验证到交叉编译移植,这套工具组合贯穿内核开发全流程。理解各工具的原理与适用场景,能够帮助开发者快速定位问题、减

weixin_42527654的博客 168

linux内核2.6中设备模块编程的解决方法

近日尝试linux内核设备模块编程,使用《linux内核编译》一书,但在新版的2.6内核中,例子程序无法编译通过,在网上搜寻了很久,都没有找到一个完整的解决方案,最后终于在网站http://lwn.net/获得帮助,现总结如下init和clear命名方式改变,makefile改变用一个hello world程序说明原版如下:#include #include #if C

rainman1981的专栏 2067

嵌入式Linux驱动开发学习路线与21天速成教材实战解析

嵌入式Linux驱动开发是嵌入式系统开发的核心技术之一,其原理基于操作系统对硬件资源的抽象管理,通过内核模块与设备树实现硬件与系统的解耦。掌握驱动开发不仅能提升系统移植与内核裁剪能力,更是嵌入式Linux面试题中的高频考察点。在工业控制、物联网网关、智能终端等场景中,驱动工程师需具备硬件分析、内核调试与并发控制等综合技能。飞凌嵌入式联合北京大学出版社推出的《嵌入式Linux系统开发21天速成》,正是围绕这一技术路径,将驱动开发、系统移植与项目实战拆解为可验证的阶段目标,帮助学习者高效跨越从入门到实战的门槛。

weixin_33979203的博客 356

使用TRACE_EVENT宏添加Tracepoint(1/3部分)

其他的追踪点的头文件必须使用除"sched"和"_TRACE_SCHED_H"之外,其他的内容。TP_fast_assign宏中的代码是普通的C语言代码。其中,"#define TRACE_SYSTEM sched"起到了这样的效果,TRACE_SYSTEM定义了头文件中的TRACE_EVENT()宏属于哪个组,同时也表明了TRACE_EVENT()宏中定义的追逐点属于"/sys/kernel/debug/tracing/events/"目录下的哪个子目录,这种分组决定了用户按组启用或者禁用追踪点。

生活需要深度 930

LDD3中英文高清电子书:嵌入式Linux驱动开发案头必备

在嵌入式Linux开发中,设备驱动是连接硬件与内核的关键抽象层,其核心在于理解字符设备、并发控制与内存管理等底层机制。Linux设备驱动程序(LDD3)虽基于早期内核,但驱动模型的核心思想一脉相承,配合现代内核API对照阅读仍极具参考价值。中英文高清电子书便于全文检索与术语对照,能显著提升驱动开发调试效率。无论是嵌入式Linux工程师、运维人员还是国产化替代方案开发者,案头常备LDD3电子版,结合当前内核文档与头文件,可快速跨越从应用开发到内核驱动修改的技术门槛。

weixin_33829657的博客 375
上一篇: LWN: 监控kernel内部的ABI
下一篇: LWN: 数据库开发者对Linux kernel的要求
LinuxNews搬运工
博客等级 码龄7年 438粉丝 20原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值