尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

深入理解Linux内核--系统调用,性能优化

深入理解Linux内核--系统调用,性能优化 1.系统调用基础架构1.1.系统调用入口系统调用是用户态进入内核态的唯一受控通道。在 x86_64 架构下用户态通过 syscall 指令触发替代了旧版的 int 0x80系统调用号存放在 rax 寄存器如 read 是 0write 是 1入口点entry_SYSCALL_64位于 arch/x86/entry/entry_64.S1.2.完整调用路径用户程序 → glibc 封装 → syscall 指令 → CPU 特权级切换(Ring3→Ring0)→ entry_SYSCALL_64 → do_syscall_64 → 系统调用表(sys_call_table)→ 具体内核函数 → 返回用户态2.参数传递机制2.1.寄存器传参x86_64寄存器用途rax系统调用号rdi第 1 个参数rsi第 2 个参数rdx第 3 个参数r10第 4 个参数注意不是 rcx因为 rcx 被 syscall 指令占用r8第 5 个参数r9第 6 个参数示例read(fd, buf, count) 调用时mov rax,0# __NR_read mov rdi,fd mov rsi,buf mov rdx,count syscall2.2.参数超过 6 个怎么办结构体指针将多余参数打包成结构体传递指针不常见Linux 系统调用设计原则上不超过 6 个参数3.返回值处理3.1.返回值规范成功返回值通过 rax 传回用户态错误返回负的错误码如 -EINVAL即 -22glibc 转换glibc 将负错误码转为正数存入 errno并返回 -13.2.内核中的返回路径// 内核态系统调用函数签名示例SYSCALL_DEFINE3(read,unsignedint,fd,char__user*,buf,size_t,count){// 返回实际读取的字节数或负错误码returnretval;}3.3.错误码映射内核返回用户态 errno含义-EPERM1操作不允许-ENOENT2无此文件-EAGAIN11资源暂时不可用-ENOMEM12内存不足-EINVAL22无效参数4.用户态/内核态内存访问4.1.核心问题地址空间隔离用户态每个进程独立的虚拟地址空间0~128TB内核态高地址空间128TB~256TB所有进程共享内核页表风险内核直接解引用用户态指针可能导致崩溃或安全漏洞4.2.安全拷贝接口copy_from_user / copy_to_user// 从用户空间拷贝到内核空间unsignedlongcopy_from_user(void*to,constvoid__user*from,unsignedlongn);// 从内核空间拷贝到用户空间unsignedlongcopy_to_user(void__user*to,constvoid*from,unsignedlongn);返回值未成功拷贝的字节数0 表示完全成功SYSCALL_DEFINE2(my_syscall,char__user*,user_buf,size_t,len){char*kernel_buf;kernel_bufkmalloc(len,GFP_KERNEL);if(!kernel_buf)return-ENOMEM;// 安全拷贝处理缺页、权限检查if(copy_from_user(kernel_buf,user_buf,len)){kfree(kernel_buf);return-EFAULT;// 用户地址无效}// ... 处理数据 ...if(copy_to_user(user_buf,kernel_buf,len)){kfree(kernel_buf);return-EFAULT;}kfree(kernel_buf);return0;}4.3.其他访问辅助函数函数用途get_user(x, ptr)从用户空间读取基本类型1/2/4/8 字节put_user(x, ptr)向用户空间写入基本类型strncpy_from_user安全拷贝用户态字符串clear_user清零用户空间内存access_ok(addr, size)检查用户地址是否合法不检查页表映射5.性能优化策略5.1.减少系统调用次数批量操作优于多次单操作// 差1000 次 write 调用 1000 次上下文切换for(i0;i1000;i)write(fd,bufi,1);// 优1 次 write 调用write(fd,buf,1000);实际应用writev/readv一次调用传输多个不连续缓冲区sendfile内核态直接文件到 socket 拷贝零用户态参与splice管道与文件/socket 间的零拷贝传输5.2.零拷贝技术 (Zero-Copy)sendfile 系统调用sendfile(out_fd,in_fd,offset,count);数据从文件页缓存直接拷贝到 socket 缓冲区省去磁盘 → 内核页缓存 → 用户缓冲区 → 内核 socket 缓冲mmap writebufmmap(NULL,len,PROT_READ,MAP_PRIVATE,fd,0);write(socket_fd,buf,len);文件内容映射到用户地址空间省去 read 的数据拷贝但仍有一次 write 的系统调用开销5.3.vDSO (Virtual Dynamic Shared Object)机制将部分高频系统调用如 gettimeofday、clock_gettime映射到用户态共享库效果无需进入内核态直接读取内核更新的内存页适用只读且无需内核实时参与的操作5.4.批量系统调用io_uringLinux 5.1 引入的高性能异步 I/O 接口// 提交一批请求一次系统调用structio_uring_sqe*sqeio_uring_get_sqe(ring);io_uring_prep_read(sqe,fd,buf,len,offset);io_uring_submit(ring);// 一次 syscall 提交多个操作优势批量提交/收割摊平系统调用开销支持轮询模式IORING_SETUP_IOPOLL完全绕过系统调用性能接近 DPDK/SPDK但保持内核安全性5.5.内核内部优化技术原理per-CPU 变量避免缓存行 bouncing减少锁竞争RCU 读路径读操作无锁零开销遍历链表/树Slab 分配器对象缓存减少内存分配碎片页缓存预读顺序读取时异步预加载下一页直接 I/O (O_DIRECT)绕过页缓存适合数据库等自缓存应用5.6.上下文切换开销优化系统调用本身开销约 100~300ns现代 CPU主要成本特权级切换Ring3→Ring0→Ring3寄存器保存/恢复优化方向使用 io_uring 将多次 I/O 合并为一次提交使用 epoll/io_uring 替代 select/poll减少每次等待的系统调用用户态轮询如 io_uring 的 polling 模式6.总结速查维度关键点传参x86_64 用rdi/rsi/rdx/r10/r8/r9系统调用号在rax返回值内核返负错误码glibc 转errno成功值在rax内存访问必须用copy_*_user用户指针标记__user性能核心减少切换次数 零拷贝 批量提交 vDSO 捷径
返回列表