首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在许多CPU上缩放处理时的奇怪行为

在许多CPU上缩放处理时的奇怪行为
EN

Stack Overflow用户
提问于 2016-03-07 06:40:12
回答 4查看 80关注 0票数 4

我正在学习性能,同时在许多CPU上扩展java代码。为此,我编写了一个简单的程序,在一个线程上运行50000斐bonacci,然后在两个线程上运行2*50000,在三个线程上运行3*50000,直到达到目标主机的CPU数。

这是我的代码:

代码语言:javascript
复制
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MultiThreadScalability {

    static final int MAX_THREADS = 4;
    static final int NB_RUN_PER_THREAD = 50000;
    static final int FIBO_VALUE = 25;

    public static void main(String[] args) {
        MultiThreadScalability multiThreadScalability = new MultiThreadScalability();
        multiThreadScalability.runTest();
    }


    private void runTest() {
        int availableProcs = Runtime.getRuntime().availableProcessors();
        System.out.println(availableProcs + " processors available");

        for (int i = 1 ; i <= availableProcs ; i++) {
            System.out.println("Running scalability test for " + i + " threads");
            long timeInMillisecs = runTestForThreads(i);
            System.out.println("=> " + timeInMillisecs + " milli-seconds");
        }
    }


    private long runTestForThreads(int threadsNumber) {
        final int nbRun = NB_RUN_PER_THREAD * threadsNumber;
        ExecutorService executor = Executors.newFixedThreadPool(threadsNumber);

        long startTime = System.currentTimeMillis();

        for (int i = 0 ; i < nbRun ; i++) {
            Runnable worker = new Runnable()
            {
                public void run()
                {
                    fibo(FIBO_VALUE);
                }
            };

            executor.execute(worker);
        }

        executor.shutdown();

        while (!executor.isTerminated())
        {}

        return (System.currentTimeMillis() - startTime);
    }


    private static long fibo(int n) {
        if (n < 2) {
            return (n);
        }

        return (fibo(n - 1) + fibo(n - 2));
    }

}

在给定的条件下,我期望--与线程数无关--执行时间保持不变。

我在一台充满电源的机器上运行它,输出如下:

代码语言:javascript
复制
48 processors available
Running scalability test for 1 threads
=> 34199 milli-seconds
Running scalability test for 2 threads
=> 34141 milli-seconds
Running scalability test for 3 threads
=> 34009 milli-seconds
Running scalability test for 4 threads
=> 34000 milli-seconds
Running scalability test for 5 threads
=> 34034 milli-seconds
Running scalability test for 6 threads
=> 34086 milli-seconds
Running scalability test for 7 threads
=> 34094 milli-seconds
Running scalability test for 8 threads
=> 34673 milli-seconds
Running scalability test for 9 threads
=> 35297 milli-seconds
Running scalability test for 10 threads
=> 35486 milli-seconds
Running scalability test for 11 threads
=> 35913 milli-seconds
Running scalability test for 12 threads
=> 36324 milli-seconds
Running scalability test for 13 threads
=> 35722 milli-seconds
Running scalability test for 14 threads
=> 35750 milli-seconds
Running scalability test for 15 threads
=> 35634 milli-seconds
Running scalability test for 16 threads
=> 35970 milli-seconds
Running scalability test for 17 threads
=> 37914 milli-seconds
Running scalability test for 18 threads
=> 36560 milli-seconds
Running scalability test for 19 threads
=> 36720 milli-seconds
Running scalability test for 20 threads
=> 37028 milli-seconds
Running scalability test for 21 threads
=> 37381 milli-seconds
Running scalability test for 22 threads
=> 37529 milli-seconds
Running scalability test for 23 threads
=> 37632 milli-seconds
Running scalability test for 24 threads
=> 39942 milli-seconds
Running scalability test for 25 threads
=> 40090 milli-seconds
Running scalability test for 26 threads
=> 41238 milli-seconds
Running scalability test for 27 threads
=> 42336 milli-seconds
Running scalability test for 28 threads
=> 43377 milli-seconds
Running scalability test for 29 threads
=> 44394 milli-seconds
Running scalability test for 30 threads
=> 46245 milli-seconds
Running scalability test for 31 threads
=> 45928 milli-seconds
Running scalability test for 32 threads
=> 47490 milli-seconds
Running scalability test for 33 threads
=> 47674 milli-seconds
Running scalability test for 34 threads
=> 48775 milli-seconds
Running scalability test for 35 threads
=> 56456 milli-seconds
Running scalability test for 36 threads
=> 50557 milli-seconds
Running scalability test for 37 threads
=> 51393 milli-seconds
Running scalability test for 38 threads
=> 52971 milli-seconds
Running scalability test for 39 threads
=> 53077 milli-seconds
Running scalability test for 40 threads
=> 54015 milli-seconds
Running scalability test for 41 threads
=> 55924 milli-seconds
Running scalability test for 42 threads
=> 55560 milli-seconds
Running scalability test for 43 threads
=> 56554 milli-seconds
Running scalability test for 44 threads
=> 57073 milli-seconds
Running scalability test for 45 threads
=> 65193 milli-seconds
Running scalability test for 46 threads
=> 58549 milli-seconds
Running scalability test for 47 threads
=> 59302 milli-seconds
Running scalability test for 48 threads
=> 60662 milli-seconds

