【问题标题】:CPU time percentage algorithm problemsCPU时间百分比算法问题
【发布时间】:2011-10-21 18:00:20
【问题描述】:

我创建的用于将纳秒 CPU 时间使用率(通过 JMX 获得)转换为 100% 百分比的 Java 算法存在问题。该算法似乎给出了大于 100% 的数字,我认为这是由于多个可用处理器造成的,尽管代码应该对此进行排序。该算法可以在下面看到。 cpuTimeDiffNS 是以纳秒为单位使用的 CPU 时间量,而 periodMS 是采样周期。

public static final double getCPUPerc(long cpuTimeDiffNS, long periodMS) {
    if (periodMS == 0) return 0;
    double cpuTimeDiffMS = cpuTimeDiffNS / 1000000d;
    int procs = Runtime.getRuntime().availableProcessors();
    long availableTime = periodMS * procs;
    double perc = cpuTimeDiffMS / availableTime;
    return perc * 100d;
}

以下是数据采集的一些示例:

0
87.5
133.8288232
160.8231707
197.7896341
209.6036585
248.822774
274.3902439
267.9115854
271.3414634
277.1067759
283.1554878
272.1036585
279.4000734
283.9176829
283.5365854
275.9146341
282.4578033
278.9634146
261.0536937
254.6071775
286.662182
278.9634146
276.7245597
288.4908537
281.6933708
286.9664634
279.7822896
276.2957317
280.4878049
275.5335366
271.7557485
280.8689024
287.2689689
281.6933708
267.5097276
273.2469512
286.1735835
289.6341463
296.875
279.4000734
289.2530488
282.8400196
288.4908537
287.4266145
288.1097561
286.5853659
288.9554795
238.1207192
288.4908537
288.7063531
290.3963415
286.662182
277.4390244
290.4843444
281.6310976
271.7557485
272.8658537
283.2222358
250.7621951

编辑:根据要求,输入收集功能(你可以忽略这个):

// returns CPU time in NS for a thread group (recursively)
public static long getCPUTime(ThreadGroup tg) {
    synchronized (TGLOCK) {
        int size;
        do {
            size = tg.enumerate(tgThreads, true);
            if (size <= tgThreads.length) continue;
            tgThreads = new Thread[size];
        } while (size > tgThreads.length);

        long totalTime = 0;
        for (int i = 0; i < size; i++) {
            totalTime += getCPUTime(tgThreads[i]);
        }
        return totalTime;
    }
}

public static long getCPUTime(Thread t) {
    return threadMXBean.getThreadCpuTime(t.getId());
}

public static ThreadGroup getRootThreadGroup() {
    // Find the root thread group
    ThreadGroup root = Thread.currentThread().getThreadGroup().getParent();
    while (root.getParent() != null) {
        root = root.getParent();
    }
    return root;
}

和输入(同样,你可以忽略这个):

    simCPUTimeNS     = getCPUTime(kks.getSimThreadGroup());
    appsCPUTimeNS    = getCPUTime(kks.getAppThreadGroup());
    lwjns3CPUTimeNS  = getCPUTime(kks.getKKSThreadGroup());
    simCoreCPUTimeNS = getCPUTime(kks.getSimThread());
    totalCPUTimeNS   = getCPUTime(getRootThreadGroup());

    simCPUTimeNSDiff  = simCPUTimeNS - lastSimCPUTimeNS;
    appsCPUTimeNSDiff = appsCPUTimeNS - lastAppsCPUTimeNS;
    lwjns3CPUTimeNSDiff = lwjns3CPUTimeNS - lastLwjns3CPUTimeNS;
    simCoreCPUTimeNSDiff = simCoreCPUTimeNS - lastSimCoreCPUTimeNS;
    totalCPUTimeNSDiff = totalCPUTimeNS - lastTotalCPUTimeNS;

    lastSimCPUTimeNS     = simCPUTimeNS;
    lastAppsCPUTimeNS    = appsCPUTimeNS;
    lastLwjns3CPUTimeNS  = lwjns3CPUTimeNS;
    lastSimCoreCPUTimeNS = simCoreCPUTimeNS;
    lastTotalCPUTimeNS   = totalCPUTimeNS;

    simCPUPerc     = getCPUPerc(simCPUTimeNSDiff, currDiffMS);
    appsCPUPerc    = getCPUPerc(appsCPUTimeNSDiff, currDiffMS);
    lwjns3CPUPerc  = getCPUPerc(lwjns3CPUTimeNSDiff, currDiffMS);
    simCoreCPUPerc = getCPUPerc(simCoreCPUTimeNSDiff, currDiffMS);
    totalCPUPerc   = getCPUPerc(totalCPUTimeNSDiff, currDiffMS);

