C++编程实践—操作系统调优和内核旁支

一、C++高性能应用

C++开发的软件现在基本已经退至了高性能应用为主的场景中去。包括一些底层框架包括分析过的DPDK、虚拟机中,都实现了各种不同的优化,甚至是驱动层给的优化。而在大规模的网络并发应用中,这种情况更是常见。

通过上述文章的分析,已经知道为什么开发者和设计者要孜孜不倦的压缩性能的极限,一个重要原因就是性能只有更高没有最高的要求。

二、操作系统调优

在前面分析网络高并发时,曾经对内核中的相关配置进行了大量的修改。DPDK中也对CPU核心进行绑定处理。诸如此等,其实在操作系统中调优的方法有很多,下面分别进行整体上的说明:

  1. CPU核心绑定(独占CPU核心)
    核心绑定其实是一把双刃剑,从理论上讲这样就会整体的处理速度即吞吐量。但在网络处理和高频交易时,绑定还是具有明显的优势的。但不要迷信核心绑定,啥需求都绑定一下,这反而会画虎不成。这里的重点是为什么要进行核心绑定?这个在前面的DPDK等系列中有分析,不明白的可以翻看或自行查找其它资料。至于绑定方法非常简单,可以通过配置文件也可以使用C++代码来实现。前面有过说明此处不再重复

  2. 中断重定向
    说白了就是中断的能力太大,它可能把正在处理关键任务的进程打断,导致任务的处理速度下降,甚至产生任务迁移。引发进一步的缓存等的链锁反应。那就谈不上性能了。所以要把重要运行的核心上的相关中断重定向其它非重要的核心上。修改方法有启动时和运行时两种方式,下面给出一个:

    复制代码
    echo {mask} > /proc/irq/{irq_num}/smp_affinity
  3. 内核调度隔离
    其实不要认为进行了CPU核心的绑定,它就不会进行切换了。内核中的线程权限很高,它仍然有可能不管不顾的调度到绑定的核心。结果就是同样会降低性能。解决的方法也很简单,进行内核调度的隔离.下面看一个具体的例子:

    复制代码
    GRUB_CMDLINE_LINUX_DEFAULT="quiet splash isolcpus=2,3 nohz_full=2,3 rcu_nocbs=2,3 irqaffinity=0-1"
  4. 内存的绑定
    在前面分析过NUMA多核中内存的处理,为了保证性能就要保证数据处理时的连续性而不能让数据访问不断的跨NUMA节点,加大内存的访问延迟。可以使用命令也可以使用代码来实现。下面看代码的实现:

    c++ 复制代码
    #include <numa.h>
    numa_set_localalloc();  
    void* localMem = numa_alloc_local(1024);
  5. 内存的预取
    内存预取则是各种性能优化的少不得的选择。像前面分析CUDA时就有这方面的接口。但在应用编程中可以使用"__builtin_prefetch"函数来实现内存的预取

  6. 内存的锁定
    即不使用交换内存,在DPDK中分析过,减少内存访问延迟的方法之一,尽量减小内存页的换来换去。特别是防止内存页交换到磁盘。它可从系统和用户两个角度来实现。下面看系统的处理:

    复制代码
     sudo sysctl -w vm.lock_limit_kb=102400  #100M 
     echo "vm.lock_limit_kb=102400" >> /etc/sysctl.conf
    
     # 禁止交换
     swapoff -a
  7. 大页内存
    大页内存太重要了,它其实是和内存预取、锁定等一起协同应用更好。大页内存的优势在于降低TLB的未命中的可能性。前面的有专门的分析,可供参考

  8. 缓存隔离
    这种方法的目的是为了降低缓存的竞争,本质仍然是提高数据的访问速度进而提高整体的性能。Intel提供了缓存分配技术(Cache Allocation Technology,CAT)其配置方法稍显复杂,此处不再给出例子。有兴趣可以去网上查找相关的应用方法

  9. SIMD
    这才是真正的大杀器,前面反复分析过。单指令多数据流,包括在GPU编程中,都会应用到这项技术。

通过上述的系统优化,基本说明了现在高性能应用项目的常见的调优方式。

三、内核旁支

Kernel Bypass,内核旁支或内核旁路。在前面分析过零拷贝技术和DMA技术,可以通过某种方式减少内核中对数据处理的流程。说通俗一些就是减少处理问题的环节,理论上讲一定会提高性能。在DPDK的分析中,可以看到对这种方式的大量使用。如果在系统优化后仍然要精益求精,内核旁支就该上场了。主流的内核旁路目前主要有两类,也是针对目前高性能开发的痛点的即网络旁路和存储旁路。

其实现的方法主要有:

  1. eBPF
    这个等于是内核向外开的一个接口钩子,前面分析过的XDP,TC等就可以实现相关的旁路处理
  2. Netmap
    它是一个网络旁路的实现,通过驱动API的重映射来实现网络包的生成和过滤。
  3. io_uring
    看过前面的文章的可以知道这是一个专门处理数据存储的内核旁支,不过现在也支持网络了
  4. DPDK
    这个就不展开说了,前面按系列分析了那么多。网络旁路的实现。

四、二者的关系

其实它们两个是相辅相成,共同协作来完成高性能开发和调优的。对大多数开发者来说,系统优化可能还经常听说或使用;而内核旁支则很少听,用就可能更少了。

系统优化强调的是确定性的处理,减少对性能操作污染的风险,提高进(线)程执行的稳定性和连续性。而内核旁支侧负责对数据通路进行压缩,最大程度减少数据流通的环节,可以理解为路径优化,它是一种暴力裁剪。

五、总结

本文做一个对C++整体的底层优化的说明分析,回看这一大段时间以来为实现高性能的开发,如何通过各种方式对系统及相关驱动进行不断的反复的优化的情况。这种对极致性能的追求,是大规模并发应用(如IM、高频量化交易系统等)天然需求。如果想真正的体会到C++的魅力,其实就是在这些具体的应用中才能够真正的感受得到。

相关推荐
小碗羊肉2 小时前
【从零开始学Java | 第十八篇】BigInteger
java·开发语言·新手入门
宵时待雨2 小时前
C++笔记归纳14:AVL树
开发语言·数据结构·c++·笔记·算法
执笔画流年呀2 小时前
PriorityQueue(堆)续集
java·开发语言
山川行2 小时前
关于《项目C语言》专栏的总结
c语言·开发语言·数据结构·vscode·python·算法·visual studio code
呜喵王阿尔萨斯2 小时前
C and C++ code
c语言·开发语言·c++
旺仔.2912 小时前
顺序容器:deque双端队列 详解
c++
左左右右左右摇晃2 小时前
JDK 1.7 ConcurrentHashMap——分段锁
java·开发语言·笔记
xcLeigh2 小时前
Python入门:Python3基础练习题详解,从入门到熟练的 25 个实例(六)
开发语言·python·教程·python3·练习题
烤麻辣烫3 小时前
I/O流 基础流
java·开发语言·学习·intellij-idea
Jasonakeke3 小时前
我的编程来时路
java·c++·python