一、顶级架构一句话总结
减少锁竞争 → 优化数据传输 → 降低系统调用 → 合理使用缓存
驱动性能优化是嵌入式和服务器开发的必修课,目标是降低延迟、提高吞吐量。
二、性能优化核心原则
优化优先级
| 层级 | 优化方式 | 收益 | 复杂度 |
|---|---|---|---|
| 算法层 | 选择合适的数据结构和算法 | 极高 | 中 |
| 架构层 | 减少锁竞争、使用per-cpu | 高 | 高 |
| 数据层 | DMA、零拷贝、批量传输 | 高 | 中 |
| 系统层 | 减少系统调用、合理缓存 | 中 | 低 |
三、锁竞争优化
1. 细粒度锁
// ❌ 粗粒度锁:整个设备用一把锁
struct device_data {
struct mutex lock;
u8 *tx_buffer;
u8 *rx_buffer;
int tx_count;
int rx_count;
};
// ✅ 细粒度锁:收发各用一把锁
struct device_data {
struct mutex tx_lock;
struct mutex rx_lock;
u8 *tx_buffer;
u8 *rx_buffer;
int tx_count;
int rx_count;
};
2. RCU(Read-Copy Update)
#include <linux/rcupdate.h>
struct config_data {
int param1;
int param2;
struct rcu_head rcu;
};
static struct config_data *global_config;
// 读端:使用rcu_read_lock()
int read_config(void)
{
int val;
rcu_read_lock();
val = rcu_dereference(global_config)->param1;
rcu_read_unlock();
return val;
}
// 写端:使用rcu_assign_pointer()
void update_config(int new_val)
{
struct config_data *old, *new;
new = kmalloc(sizeof(*new), GFP_KERNEL);
if (!new)
return;
rcu_read_lock();
old = rcu_dereference(global_config);
*new = *old; // 复制旧数据
new->param1 = new_val;
rcu_read_unlock();
rcu_assign_pointer(global_config, new);
synchronize_rcu(); // 等待所有读端完成
kfree(old);
}
3. Per-cpu变量
#include <linux/percpu.h>
// 定义per-cpu变量
DEFINE_PER_CPU(int, cpu_counter);
// 使用per-cpu变量
void increment_counter(void)
{
this_cpu_inc(cpu_counter); // 无锁操作
}
// 汇总所有cpu的值
int get_total_counter(void)
{
int total = 0;
int cpu;
for_each_possible_cpu(cpu) {
total += per_cpu(cpu_counter, cpu);
}
return total;
}
4. 自旋锁优化
// 使用spin_lock_irqsave()代替spin_lock_irq()
unsigned long flags;
spin_lock_irqsave(&lock, flags);
// 临界区
spin_unlock_irqrestore(&lock, flags);
// 读写锁:读多写少场景
#include <linux/rwlock.h>
rwlock_t rwlock;
void read_operation(void)
{
read_lock(&rwlock);
// 读操作
read_unlock(&rwlock);
}
void write_operation(void)
{
write_lock(&rwlock);
// 写操作
write_unlock(&rwlock);
}
四、数据传输优化
1. DMA(直接内存访问)
#include <linux/dma-mapping.h>
// 分配DMA一致性内存
void *dma_alloc_coherent(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag);
void dma_free_coherent(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle);
// 流式DMA映射
dma_addr_t dma_map_single(struct device *dev, void *ptr,
size_t size, enum dma_data_direction dir);
void dma_unmap_single(struct device *dev, dma_addr_t addr,
size_t size, enum dma_data_direction dir);
// 示例:使用DMA传输数据
struct device_data {
struct device *dev;
dma_addr_t dma_handle;
void *buffer;
size_t buffer_size;
};
int dma_transfer(struct device_data *data, void *src, size_t len)
{
dma_addr_t src_dma;
// 映射源地址
src_dma = dma_map_single(data->dev, src, len, DMA_TO_DEVICE);
if (dma_mapping_error(data->dev, src_dma))
return -ENOMEM;
// 启动硬件DMA
// hardware_start_dma(src_dma, data->dma_handle, len);
// 等待DMA完成
// wait_for_dma_complete();
// 取消映射
dma_unmap_single(data->dev, src_dma, len, DMA_TO_DEVICE);
return 0;
}
2. 零拷贝(Zero-Copy)
#include <linux/mm.h>
#include <linux/sched.h>
// 直接操作用户空间页面(避免拷贝)
int zero_copy_read(struct file *filp, char __user *buf,
size_t count, loff_t *pos)
{
struct page **pages;
int nr_pages;
int i;
// 锁定用户空间页面
nr_pages = (count + PAGE_SIZE - 1) >> PAGE_SHIFT;
pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
if (!pages)
return -ENOMEM;
down_read(¤t->mm->mmap_sem);
if (get_user_pages_fast((unsigned long)buf, nr_pages, 1, pages) != nr_pages) {
up_read(¤t->mm->mmap_sem);
kfree(pages);
return -EFAULT;
}
up_read(¤t->mm->mmap_sem);
// 直接操作页面,零拷贝
for (i = 0; i < nr_pages; i++) {
void *kaddr = kmap(pages[i]);
// 填充数据
memset(kaddr, 0xaa, PAGE_SIZE);
kunmap(pages[i]);
put_page(pages[i]);
}
kfree(pages);
return count;
}
3. 批量传输(Batch Processing)
// ❌ 每次传输一个字节
void transfer_byte(struct device_data *dev, u8 byte)
{
writeb(byte, dev->io_base + DATA_REG);
}
// ✅ 批量传输
void transfer_batch(struct device_data *dev, u8 *buf, size_t count)
{
int i;
// 启动批量传输
writel(count, dev->io_base + COUNT_REG);
// 使用 memcpy_toio() 批量写入
memcpy_toio(dev->io_base + DATA_FIFO, buf, count);
// 或者使用循环,但每次多写几个
for (i = 0; i < count; i += 4) {
writel(*(u32 *)(buf + i), dev->io_base + DATA_FIFO);
}
}
五、中断与延迟优化
1. Threaded IRQ
#include <linux/interrupt.h>
// 顶半部:快速处理
irqreturn_t hardirq_handler(int irq, void *dev_id)
{
struct device_data *dev = dev_id;
// 确认中断
writel(1, dev->io_base + INT_ACK);
// 禁用该中断
disable_irq_nosync(irq);
return IRQ_WAKE_THREAD;
}
// 底半部:可睡眠处理
irqreturn_t threadirq_handler(int irq, void *dev_id)
{
struct device_data *dev = dev_id;
// 处理数据(可以睡眠)
process_data(dev);
// 重新启用中断
enable_irq(irq);
return IRQ_HANDLED;
}
// 注册threaded irq
request_threaded_irq(irq, hardirq_handler, threadirq_handler,
IRQF_SHARED, "my_device", dev);
2. NAPI(New API)
#include <linux/netdevice.h>
struct my_napi_dev {
struct napi_struct napi;
struct net_device *netdev;
struct device_data *hw;
};
// NAPI poll函数
int my_napi_poll(struct napi_struct *napi, int budget)
{
struct my_napi_dev *dev = container_of(napi, struct my_napi_dev, napi);
int packets = 0;
while (packets < budget) {
struct sk_buff *skb;
skb = get_next_packet(dev->hw);
if (!skb)
break;
netif_receive_skb(skb);
packets++;
}
// 如果预算没用完,说明没有更多包了
if (packets < budget) {
napi_complete(napi);
// 重新启用硬件中断
enable_hw_interrupt(dev->hw);
}
return packets;
}
// 中断处理函数
irqreturn_t my_interrupt(int irq, void *dev_id)
{
struct my_napi_dev *dev = dev_id;
// 禁用硬件中断
disable_hw_interrupt(dev->hw);
// 调度NAPI
napi_schedule(&dev->napi);
return IRQ_HANDLED;
}
3. 工作队列与tasklet选择
// 低优先级、可睡眠:使用工作队列
#include <linux/workqueue.h>
struct device_data {
struct work_struct work;
};
void work_handler(struct work_struct *work)
{
struct device_data *dev = container_of(work, struct device_data, work);
// 可以睡眠的操作
msleep(10);
}
INIT_WORK(&dev->work, work_handler);
schedule_work(&dev->work);
// 高优先级、不可睡眠:使用tasklet
#include <linux/interrupt.h>
void tasklet_handler(unsigned long data)
{
struct device_data *dev = (struct device_data *)data;
// 快速操作,不可睡眠
process_data(dev);
}
DECLARE_TASKLET(my_tasklet, tasklet_handler, (unsigned long)dev);
tasklet_schedule(&my_tasklet);
六、内存管理优化
1. Slab缓存
#include <linux/slab.h>
static struct kmem_cache *my_object_cache;
struct my_object {
int data[100];
};
// 创建slab缓存
int __init my_cache_init(void)
{
my_object_cache = kmem_cache_create("my_object",
sizeof(struct my_object),
0, SLAB_HWCACHE_ALIGN, NULL);
if (!my_object_cache)
return -ENOMEM;
return 0;
}
// 分配对象
struct my_object *alloc_object(void)
{
return kmem_cache_alloc(my_object_cache, GFP_KERNEL);
}
// 释放对象
void free_object(struct my_object *obj)
{
kmem_cache_free(my_object_cache, obj);
}
2. 内存池(Memory Pool)
#include <linux/mempool.h>
static mempool_t *my_mempool;
struct my_object {
int data[100];
};
void *my_alloc(gfp_t gfp_mask, void *pool_data)
{
return kmalloc(sizeof(struct my_object), gfp_mask);
}
void my_free(void *element, void *pool_data)
{
kfree(element);
}
int __init my_mempool_init(void)
{
// 创建内存池,预分配16个对象
my_mempool = mempool_create(16, my_alloc, my_free, NULL);
if (!my_mempool)
return -ENOMEM;
return 0;
}
// 从内存池分配(保证成功)
struct my_object *mempool_alloc_object(void)
{
return mempool_alloc(my_mempool, GFP_KERNEL);
}
// 释放回内存池
void mempool_free_object(struct my_object *obj)
{
mempool_free(obj, my_mempool);
}
3. 页高速缓存(Page Cache)
#include <linux/pagemap.h>
#include <linux/fs.h>
// 实现address_space_operations
static int my_readpage(struct file *file, struct page *page)
{
struct address_space *mapping = page->mapping;
struct inode *inode = mapping->host;
// 从硬件读取数据到page
void *kaddr = kmap(page);
read_from_hardware(inode->i_ino, kaddr, PAGE_SIZE);
kunmap(page);
SetPageUptodate(page);
unlock_page(page);
return 0;
}
static const struct address_space_operations my_aops = {
.readpage = my_readpage,
};
// 在open时设置
int my_open(struct inode *inode, struct file *file)
{
inode->i_mapping->a_ops = &my_aops;
return 0;
}
七、系统调用优化
1. ioctl vs sysfs
// ❌ 频繁的ioctl调用
int user_app_configure(void)
{
int fd = open("/dev/mydev", O_RDWR);
ioctl(fd, MYDEV_SET_PARAM1, 100);
ioctl(fd, MYDEV_SET_PARAM2, 200);
ioctl(fd, MYDEV_SET_PARAM3, 300);
ioctl(fd, MYDEV_SET_PARAM4, 400);
close(fd);
}
// ✅ 批量配置的ioctl
struct mydev_config {
int param1;
int param2;
int param3;
int param4;
};
int user_app_configure_batch(void)
{
int fd = open("/dev/mydev", O_RDWR);
struct mydev_config cfg = {100, 200, 300, 400};
ioctl(fd, MYDEV_SET_CONFIG, &cfg);
close(fd);
}
// ✅ 使用sysfs(适合配置参数)
// 内核驱动中
static ssize_t param1_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct device_data *data = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", data->param1);
}
static ssize_t param1_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct device_data *data = dev_get_drvdata(dev);
sscanf(buf, "%d", &data->param1);
return count;
}
static DEVICE_ATTR_RW(param1);
// 用户空间
void config_with_sysfs(void)
{
int fd = open("/sys/class/mydev/mydev0/param1", O_WRONLY);
write(fd, "100", 3);
close(fd);
}
2. mmap减少数据拷贝
#include <linux/mm.h>
static int my_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct device_data *dev = filp->private_data;
unsigned long size = vma->vm_end - vma->vm_start;
if (size > dev->buffer_size)
return -EINVAL;
// 映射DMA缓冲区到用户空间
if (remap_pfn_range(vma, vma->vm_start,
virt_to_phys(dev->buffer) >> PAGE_SHIFT,
size, vma->vm_page_prot)) {
return -EAGAIN;
}
return 0;
}
// 用户空间使用
void user_app_mmap(void)
{
int fd = open("/dev/mydev", O_RDWR);
void *buf = mmap(NULL, 4096, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
// 直接读写缓冲区,零拷贝
memset(buf, 0x55, 4096);
munmap(buf, 4096);
close(fd);
}
八、性能分析工具
1. ftrace
# 查看可用的tracer
cd /sys/kernel/debug/tracing
cat available_tracers
# 使用function_graph tracer
echo function_graph > current_tracer
echo 1 > tracing_on
# 运行测试程序
./test_program
# 查看跟踪结果
cat trace
echo 0 > tracing_on
2. perf
# 性能计数
perf stat ./test_program
# 性能采样
perf record -g ./test_program
perf report
# 查看内核函数性能
perf record -e cycles:k -a -g sleep 1
perf report
3. /proc文件系统
# 中断统计
cat /proc/interrupts
# 内存使用
cat /proc/meminfo
cat /proc/slabinfo
# 软中断统计
cat /proc/softirqs
# 调度统计
cat /proc/sched_debug
九、终极总结
驱动性能优化 = 找准瓶颈 + 针对性优化
- 锁优化:细粒度锁、RCU、per-cpu、读写锁
- 数据传输:DMA、零拷贝、批量传输
- 中断处理:threaded irq、NAPI、workqueue/tasklet选择
- 内存管理:slab、mempool、page cache
- 系统调用:减少调用次数、mmap、sysfs
- 性能分析:ftrace、perf、/proc文件系统
没有最快,只有更快!持续优化,持续进步!
2914



被折叠的 条评论
为什么被折叠?



