请注意,本文不是讲解处理器缓存,如果你对cpu cache这个概念不清楚,请先Google一下。
另外,本文主要针对像 C,C++ 这种产生机器码的语言的,对于像 Java,.Net 这样的字节码语言,这里所说的可能无效,至少我没研究过。
首先说说我所说的这些旧有的优化技巧从哪里来的。
原因很简单,如果你像我一样,多年只用 J2ME,或者 Flash 这样的技术开发,你是不太可能会关心处理器缓存的,而是用一些其它的性能技巧,这些技巧遇到处理器缓存问题,就失效了。
再如果你的CPU,汇编,优化知识像我一样仍停留在 80386 时代,你我掌握的优化技巧断然也是过时的。
失效技巧一,使用预先计算好的变量或者查找表
现在来怎么用查找表来计算一个32位整数里位为1的个数。
static const unsigned char BitsSetTable256[256] =
{
// 预先计算好的256个8位数的1的个数
};
int calculateBitsCount(unsigned int n)
{
unsigned char * p = (unsigned char *)&n;
return BitsSetTable256[p[0]] +
BitsSetTable256[p[1]] +
BitsSetTable256[p[2]] +
BitsSetTable256[p[3]];
}
很酷,是吧,只用了四次加法运算,我们可以想当然地认为这个算法比那些充满乘除法甚至循环的算法快。
但当有了CPU的数据缓存,情况不一样了。当 calculateBitsCount 第一次取 BitsSetTable256
数据,很有可能导致数据缓存清空重新加载 BitsSetTable256
位置的内存,会导致浪费上百指令周期,而这上百指令周期,足够用普通方法计算位数了。
比如下面这个算法,来自
http://graphics.stanford.edu/~seander/bithacks.html
unsigned int v; // count the number of bits set in v
unsigned int c; // c accumulates the total bits set in v
for (c = 0; v; c++)
{
v &= v - 1; // clear the least significant bit set
}
这个算法看似比上面查找表算法多了很多指令,还有循环,但要记住指令成本比数据成本低非常非常多(指令数量很多超出指令缓存的除外),值票价!确实值票价,因为我用这个算法替代查找表以后,确实快了。
失效技巧二,用局部变量来缓存所操作对象的成员变量
请注意,这个技巧在大多数情况下是有效的,这里只是说明某些情况下会失效。
比如有这样一个函数,
void func(SomeObject * obj)
{
int i, k, p;
int count = obj->getCount();
for(i = 0; i < 100; ++i) {
for(int k = 0; k < 100; ++k) {
for(int p = 0; p < count; ++p) {
// 处理 obj 的数据
}
}
}
}
假设 getCount 只是取一个数值。
这看起来很好,很完美,但仔细看却有一个问题。假如所有局部变量都能被放在寄存器,没有问题。但如果 count 不能被放到寄存器里呢?那么每次循环
count 都要从堆栈内存里读取,但同时又要处理 obj 的数据,这两部分极有可能不在一个数据缓存里,这就会导致频繁的数据缓存交换,慢!
如果抛弃 count,而把最内层循环改成
for(int p = 0; p < obj->getCount(); ++p) {
// 处理 obj 的数据
}
因为读取的数据都在 obj 范围内,如果都在数据缓存范围里,那就会相当快。
失效技巧三,在一个循环里干所有事
我们可能老觉得循环是慢的,因为还要跳转,所以我们宁愿在一个循环里把所有事都做了。
ObjectA * objA;
ObjectB * objB;
for(int i = 0; i < 100; ++i) {
// 对 objA 做点事
// 对 objA 做点别的事
// 对 objB 做点事
}
这有两个问题:
1,一旦循环体里的代码长度超过指令缓存,那么每次循环都要导致指令缓存动荡,无论 CPU 有几级缓存,L1 被清空重新装载,总归比直接命中 L1 缓存慢。
2,更麻烦的事,循环里在两个数据块操作,除非两个对象恰好分配的很近,否则必然导致数据缓存的动荡,慢。
如果把循环切分,
ObjectA * objA;
ObjectB * objB;
for(int i = 0; i < 100; ++i) {
// 对 objA 做点事
}
for(int i = 0; i < 100; ++i) {
// 对 objA 做点别的事
}
for(int i = 0; i < 100; ++i) {
// 对 objB 做点事
}
则指令缓存和数据缓存都会觉得很高兴,自然也就工作快一点了。
总结:
虽然上面这些技巧会失效,并不意味这些技巧是错的,很多情况下也可能真的有效。而且处理器缓存这东西优化起来不定因素很大,并无不变之规,所以具体做时还要仔细测试,方能知道哪种方法好。
分享到:
相关推荐
《面向异构融合处理器的性能分析、优化及应用综述》这篇文章主要探讨了在现代计算机领域中,异构融合处理器的性能分析、优化及其广泛应用。随着异构计算技术的不断进步,CPU和GPU等不同类型的处理器集成在一起,形成...
基于数据预取的多核处理器末级缓存优化方法可以有效地提高多核处理器的性能,提高系统的整体性能。本文的方法和结果可以作为参考文献和指导,帮助研究生和研究人员更好地研究和应用多核处理器技术。
在《面向Blackfin®处理器的C语言编程及优化》这门课程中,主要内容围绕ADI公司的Blackfin系列处理器及其相关的C语言编程技巧与优化方法展开。Blackfin处理器作为一款高度集成的混合信号处理器,结合了强大的DSP能力...
【缓存与CPU:解析处理器缓存的作用】 ...缓存的分级策略进一步优化了数据查找过程,确保了CPU性能的发挥。因此,缓存的大小和配置已成为衡量CPU性能的重要参考指标,对于理解和选择适合的处理器至关重要。
标题中的"E5超大三级缓存处理器"指的是Intel的Xeon E5系列处理器,这是一个针对服务器和工作站市场的高性能CPU系列。这些处理器以其巨大的三级缓存而闻名,旨在提高多线程工作负载的效率,通过存储频繁访问的数据来...
在现代计算机系统中,高速缓存(Cache)是提高处理器性能的关键组件,它通过存储频繁访问的数据来减少处理器与主内存之间的数据交换时间。本文将深入探讨CMT(Chip Multi-Threading,芯片多线程)处理器中的高速缓存...
缓存利用率是另一个重要因素,通过优化索引设计以适应处理器的缓存层次结构,可以显著提升性能,减少数据在主存和缓存之间频繁移动导致的性能瓶颈。 当前,内存索引面临着诸多挑战和机遇。随着多核心处理器和分布式...
《基于多核处理器的程序性能优化方法》这篇文章探讨了在多核处理器环境下,如何通过优化技术提升程序的执行效率和性能。多核处理器是解决单核处理器时钟频率提升困难的有效途径,它在一个芯片上集成多个处理器核心,...
在详细讨论高速缓存一致性协议设计的关键问题时,本文从程序访存行为模式、目录组织结构、一致性粒度、一致性协议流量、目录协议的可扩展性等方面阐述了近年来缓存一致性协议性能优化的 方向。同时,本文还对当前片...
性能优化方法和技巧 性能优化是软件开发中非常重要的一部分,它关注系统的控制流程和数据流程、算法的选择和优化、代码的执行顺序和缓存相关的优化等多个方面。性能优化的目的是提高系统的性能,减少系统的负载,...
本文主要探讨了面向大数据应用的众核处理器缓存结构设计,针对大数据应用在多核/众核处理器上运行时资源利用率低下,一级缓存命中率高但二级和三级缓存命中率低的问题,提出了一种新的优化方案。文章首先指出,大...
CPU缓存失效是一个可能导致计算机性能显著下降的问题,尤其是在运行依赖CPU处理能力的旧版3D游戏时。本文通过一个实例,讲述了如何诊断和解决由主板BIOS损坏导致的CPU缓存失效问题。 案例中,一台配置为Athlon XP ...
这项工作不仅为多核处理器的缓存优化提供了新的视角和解决方案,而且对于现代高性能计算和数据中心的能效管理具有重要意义。高性能计算和数据中心是当今社会信息处理的重要基础设施,对于支撑云计算、大数据分析、...
书中内容围绕着内存优化与性能提升展开,详细讲解了C++内存分配、回收机制,深入分析了标准库容器和STL的实现机制,探讨了内存泄漏的检测和预防方法,还讨论了现代处理器缓存的特性及其对性能的影响。此外,对于那些...
且缓存占据了芯片的大部分面积,使得片上缓存所消耗的能量成为存储器子系统中功率损耗的主要贡献者,因此对片上缓存进行优化是提高存储器系统效率的主要途径,增强了片上多核处理器的运算性能。针对共享缓存的管理、...
《CSAPP性能优化实验》是计算机科学与应用(Computer Science and Application Programming)课程的一个实践环节,旨在提升学生对程序性能优化的理解与技能。在这个实验中,我将详细探讨三个关键的优化策略,并结合...
为了充分利用其硬件性能,开发者需要掌握一系列优化技巧。本篇文章将根据提供的三个文档——"TMS320C6000 Optimizing Compiler User's Guide.pdf"、"spru198k.pdf"以及"TI C66x Optimization startup guide.pdf",...