一般说来, 主要的思路定了之后, 程序的性能大致也定了. 但是, 当前的CPU 潜力很大, 并且 CPU 比内存速度很多, 还是带来很多优化余
地的. 优秀的低级优化是要考虑 memory 访问次数, 顺序访问/随机访问, cpu cache line 大小(例如 64bytes),
甚至考虑到某个地址段的访问, 读和写分别集中起来(内存不但速度慢, 非连续访问的时候, 要等待, 读和写还有切换时间, AMD cpu 内置
memory controller, 内部更加智能地对读写group, 内存性能好), 调整条件判断指令, 以便让分支预测更准确, 等等,
因素很多.
对于基本算法不良的程序, 这种低级优化能够带来的帮助未必很大, 因为它可能有其他严重的性能瓶颈, 例如同步瓶颈, 内存块非常零散, CPU 指
令太多, 或者造成分支预测不准的条件判断太多等不良问题.
但是对于算法良好的程序, 如果程序不是 memory bound 的这种级别的优化, 经常能够提高程序的性能40% 以上, 甚至快几倍.
memory bound 的程序 -- 例如那种执行10万条CPU指令, 就要从1000个不同地址取数据, 数据量还大到cache 放不下;
或者要从一个地址复制5M, 10M 数据到另外一个地址的程序, 这种程序性能被 memory bound 住了, 优化也无用.
intel 的工程师经常帮一起经典的软件, 库进行优化, 优化结果经常是可以快很多, 他们就是结合考虑指令集(SSE之类)优化, 内存访问优
化, 分支预测优化, 可并行(cpu 执行器级别)指令顺序调整等等做的优化.
我现在的水平还很低, 性能 critical 的代码, 主要做的是memory, cache 考虑, 以及用软件对分支预测不准进行分析, 对不
准的点做做调整看看结果(不知道所以然, 所以不知道理论上怎么调整好).
有经验的大大出来指点一下 ?
在 2007-10-24三的 19:13 -0700,redsea写道:
--
Live Long and Prosper
- oldrev
--
Everything is possible and available if we trust ourselves!
还有, 有时候的算法必须依据硬件的特点进行选择, 例如, 我们有一个程序, 每秒
钟收到8万个请求包, 要根据请求包中的一个字符串判断这个请求包后续应该怎么
处理, 请求字符串分布范围非常广, 但是可能有50万个字符串规则; 而这个判断要
在3us 之内确保完成, 这个程序没有架构问题, 没有同步问题(不能进行动态内存
分配, 连这个同步冲突点都没有).
这种情形下面, Intel 销售的优化的算法库也都没有什么用 (实际上这个程序在
os kernel 里面跑), 程序量不大(也不能大).
wang xin 写道:
cpu 的 l2 cache line 大小种类也不太多, 32bytes, 64bytes(有没有 128bytes
的 ?), 很多是64bytes, 这样, 一个内存访问, 只要你访问了其中1个字节, 你再
访问64对齐该内存块其他内存就很快了; 由于现在 cpu 执行指令快, 所以
longlong ago 前的传说: byte bool 比起 int bool 速度慢 (cpu 要先执行一个
int 扩展) 现在也不存在了, 反而如果一个结构中, 你将常用的字段都尽量缩小,
并且尽量挤在前面, 那么无论 cpu cache line 多大, 性能多半都有提升.
莫华枫 写道:
> 这么说来,考虑到高性能的情况下,就无法再考虑移植性了。高级的性能优化都
> 是平台特定的。
> 从这一点上来看,C++既强调性能,又要确保移植性的做法是错误的。与其同时
> 确保两者,还不如确保编译器的可移植性,以便开发者利用不同的编译器针对性
> 地提高性能。如今的情况就是既无法保证一个编译器包打天下,又无法让代码在
> 不同编译期间快速移植,两头没着落。
>
不过我说得也不准确, 准确地说, 应该, 硬件的这些特性, 对高性能计算的底层算
法选择影响很大.
只是, 最核心的代码, 自己进行分析之后, 调整优化, 可以有机会比编译器干得
好; 并且编译器是不会抱怨你的基础算法不好, 调整一下更好优化的, 人却可以发
现这点.
不过我发现我的题目取错了, 回想起来, 这种优化经常涉及到回头大调或者细调数
据结构. 很有可能 intel 工程师帮别人优化的时候, 也是有这样的调整的.
所以, 不应该叫做算法之外的优化, 应该是从低级分析结果引导的优化.
wang xin 写道:
> 精心构造你的字符串规则(也就是选取一个精心构造都数据集)
> 如:著名的quake中的那个用于求平方根的浮点数
如果先抛开算法本身的问题,仅考虑面向平台优化,编译器能多大程度上帮助,或者说代替人工进行的优化呢?是否一个面向特定平台优化的编译器可以完全达到人工的程度?
此外,jit能够起到什么样的作用?
99%的程序员做不到比编译器优化的更好的地步
在07-10-25,莫 华枫 <longsh...@gmail.com> 写道:如 果先抛开算法本身的问题,仅考虑面向平台优化,编译器能多大程度上帮助,或者说代替人工进行的优化呢?是否一个面向特定平台优化的编译器可以完全达到人工 的程度?
此外,jit能够起到什么样的作用?
嗯, 确实如此, 就拿最基本的并行指令重新排列, 要做这件事情, pentium 是有两个 uv 不同的执行器, 能力不同, 最新的 core2 有三个整数执行器, 两个浮点执行器, 不同的目标CPU, 做法就不一样. gcc 的 march 选项就有很多的 cpu 选择. vc 就简单很多.
要能够做好这些事情, 非得要长期做汇编才可以 ---- intel 的工程师可以, photoshop 的程序员中, 说不定也有几个有些研究, 暴雪公司不知道有没有, 但是这样的人, 肯定不多. 但是 gcc 是知道这些事情的, vc 也应该知道.
jit 能够做到什么地步, 我不清楚. 对于编译器而言, 似乎这个地方的优化开销并不是特别大(起码 gcc 开全优化, 编译速度也还能够接受, g++ 那个不谈, 时间花到其他地方了.).
我们现在只是在某些方面, 例如内存访问次数, 条件判断等方面, 在数据结构和C代码的一个级别进行调节和优化. 条件判断这边做的优化我还不知道方向, 只是发现分支预测错误多, 就将条件反向看看结果, 到底应该怎么做呢 ?
不知道是不是正确,呵呵,见笑了。
On 10月25日, 上午11时34分, red...@gmail.com wrote:
> 嗯, 确实如此, 就拿最基本的并行指令重新排列, 要做这件事情, pentium 是有两个 uv 不同的执行器, 能力不同, 最新的 core2 有三个整数执行器, 两个浮点执行器, 不同的目标CPU, 做法就不一样. gcc 的 march 选项就有很多的 cpu 选择. vc 就简单很多.
> 要能够做好这些事情, 非得要长期做汇编才可以 ---- intel 的工程师可以, photoshop 的程序员中, 说不定也有几个有些研究, 暴雪公司不知道有没有, 但是这样的人, 肯定不多. 但是 gcc 是知道这些事情的, vc 也应该知道.
> jit 能够做到什么地步, 我不清楚. 对于编译器而言, 似乎这个地方的优化开销并不是特别大(起码 gcc 开全优化, 编译速度也还能够接受, g++ 那个不谈, 时间花到其他地方了.).
> 我们现在只是在某些方面, 例如内存访问次数, 条件判断等方面, 在数据结构和C代码的一个级别进行调节和优化. 条件判断这边做的优化我还不知道方向, 只是发现分支预测错误多, 就将条件反向看看结果, 到底应该怎么做呢 ?
> wang xin 写道:99%的程序员做不到比编译器优化的更好的地步在07-10-25,莫华枫<longsh...@gmail.com> 写道:如果先抛开算法本身的问题,仅考虑面向平台优化,编译器能多大程度上帮助,或者说代替人工进行的优化呢?是否一个面向特定平台优化的编译器可以完全达到人工的程度?
> 此外,jit能够起到什么样的作用?
On 10月25日, 上午10时13分, redsea <red...@gmail.com> wrote:
我自己的程序, 字符串查找分段, 同时变大写, 并且计算 hash code 的几个函数, 在源代码级别优化, 做内存访问优化之后也提高了大概是40% 左右.
后来想进一步优化, 同时减小了内存访问次数和代码行数, 第一次扫描字符串改成跳跃着扫描, 结果是, 比之前的两次从头到尾扫描, 代码行数更长的算法反倒慢了.
对于编译器的优化能力,VC2005不错(GCC差一些),如果是同一个实现,我手工写的汇编一般能比VC2005提高10%-20%;(但在不同
CPU上的
适应能力有时没有编译器做得好) (高手应该可以做得更好一些; 什么时候可以不用写汇编就好了) ;
这方面比较佩服Intel的编译器,手工写的汇编很难超过它,但它只对自家的CPU支持比较好,在AMD的CPU上麻烦多多(可能孤陋寡闻);