有人可以向我推荐一些文档来说明多CPU,多核和超线程之间的区别吗?我总是对这些差异以及不同场景中每个架构的优缺点感到困惑.
编辑:这是我在网上学习并从别人的评论中学习后的当前理解; 有人可以评论评论吗?
乔治,提前谢谢
我有一个多线程的c ++应用程序,可以在Windows,Mac和一些Linux风格上运行.
简而言之:为了使它以最高效率运行,我必须能够为每个物理处理器/核心实例化一个线程.创建比物理处理器/内核更多的线程会大大降低程序的性能.我已经可以在所有这三个平台上正确检测逻辑处理器/核心的数量.为了能够正确检测物理处理器/内核的数量,我必须检测是否支持超级交叉和活动.
因此,我的问题是,是否有办法检测是否支持超线程并启用?如果是这样,究竟如何.
我正在阅读新的英特尔凌动330的评论,他们注意到任务管理器显示4个核心 - 两个物理核心,另外两个由超线程模拟.
假设你有一个包含两个线程的程序.假设这些是在PC上进行任何工作的唯一线程,其他一切都是空闲的.操作系统将两个线程放在同一个核心上的概率是多少?这对程序吞吐量有很大影响.
如果答案不是0%,那么除了创建更多线程之外,是否还有其他缓解策略?
我希望Windows,Linux和Mac OS X会有不同的答案.
鉴于:
8,16和28个线程可能比4个线程表现更好吗?我的理解是,4个线程将执行较少的上下文切换,并且在任何意义上将比4个物理核心机器上的8,16或28个线程具有更少的开销.但是,时间是 -
Threads Time Taken (in seconds)
4 78.82
8 48.58
16 51.35
28 52.10
Run Code Online (Sandbox Code Playgroud)
用于测试获取时间的代码在下面的原始问题部分中提到.CPU规格也在底部给出.
在阅读了各个用户提供的答案以及评论中给出的信息后,我终于可以将问题归结为我上面写的内容.如果上述问题为您提供完整的上下文,则可以跳过下面的原始问题.
我们说的是什么意思
超线程的工作方式是复制处理器的某些部分 - 存储体系结构状态的部分 - 但不复制主要执行资源.这允许超线程处理器作为通常的"物理"处理器和主机操作系统的额外"逻辑"处理器出现
?
今天在SO上询问了这个问题,它基本上测试了多个线程执行相同工作的性能.它具有以下代码:
private static void Main(string[] args)
{
int threadCount;
if (args == null || args.Length < 1 || !int.TryParse(args[0], out threadCount))
threadCount = Environment.ProcessorCount;
int load;
if (args == null || args.Length < 2 || !int.TryParse(args[1], out load))
load = 1;
Console.WriteLine("ThreadCount:{0} Load:{1}", …Run Code Online (Sandbox Code Playgroud) 假设我们想尽快编译一个大型项目(比如GCC或Linux内核).具有超线程功能的CPU(比如Intel Core i7)是否可以在启用或禁用超线程的情况下更快地运行编译器?是否有任何已发布的测试基准测试?
我对超线程的理解是每个核心都可以从两个(或更多个进程)中选择指令.这通常使核心更有效,因为功能单元不太可能空闲.但是,由于在相同内核上运行的进程共享资源(如缓存)可能会相互干扰,因此可能会降低性能.性能是否实际增加取决于工作量.
那么对于编译器工作负载,性能是否会提高?如果是这样,多少钱?
我想知道我可以运行的最佳线程数.通常,这等于Runtime.getRuntime().availableProcessors().
但是,在支持超线程的CPU上,返回的数字是两倍.现在,对于某些任务,超线程是好的,但对于其他任务,它什么都不做.在我的情况下,我怀疑,它什么也没做,所以我想知道我是否必须将返回的数字除以Runtime.getRuntime().availableProcessors()二.
为此,我必须推断CPU是否是超线程.因此我的问题 - 我怎么能用Java做到这一点?
谢谢.
编辑
好的,我已对我的代码进行了基准测试.这是我的环境:
Long,然后存储在共享散列集中.因此,工作线程不会从HD中读取任何内容,但是它们会通过解压缩和解析内容来占用自己(使用opencsv库).
下面是代码,没有枯燥的细节:
public void work(File dir) throws IOException, InterruptedException {
Set<Long> allCoordinates = Collections.newSetFromMap(new ConcurrentHashMap<Long, Boolean>());
int n = 6;
// NO WAITING QUEUE !
ThreadPoolExecutor exec = new ThreadPoolExecutor(n, n, 0L, TimeUnit.MILLISECONDS, new SynchronousQueue<Runnable>());
StopWatch sw1 = new StopWatch();
StopWatch sw2 = new StopWatch();
sw1.start();
sw2.start();
sw2.suspend();
for (WorkItem wi : m_workItems) …Run Code Online (Sandbox Code Playgroud) 执行摘要:如何在代码中指定OpenMP应该只为REAL内核使用线程,即不计算超线程的线程?
详细分析:多年来,我在空闲时间编写了一个仅限SW的开源渲染器(光栅化器/光线跟踪器).可以从这里获得GPL代码和Windows二进制文件:https: //www.thanassis.space/renderer.html 它在Windows,Linux,OS/X和BSD下编译并运行良好.
我上个月推出了一种光线追踪模式 - 生成的图片质量飙升.不幸的是,光线跟踪比光栅化要慢几个数量级.为了提高速度,就像我对光栅化器一样,我为光线跟踪器添加了OpenMP(和TBB)支持 - 以便轻松利用额外的CPU内核.光栅化和光线跟踪都很容易进行线程化(每个三角形工作 - 每像素工作).
在家里,凭借我的Core2Duo,第二核心帮助了所有模式 - 光栅化和光线跟踪模式的加速都在1.85x和1.9x之间.
问题:当然,我很想看到CPU的最高性能(我也玩"GPU",初步的CUDA端口),所以我想要一个坚实的基础进行比较.我把代码交给了我的一个好朋友,他可以使用16英寸,1500美元英特尔超级处理器的"野兽"机器.
他以"最重"模式运行它,光线跟踪模式......
......他的速度是我的Core2Duo的五分之一(!)
喘气 - 恐怖.刚刚发生了什么?
我们开始尝试不同的修改,补丁,......最终我们弄明白了.
通过使用OMP_NUM_THREADS环境变量,可以控制生成的OpenMP线程数.随着线程数从1增加到8,速度增加(接近线性增加).在我们越过8的那一刻,速度开始减弱,直到我的Core2Duo速度的五分之一,当使用所有16个核心时!
为什么8?
因为8是真实核心的数量.其他8个是...超线程的!
理论:现在,这对我来说是新闻 - 我看到超线程在其他算法中帮助很多(高达25%),所以这是出乎意料的.显然,即使每个超线程核心都有自己的寄存器(和SSE单元?),光线跟踪器也无法利用额外的处理能力.这引导我思考......
它可能不是缺乏处理能力 - 它是内存带宽.
光线跟踪器使用边界体积层次结构数据结构来加速光线三角形交叉.如果使用的芯超线程,则每个在一对"逻辑核"的,试图从在该数据结构不同的地方(即,在存储器中),以读 - 和CPU高速缓存(每对本地)完全捶打.至少,这是我的理论 - 任何建议都是最受欢迎的.
所以,问题是: OpenMP检测"核心"的数量并产生与之匹配的线程 - 也就是说,它包括计算中的超线程"核心".就我而言,这显然会导致灾难性的结果,速度方面.有谁知道如何使用OpenMP API(如果可能的话,可移植)只为REAL内核生成线程,而不是超线程的线程?
PS代码是开放的(GPL),可在上面的链接中找到,随时可以在您自己的机器上重现 - 我猜这将在所有超线程CPU中发生.
PPS原谅帖子的长度,我认为这是一种教育经历,想分享.
单个进程中的两个不同线程可以通过读取和/或写入来共享公共存储器位置.
通常,这种(有意)共享是使用lockx86上的前缀使用原子操作实现的,该前缀对于lock前缀本身(即,无竞争成本)具有相当广为人知的成本,并且当实际共享高速缓存行时还具有额外的一致性成本(真或假共享).
在这里,我对生产 - 消费者成本感兴趣,其中单个线程P写入内存位置,另一个线程`C从内存位置读取,都使用普通读取和写入.
在同一个套接字上的不同内核上执行此类操作的延迟和吞吐量是多少,并且在最近的x86内核上在同一物理内核上执行兄弟超线程时进行比较.
在标题中,我使用术语"超级兄弟"来指代在同一核心的两个逻辑线程上运行的两个线程,以及核心间兄弟,以指代在不同物理核心上运行的两个线程的更常见情况.
如果您同时生成多个线程(或进程),假设任务受CPU限制,最好是生成多少个物理处理器数量或逻辑处理器数量?或者最好在两者之间做一些事情(例如,3个线程)?
性能是否取决于正在执行的指令类型(例如,非本地内存访问是否与缓存命中有很大不同)?如果是这样,在哪种情况下利用超线程更好?
更新:
我问的原因是,我记得在某个地方读过,如果你的任务数与虚拟处理器的数量一样多,那么同一物理内核上的任务有时会使某些CPU资源匮乏并阻止彼此获得所需的资源,可能会降低性能.这就是为什么我想知道是否拥有与虚拟内核一样多的线程是一个好主意.
我正在开发大密集矩阵乘法代码.当我对代码进行分析时,它有时会获得我的四个核心系统中大约75%的峰值触发器,而其他时间则大约为36%.在执行代码之间效率不会改变.它要么以75%开始并继续保持效率,要么从36%开始并继续保持这种效率.
我已经将问题追溯到超线程以及我将线程数设置为4而不是默认值8的事实.当我在BIOS中禁用超线程时,我一致地获得大约75%的效率(或者至少我从未看到大幅下降到36%).
在我调用任何并行代码之前omp_set_num_threads(4).我export OMP_NUM_THREADS=4在运行代码之前也尝试过,但它似乎是等效的.
我不想在BIOS中禁用超线程.我想我需要将四个线程绑定到四个核心.我已经测试了一些不同的情况,GOMP_CPU_AFFINITY但到目前为止,我仍然存在效率为36%的问题. 超线程和核心的映射是什么? 例如,线程0和线程1对应于同一个核心和线程2,线程3对应另一个核心吗?
如何在没有线程迁移的情况下将线程绑定到每个核心,这样我就不必在BIOS中禁用超线程? 也许我需要研究使用sched_setaffinity?
我当前系统的一些细节:Linux内核3.13,GCC 4.8,Intel Xeon E5-1620(四个物理内核,八个超线程).
编辑:到目前为止,这似乎运作良好
export GOMP_CPU_AFFINITY="0 1 2 3 4 5 6 7"
Run Code Online (Sandbox Code Playgroud)
要么
export GOMP_CPU_AFFINITY="0-7"
Run Code Online (Sandbox Code Playgroud)
编辑:这似乎也运作良好
export OMP_PROC_BIND=true
Run Code Online (Sandbox Code Playgroud)
编辑: 这些选项也很好用(gemm是我的可执行文件的名称)
numactl -C 0,1,2,3 ./gemm
Run Code Online (Sandbox Code Playgroud)
和
taskset -c 0,1,2,3 ./gemm
Run Code Online (Sandbox Code Playgroud) hyperthreading ×10
performance ×3
multicore ×2
openmp ×2
.net ×1
assembly ×1
c# ×1
c++ ×1
compilation ×1
concurrency ×1
gcc ×1
java ×1
macos ×1
renderer ×1
rendering ×1
scheduler ×1
slowdown ×1
smp ×1
windows ×1
x86 ×1