1. printk 速率限制
使用 printk_ratelimited()
c
复制代码
#include <linux/ratelimit.h>
// 基本用法
printk_ratelimited(KERN_INFO "Rate limited message: %d\n", value);
// 带自定义限制
static DEFINE_RATELIMIT_STATE(my_ratelimit, HZ, 10); // 每秒最多10条
if (__ratelimit(&my_ratelimit)) {
printk(KERN_INFO "Custom rate limited: %d\n", value);
}
2. 动态调试 (Dynamic Debug)
启用和控制动态调试
c
复制代码
// 在代码中使用 pr_debug()
pr_debug("Debug message: %s\n", debug_info);
// 内核配置需要 CONFIG_DYNAMIC_DEBUG
运行时控制
bash
复制代码
# 启用特定文件的调试
echo 'file driver.c +p' > /sys/kernel/debug/dynamic_debug/control
# 启用模块的调试
echo 'module mymodule +p' > /sys/kernel/debug/dynamic_debug/control
# 启用函数的调试
echo 'func my_function +p' > /sys/kernel/debug/dynamic_debug/control
# 限制频率 - 每10条打印一次
echo 'file driver.c =_' > /sys/kernel/debug/dynamic_debug/control
3. 条件编译调试
c
复制代码
#ifdef DEBUG
#define dbg_print(fmt, args...) \
printk(KERN_DEBUG "%s:%d: " fmt, __FILE__, __LINE__, ##args)
#else
#define dbg_print(fmt, args...)
#endif
// 或者使用自定义调试级别
#define MY_DEBUG 1
#if MY_DEBUG > 0
#define dbg_print printk
#else
#define dbg_print(fmt, args...)
#endif
4. 基于时间的频率控制
c
复制代码
#include <linux/jiffies.h>
static unsigned long last_print_time;
void conditional_print(const char *msg)
{
static unsigned long last_time;
unsigned long now = jiffies;
// 至少间隔 1 秒打印一次
if (time_after(now, last_time + HZ)) {
printk(KERN_INFO "%s\n", msg);
last_time = now;
}
}
// 或者使用 ktime
#include <linux/ktime.h>
static ktime_t last_print;
void debug_print_limited(const char *msg)
{
ktime_t now = ktime_get();
ktime_t diff = ktime_sub(now, last_print);
// 每100毫秒最多打印一次
if (ktime_to_ns(diff) > 100 * NSEC_PER_MSEC) {
printk(KERN_DEBUG "%s\n", msg);
last_print = now;
}
}
5. 计数限制
c
复制代码
static int print_count = 0;
#define MAX_PRINTS 100
void limited_debug(const char *msg)
{
if (print_count < MAX_PRINTS) {
printk(KERN_DEBUG "%s (print %d/%d)\n", msg, ++print_count, MAX_PRINTS);
}
}
6. 使用日志级别控制
c
复制代码
// 设置控制台日志级别
echo "6" > /proc/sys/kernel/printk
// 在代码中设置
console_loglevel = 6;
// 按级别条件打印
if (console_loglevel >= LOGLEVEL_DEBUG) {
printk(KERN_DEBUG "Debug message\n");
}
7. 完整的模块示例
c
复制代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/ratelimit.h>
static DEFINE_RATELIMIT_STATE(my_rs, HZ * 5, 5); // 5秒内最多5条
static int __init debug_init(void)
{
int i;
printk(KERN_INFO "Debug module loaded\n");
for (i = 0; i < 100; i++) {
// 方法1: 使用标准速率限制
printk_ratelimited(KERN_INFO "Standard rate limited: %d\n", i);
// 方法2: 自定义速率限制
if (__ratelimit(&my_rs)) {
printk(KERN_INFO "Custom rate limited: %d\n", i);
}
msleep(100);
}
return 0;
}
static void __exit debug_exit(void)
{
printk(KERN_INFO "Debug module unloaded\n");
}
module_init(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
8. 通过 procfs 或 sysfs 动态控制
c
复制代码
#include <linux/proc_fs.h>
static int debug_enable = 1;
static int debug_count = 0;
static ssize_t debug_enable_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
char buf[32];
if (copy_from_user(buf, buffer, min(count, sizeof(buf)-1)))
return -EFAULT;
debug_enable = simple_strtol(buf, NULL, 10);
debug_count = 0; // 重置计数
return count;
}
static void conditional_debug_print(const char *fmt, ...)
{
va_list args;
if (!debug_enable || debug_count >= 1000)
return;
va_start(args, fmt);
vprintk(fmt, args);
va_end(args);
debug_count++;
}
最佳实践建议
- 生产环境 :使用
printk_ratelimited()
或动态调试
- 开发阶段:使用条件编译或动态调试
- 性能敏感区域:基于时间的频率控制
- 内存调试:结合计数限制防止内存耗尽