原文:http://www.agner.org/optimize/blog/read.php?i=6
现在的大端(字节序)微处理器拥有双核或者更多核已经不是一个新闻了。 多线程应用利用多核的的优势,能同时运行多个线程。 如果你在一个四核的处理器上运行一个四线程的程序,你的程序很可能获得四倍的性能。有些处理器则通过在一个核上同时运行多个线程的方式更进一步的利用多线程的优势。 这就是Inter所谓的“超线程”。 例如: Intel 酷睿I7处理器拥有4个核却能让8个线程同时运行--每两个线程公用一个核。 显而易见的是同一时刻能同时运行的线程越多, 单位时间内你能完成的工作就越多。 但有一个问题,其实运行在同一个核上的两个线程在竞争同样的资源。如果这两个线程都只得到了一半的资源, 那么超线程带来的收益就为0. 两个线程以一半的速度运行带来的收益不会比一个线程全速运行带来的收益多。
为了观测超线程其中一个线程到底能跑多快,我曾对超线程做个一些实验。 以下是超线程之间共享的资源列表:1. 缓存
2. 代码分支预测资源
3. 指令读入和解码资源
4. 运行单元
如果以上任意资源成为了线程运行速度的限制因素, 那么超线程将毫无优势, 反正则超线程大有用武之地。 具体而言, 在如下的情况下超线程是很好的选择。
1. 内存数据过于分散, 以至于不管线程是使用全部cache还是一般的cache, cache命中率都很低。 这样的话, 超线程能使一个线程在等待没有命中cache的数据调入的同时让另一个线程继续使用运行单元 。
2. 不管线程是使用全部或部分的代码分支预测资源, 都有大量的分支预测错误。 这样的话, 超线程能在一个线程在等待指令读入的过程中让另一个现实使用运行单元。
3. 代码中有大量长依赖链(long dependency chains 是啥?)阻止了执行单元的高效利用。
在以上情况下, 超线程将获得小于100%的收益。 超线程的不会是性能翻倍, 而只是让性能有所增长, 比如25%。 另一方面, 如果诸如指令读取, 内存读取或者乘法单元,成了程序运行速度的瓶颈, 那么超线程将不会提高性能。实际在, 在最坏的情况下, 由于线程间资源的竞争, 超线程甚至会降低程序的性能。只需要google一下, 你就会找到大量禁止超线程,程序性能不降反升的案例。
Intel Atom 相比而言就没那么强大了, 这种处理器一般用在小笔记本和嵌入式环境中。 他只拥有两个核, 最多能让四个线程同时运行。他的执行单元远没有I7那么大,听起来让两个线程共享这个本来就捉襟见肘的执行单元不是一个怪诞的主意。 这个主意的原因是Atom缺少大处理器所拥有的out-of-order capabilities 。 当执行单元在等待不在cache中的数据读入或者其他的长延时事件时,除非有另一个线程可以继续调入工作, 否则执行单元被白白浪费。
关于以上处理器的详尽介绍,请移步我的处理器架构手册www.agner.org/optimize/#manuals.
明显, 让程序员直接去判断超线程对一个特定的程序是否有收益不是一件容易的事情。 判断这个问题得最稳妥的方法是进行测试。 理论上,打开和关闭超线程的对比测试应该在不同的处理器和不同的数据集上分别进行。这对开发者而言确实是一个沉重的负担, 估计没有几个程序要愿意花这么多时间和财力在测试超线程对他的程序的影响上。
不幸的是, 你阻止不了操作系统利用这些空闲的逻辑核来做一些事情。让处理器严格的使一个线程的优先级高于另一个线程是不可能的(why), 有时候操作系统会让两个优先级差别明显的线程跑在同一个处理器上,这时候低优先级的线程会偷走高优先级线程的资源(甚至造成优先级反转)。 这一点即使在最新的WINDOW7系统上我也发现了。不让不同优先级的线程跑在同一个核上是操作系统应该完成的功能(不懂), 可惜操作系统的设计者们目前还没有完全解决这一的问题。
程序员所需要的是一个系统调用, 这个系统调用能告诉操作系统我不想让每一个核上跑超过一个线程并且我也不想和别的任何程序分享我所占用任意一个核。 可是据我所知这样的系统调用迄今为止没有操作系统有提供。