时间保持几乎相同的,直到24个线程。它变得越来越慢,你可以在这张图上看到它

我寻求帮助是为了了解为什么会发生这样的“中断”。

最后但并非最不重要的是,运行测试的主机的CPU配置如下:

代码语言:javascript
复制
$ cat /proc/cpuinfo
processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 46
model name      : Intel(R) Xeon(R) CPU           E7540  @ 2.00GHz
stepping        : 6
cpu MHz         : 1997.885
cache size      : 18432 KB
physical id     : 0
siblings        : 12
core id         : 0
cpu cores       : 6
apicid          : 0
fpu             : yes
fpu_exception   : yes
cpuid level     : 11
wp              : yes
flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat p
se36 clflush dts acpi mmx fxsr sse sse2 ss ht tm syscall nx rdtscp lm constant_tsc id
a nonstop_tsc pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr sse4_1 sse4_2 popcnt lah
f_lm
bogomips        : 3995.77
clflush size    : 64
cache_alignment : 64
address sizes   : 44 bits physical, 48 bits virtual
power management: [8]

在这里,我看到内核的实际数量只有6。Runtime.getRuntime().availableProcessors()不返回物理CPU的数量,而是返回“超级线程”的数目: 48。

你认为它能解释我在24条线上观察到的“断线”吗?

EN

回答 4

Stack Overflow用户

发布于 2016-03-07 07:04:19

在我看来,你的机器似乎有4个英特尔E7540 CPU,每个CPU有6个核心和12个线程,总共有24个核心和48个线程。因此它可以同时执行24条指令。

这48个线程引用了超线程特性,它的构建是为了更好地利用线程必须获取内存才能继续的微暂停。因为您的测试不访问最内部循环中的任何新内存,所以您的测试受到24个内核的限制。

所以是的,内核的数量和线程的数量解释了这一点。

票数 4
EN

Stack Overflow用户

发布于 2016-03-07 07:04:19

首先,这种临时测量很难正确地进行。让我们检查一下您的方法:

  1. 您正在运行哪个版本的java?提供给这个JVM的运行时标志是什么?
  2. Fibonacci可能不是最好的CPU测试,因为它加载堆栈--尽管您已经将它设置为n=25。此外,您的CPU或JVM可能会自动执行一些优化,因为您一遍又一遍地做着相同的事情。我建议您将其模块化,并测试几个不同的负载生成函数!随机种子矩阵的矩阵乘法将是一个合理的想法,或者是一些密码函数,例如,对/dev/urandom等效的scrypt散列。
  3. 在多个物理CPU的不同情况下,您看到了许多独立运行的中断吗?像这样的1测试不足以使您对曲线的形状产生疑问。在提出问题之前,让我们试一试10到20个测试(我知道你可能有,但我没有看到数据)。
  4. CPU有很多不同的组件!有一个ALU,它做简单的数学运算,有几个不同的高速缓存层,主控制器单元,可能还有许多其他未知的小块来优化某些操作(嘿,Intell自从我详细研究这个操作以来已经做了一些改进),所有这些都可能导致不同类型的操作的负载扩展。
  5. 操作系统负责线程的调度,它可以使用许多不同的算法来执行这个调度功能。图形中的任何下降或尖峰都可能是操作系统以不同的方式执行此调度的结果(您正在测试一个极其复杂的系统的行为,这种噪音并不是不合理的)。
票数 1
EN

Stack Overflow用户

发布于 2016-03-07 06:55:45

运行FIBO的线程任务非常密集,在第一个线程之后,其他线程几乎没有机会启动。

如果你要创建它们,然后让它们同时开始,你可能会看到一些改进,但我对此表示怀疑。

线程的好处是允许在占用一个特定资源时进行其他处理,但在您的示例中,唯一被赋税的资源是CPU。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35837650

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档