为任何帮助干杯,我相信答案是显而易见的 ;)
克里斯

【问题讨论】:

  • 希望这篇文章能更好地帮助到你:stackoverflow.com/questions/47177/…
  • 您使用什么 JMX 调用和计算来获取 cpuTimeDiffNS
  • 通常当我遇到这样的问题时,我会让它发出你正在计算的每个中间值。例如,您的输入是否符合您的期望? cpuTimeDiffMS 计算是否正确?过程?有空时间? perc的第一个化身?还是只有关闭的返回值?
  • 我的回答对你有帮助吗@Chris?如果是,请接受。

标签: java algorithm debugging cpu-usage sampling


【解决方案1】:

所以我们使用类似的代码来计算平均负载,并且(事实证明)它有一个错误,可能也存在于您的代码中。我们使用getAllThreadIds(),但它只返回“活动”线程,enumerate 也这样做。如果您的任何线程停止,则总 cpu 时间可能会下降。我不明白这会如何导致值超过 100%。

关于你的代码的几个问题:

  • 为什么是synchronized (TGLOCK) 行?这是为了同步ThreadGroup 对象吗?
  • if (size &lt;= tgThreads.length) continue; 应该是 break;。无需重复测试。
  • enumerate 返回放入数组的线程数。这将永远是&lt;= tg.length,所以如果我准备好了,数组将永远不会增长。如果它确实返回了更大的大小,那么您将获得 NPE,因为您在 while 检查之前有 tgThreads = new Thread[size];,这永远不会是真的。
  • 您使用ThreadGroup 有什么原因吗?我们正在使用以下不需要递归或任何东西的内容:
    for (long id : threadMxBean.getAllThreadIds()) {
        长 cpuTime = threadMxBean.getThreadCpuTime(id);
    

希望这至少有所帮助。

【讨论】:

  • 我使用 ThreadGroup 是因为我的线程被整齐地组织成组,我需要枚举这些组中线程的属性。 synchronized 块是因为 tgThreads 静态字段,我想保护对它的访问。双重测试是必要的,因为tg.enumerate(..) 返回的大小可能小于传递的数组,在这种情况下,您需要创建一个具有给定大小的新数组并传递它,这样元素就不会落到最后。可能不需要 do { } while { },但这并不重要。
  • 我觉得你不太明白。首先你正在做size &lt;= tgThreads.length 和调用continue 将你带到while (size &gt; tgThreads.length)。这是一个不必要的测试,因为它总是错误的。
  • 而 while () 循环似乎无关紧要,因为它永远不会是真的。大小将始终为 == tgThreads.length,因为之前是新的。
  • 它会在 size
  • 啊,我明白它为什么起作用了。阅读 enumerate 的 javadocs。它永远不会返回大小 > tg.length。不管你说什么伙计,那个循环中都有错误。但我同意他们没有解释> 100%。我敢打赌,如果您打印出数组的大小,它与最初创建时的大小相同。
【解决方案2】:

我在时间膨胀的 JVM 上运行(减速 5 倍),在进行调整时,我似乎忘记在 os_windows.cpp (os::thread_cpu_time) 中的 C++ JVM 代码的一部分中进行膨胀。哎呀。它使用timeGetTime(),一个Windows 时间函数。这样就可以解释了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 2019-05-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多