湛江市网站建设_网站建设公司_SQL Server_seo优化
2025/12/23 14:27:19 网站建设 项目流程

1. 前文回顾

Linux的Dynamic debug功能简单讲了下如何使用。再来回顾下其概念和用法。
Dynamic Debug 是 Linux 内核的动态调试功能,允许在运行时动态开启/关闭特定的pr_debug()dev_dbg()输出,而无需重新编译内核。

核心特点:

  • ✅ 运行时控制:无需重启
  • ✅ 精细化控制:可按模块、文件、函数、行号过滤
  • ✅ 零性能开销:关闭时完全无开销
  • ✅ 使用 DebugFS 作为控制接口

1.1 DebugFS 控制接口

主控制文件:/sys/kernel/debug/dynamic_debug/control

# 查看所有可用的 debug 点$cat/sys/kernel/debug/dynamic_debug/control drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c:123[amdgpu]amdgpu_init=_"AMDGPU driver loaded\012"drivers/gpu/drm/amd/amdgpu/amdgpu_device.c:456[amdgpu]amdgpu_device_init=_"Device init started\012"...# 启用特定模块的所有 debug 输出$echo'module amdgpu +p'>/sys/kernel/debug/dynamic_debug/control# 启用特定文件的 debug 输出$echo'file amdgpu_ring.c +p'>/sys/kernel/debug/dynamic_debug/control# 启用特定函数的 debug 输出$echo'func amdgpu_ring_init +p'>/sys/kernel/debug/dynamic_debug/control# 禁用 debug 输出$echo'module amdgpu -p'>/sys/kernel/debug/dynamic_debug/control

2. 内核实现分析

位置:lib/dynamic_debug.c

2.1. 数据结构
/* 每个 pr_debug() 对应一个 _ddebug 结构 */struct_ddebug{constchar*modname;/* 模块名 */constchar*function;/* 函数名 */constchar*filename;/* 文件名 */constchar*format;/* 格式字符串 */unsignedintlineno:18;/* 行号 */unsignedintflags:8;/* 标志 (是否启用) */}__attribute__((aligned(8)));/* 标志定义 */#define_DPRINTK_FLAGS_PRINT(1<<0)/* 启用打印 */#define_DPRINTK_FLAGS_INCL_MODNAME(1<<1)#define_DPRINTK_FLAGS_INCL_FUNCNAME(1<<2)#define_DPRINTK_FLAGS_INCL_LINENO(1<<3)
2.2. DebugFS 文件操作
/* 读操作:显示所有 debug 点 */staticintddebug_proc_show(structseq_file*m,void*p){structddebug_iter*iter=m->private;struct_ddebug*dp=p;charflagsbuf[10];/* 格式化输出每个 debug 点的信息 */seq_printf(m,"%s:%u [%s]%s =%s \"%s\"\n",trim_prefix(dp->filename),dp->lineno,iter->table->mod_name,dp->function,ddebug_describe_flags(dp->flags,flagsbuf,sizeof(flagsbuf)),dp->format);return0;}/* 写操作:处理控制命令 */staticssize_tddebug_proc_write(structfile*file,constchar__user*ubuf,size_tlen,loff_t*offp){char*tmpbuf;intret;/* 限制输入大小 */if(len==0||len>PAGE_SIZE)return-EINVAL;/* 从用户空间复制命令 */tmpbuf=memdup_user_nul(ubuf,len);if(IS_ERR(tmpbuf))returnPTR_ERR(tmpbuf);/* 解析并应用控制命令 */ret=ddebug_exec_queries(tmpbuf,NULL);kfree(tmpbuf);if(ret<0)returnret;returnlen;}/* file_operations 定义 */staticconststructfile_operationsddebug_proc_fops={.owner=THIS_MODULE,.open=ddebug_proc_open,.read=seq_read,.llseek=seq_lseek,.release=seq_release_private,.write=ddebug_proc_write,};
2.3. 初始化
staticint__initdynamic_debug_init_debugfs(void){structdentry*dir;/* 创建 dynamic_debug 目录 */dir=debugfs_create_dir("dynamic_debug",NULL);if(!dir)return-ENOMEM;/* 创建 control 文件 */debugfs_create_file("control",0644,dir,NULL,&ddebug_proc_fops);return0;}fs_initcall(dynamic_debug_init_debugfs);

