赞
踩
总结了一些关于性能方面的知识/经验,跟大家分析下。
欢迎大家在评论进行补充(我会按照补充添加)。
希望大家点赞收藏
(1) 尽量Cache命中
(2) 使用数据缓存
如果某些数据被频繁访问,考虑将它们缓存在更快的存储介质中,如CPU缓存或寄存器
在某些情况下,使用内存池或对象池可以避免频繁的内存分配和释放,从而提高性能
概念1: 存储金字塔
** 越靠近 CPU 速度越快,容量越小,价格越贵
** 每一种存储器设备只和它相邻的存储设备打交道 比如,CPU Cache 是从内存里加载而来的,或者需要写回内存,并不会直接写回数据到硬盘,也不会直接从硬盘加载数据到 CPU Cache 中,而是先加载到内存,再从内存加载到 Cache 中。
概念2: 高速缓存-Cache
** CPU和内存之间速度严重不匹配的问题,在CPU和内存之间设计了高速缓存,即Cache。
CPU读取数据时,会在L1、L2、L3Cache中逐级查找,如果找到,就从Cache直接读取,找不到再从内存读取,并且把数据存放到Cache中,以便提高下次访问的效率。
在这个过程中,如果在Cache中找到所需数据,称为Cache命中(Cache Hit), 找不到称为Cache未命中(Cache Miss)。
L1 Cache命中的时候,读取数据最快,性能最好,而当L1、L2、L3 Cache全部未命中时,就必须要直接从内存中读取数据,性能最差
概念3: 局部性原理
** 时间局部性。如果一个数据在某个时间点被CPU访问了,那么在接下来很短的一段时间内,这个数据很有可能会再次被CPU访问到。
** 空间局部性。如果一个数据在某个时间点被CPU访问了,那么与这个数据临近的其他数据,很有可能也会很快被CPU访问到。
概念4: 缓存行-Cache Line
** 根据 局部性原理 如果一个数据被CPU访问了,那么这个数据相邻的其他数据也很快会被访问到。因此,为了提高内存数据的读取效率,并且最大化利用CPU资源,数据在Cache和内存之间传输时,不是一个字节一个字节进行传输的,而是以缓存行(Cache Line)为单位进行传输的。
(3) 数据结构优化
设计/选择 合适的数据结构和算法,避免不必要的数据复制和遍历。选择合适的数据结构可以减少内存访问次数和数据移动操作。
(4) 尽量确保内存对齐
大多数现代处理器在访问未对齐的内存时,性能会下降。这是因为处理器通常一次从内存中读取或写入多个字节(例如,4字节、8字节等),如果数据未对齐,处理器可能需要多次访问内存来获取或存储数据,这被称为“未对齐访问”或“跨边界访问”。因此,内存对齐可以显著提高数据访问的性能。
(5) 考虑使用内联函数
将那些短小的、频繁调用的函数声明为内联函数
(1) 使用引用或指针传递参数 或 做为返回值
(2) 使用零拷贝技术
(3) 使用合理的数据结构
合理设计数据结构可以减少内存拷贝。例如,使用连续存储的数组而不是链表,可以减少访问和拷贝的开销。
(4) 避免容器扩容
选择好需使用容器后(如std::vector), 尽量通过resize、reserve来提前分配好内存, 来避免或 减少 扩容次数。 (经实测小数据对象下(如int)reserve后一个个去赋值 快于resize后一个个 push_back, 可能是因为push_back多了很多单次修改std::vector成员属性, 校验等…)
(5) 避免不必要的临时对象
在函数调用或表达式求值过程中,尽量减少临时对象的创建。这可以通过使用const引用参数、返回值优化等技术来实现
(1) 合理进行程序设计 找出最优解决方案
(2) 使用更高效的算法和数据结构
(3) 使用缓存机制
使用变量存储中间结果,避免在循环中重复计算相同的表达式。使用记忆化技术或缓存机制,特别是在递归算法中.
(1) Valgrind
主要用于内存泄漏检测,但它的工具集中的Callgrind可以用于性能分析。
(2) gprof
GNU Profiler 是一个标准的UNIX/Linux命令行性能分析工具,输出程序的调用图和执行时间统计。
(3) perf
Linux性能计数器工具,可以分析CPU性能计数器和程序事件,如缓存未命中、分支预测错误等。
(4) Intel VTune Profiler
一款功能强大的性能分析工具,适用于Intel处理器,提供了详细的硬件级别性能数据。
(5) Visual Studio Profiler
Visual Studio集成了性能分析工具,可以在Windows平台上进行性能分析和调试。
(6) Very Sleepy
一个Windows平台上的C/C++ CPU性能分析工具,可以分析函数调用次数和时间消耗。
(7) AQtime
一款商业性能分析工具,支持多种编程语言和开发环境,提供详细的性能报告。
(8) AMD uProf
AMD uProf是AMD的性能分析工具,提供了对CPU性能事件的分析。
(9) Google’s CPU Profiler
部分Google性能工具套件(gperftools),可以用来记录和分析程序的CPU使用情况
(1) GCC和Clang
-O0:不进行优化,编译速度最快,适用于调试。
-O1:开启基本优化,编译器会尝试减少代码大小和执行时间,而不会显著增加编译时间。
-O2:开启进一步优化,比-O1更激进,包括所有不涉及空间-时间权衡的优化。
-O3:启用-O2中的所有优化,并添加更多优化,如更积极的循环优化和内联函数。
-Os:优化代码大小,可能会牺牲一些执行速度。
-Ofast:启用所有-O3优化,并启用一些可能不遵守严格标准兼容性的优化策略。
-flto:启用链接时优化,允许在链接时进行更多的优化。
(2) Microsoft Visual C++(MSVC):
/Od:禁用优化,适合调试。
/O1, /O2:对应于GCC和Clang中的-O1和-O2。
/Ox:使用最大优化(相当于-O2或-O3)。
/Ot:优先优化速度。
/Os:优先优化大小。
/Oy:省略帧指针。
/GL:启用全程序优化。
(4) Intel C++ Compiler
类似于GCC和Clang的优化选项,但还提供一些特定于Intel处理器的优化选项。
用于多处理器系统,其中每个处理器都有自己的本地内存。处理器可以访问本地内存比访问远程内存(属于其他处理器的本地内存)更快
(1) 改进的内存访问性能:
通过将线程和内存分配给特定的NUMA节点,可以减少对远程内存的访问,从而减少访问延迟,提高内存访问速度。
(2) 高度并行性:
NUMA架构允许多个处理器同时访问多个内存节点,增加了系统的并行处理能力,这对于并行计算和多线程应用程序来说是非常重要的。
(3) 提高大型多核系统的效率:
对于拥有大量核心的系统,NUMA架构有助于减少每个核心在内存访问时的争用,因为每个核心能够更频繁地访问本地内存。
(1) 最小化锁的使用:
只在绝对必要的时候使用锁。尽量减少锁的粒度,只保护临界区,即实际需要同步的最小代码块。
(2) 避免锁竞争:
尽量设计无锁的数据结构或算法。
使用局部变量代替共享变量,减少需要锁定的资源。
将数据分解为更小的块,以减少不同线程之间的竞争。
(3) 使用自旋锁:
对于持锁时间非常短的场景,使用自旋锁可能比互斥锁(mutex)效率更高,因为自旋锁避免了线程上下文切换的开销。
(4) 读写锁(共享-独占锁):
当读操作远多于写操作时,使用读写锁可以提高性能。读写锁允许多个读线程同时访问资源,但写线程会独占锁。
(5) 分离互斥:
如果可能,将数据结构分离,使不同的线程操作不同的锁,从而减少锁的争用。
(6) 锁分级:
使用分级锁来减少死锁的可能性,并提高锁的性能。
(7) 条件变量:
结合互斥锁使用条件变量,只在必要时挂起和唤醒线程,减少不必要的锁争用。
(8) 锁粗化:
如果频繁地锁定同一资源,考虑将多个操作合并为一个大的锁定区域(锁粗化),以减少锁的开销。
(9) 避免长时间持锁:
尽量不要在持有锁的时候进行I/O操作、计算密集型任务或者可能导致线程挂起的操作。
(1) 使用亲和性绑定:
(线程核心绑定) 将线程绑定到特定的处理器核心上,这样可以减少线程在不同核心间迁移,从而减少缓存失效和上下文切换。
(2) 减少线程数量:
尽量使用不多于处理器核心数的线程。过多的线程会导致频繁的上下文切换,增加开销。
(3) 使用线程池:
线程池可以复用一组线程来执行多个任务,减少线程创建和销毁的开销。
(4) 避免过度同步:
多线程合理使用锁,尽量避免不必要的同步,以减少因等待锁而导致的线程挂起和切换。
(5) 合理分配任务:
尽量将任务合理分配给线程,使线程可以持续工作一段时间,避免频繁的任务切换。
(6) 使用工作窃取策略:
对于任务并行库,可以减少线程间的同步,从而减少切换。
(7) 避免长时间的阻塞操作:
尽量减少线程执行I/O操作或其他可能导致线程阻塞的操作。可以使用异步I/O或将I/O操作分离到特定的I/O线程。
(8) 合理设置线程优先级:
谨慎设置线程优先级,以防止优先级倒置或饿死问题。
(9) 减少虚假唤醒:
使用条件变量时,减少不必要的唤醒操作。
(10) 使用并发数据结构:
使用无锁或者低锁的并发数据结构,如C++11中的std::atomic和std::concurrent_queue。
(11) 避免昂贵的操作:
在锁定资源时,避免在临界区内进行昂贵的操作,如内存分配或复杂的计算。
冲突包含
(1)数据冲突(Data Hazard) 数据间依赖
(2)控制冲突(Control Hazard) 遇到分支跳转 无法预测
(3)结构冲突(Structure Hazard) 多条指令同时竞争同一个硬件资源
需要你做的(编译器也会帮你做)
不需要你做的, 但需要你了解贴合 (由系统、CPU架构、硬件支持)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。