2.4 pr_debug() 宏实现

/* include/linux/dynamic_debug.h */#ifdefCONFIG_DYNAMIC_DEBUG#definepr_debug(fmt,...)\do{\staticstruct_ddebug__aligned(8)\__section("__dyndbg")descriptor={\.modname=KBUILD_MODNAME,\.function=__func__,\.filename=__FILE__,\.format=(fmt),\.lineno=__LINE__,\.flags=_DPRINTK_FLAGS_DEFAULT,\};\if(unlikely(descriptor.flags&_DPRINTK_FLAGS_PRINT))\__dynamic_pr_debug(&descriptor,pr_fmt(fmt),\##__VA_ARGS__);\}while(0)#else#definepr_debug(fmt,...)no_printk(fmt,##__VA_ARGS__)#endif

工作原理:

  1. 每个pr_debug()编译时生成一个_ddebug结构
  2. 所有_ddebug放在特殊段__dyndbg
  3. 内核启动时收集所有_ddebug结构
  4. 通过 debugfs 控制flags字段
  5. 运行时检查flags决定是否打印

使用示例

驱动代码
/* drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c */intamdgpu_ring_init(structamdgpu_device*adev,structamdgpu_ring*ring,unsignedintmax_dw,structamdgpu_irq_src*irq_src){/* 这些 pr_debug 默认不输出 */pr_debug("Initializing ring %s\n",ring->name);pr_debug("Ring size: %u DWs\n",max_dw);/* ... 初始化逻辑 ... */pr_debug("Ring %s initialized successfully\n",ring->name);return0;}
运行时控制
# 启用该文件的所有 debug 输出$echo'file amdgpu_ring.c +p'>/sys/kernel/debug/dynamic_debug/control# 现在执行操作会看到 debug 信息$dmesg|tail[123.456]amdgpu: Initializing ring gfx[123.457]amdgpu: Ring size:1024DWs[123.458]amdgpu: Ring gfx initialized successfully# 禁用$echo'file amdgpu_ring.c -p'>/sys/kernel/debug/dynamic_debug/control

高级用法

# 按行号启用$echo'file amdgpu_ring.c line 123 +p'>control# 组合条件(文件 + 函数)$echo'file amdgpu_ring.c func amdgpu_ring_init +p'>control# 格式化标志$echo'module amdgpu +pflmt'>control# +p: 启用打印# +f: 包含函数名# +l: 包含行号# +m: 包含模块名# +t: 包含线程 ID# 使用通配符$echo'file amdgpu_* +p'>control $echo'func *_init +p'>control

性能影响分析

/* 关闭时的性能开销 */if(unlikely(descriptor.flags&_DPRINTK_FLAGS_PRINT))// 仅一次位测试__dynamic_pr_debug(&descriptor,...);// 不执行/* * unlikely() 提示:分支预测优化 * 位测试:极快的 CPU 操作 * 关闭时:几乎零开销(<1 纳秒) */

与其他调试方式对比

方式运行时控制性能开销灵活性需要重启
printk
Dynamic Debug极低
Ftrace极高
条件编译 (#ifdef)

学习要点

Dynamic Debug 展示了 DebugFS 的典型应用模式:

  1. 复杂的写操作

    • 解析用户命令
    • 应用配置到内核数据结构
    • 错误处理和验证
  2. 大量数据的读操作

    • 使用 seq_file 遍历内核数据
    • 格式化输出便于阅读
  3. 运行时控制内核行为

    • 无需重启或重新加载模块
    • 即时生效

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询