是否有可能在Java中,检查CPU是否支持超线程?(Is it possible to check

2019-07-30 17:10发布

我想知道我的线程可以运行的最佳数量。 通常情况下,这相当于Runtime.getRuntime().availableProcessors()

但是,返回的次数为两次一个CPU支持超线程的那样高。 现在,对于某些任务超线程是好的,但对其他人而言,什么都不做。 就我而言,我怀疑,它什么都不做,所以我想知道我是否有除以返回的数字Runtime.getRuntime().availableProcessors()两种。

对于我推断出CPU是否支持超线程。 因此,我的问题 - 我怎么能做到这一点在Java中?

谢谢。

编辑

OK,我已经基准我的代码。 下面是我的环境:

  • 联想ThinkPad W510(即i7的CPU有4个内核和超线程)的RAM,16G
  • Windows 7的
  • 84个压缩的CSV文件有拉链尺寸范围从105M 16M的
  • 所有文件都逐个读取在主线程中 - 没有多线程访问HD。
  • 每个CSV文件行包含一些数据,这些数据被分析和快速上下文测试确定该行是否是相关的。
  • 每个相关的行包含两个双打(表示经度和纬度,为好奇),其被强制转换为单个Long ,然后将其存储在共享哈希集合。

因此,工作线程不读从HD什么,但他们不与解压缩和解析的内容(使用占用自己opencsv库)。

下面是代码,W / O无聊的细节:

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) {
    for (File file : dir.listFiles(wi.fileNameFilter)) {
      MyTask task;
      try {
        sw2.resume();
        // The only reading from the HD occurs here:
        task = new MyTask(file, m_coordinateCollector, allCoordinates, wi.headerClass, wi.rowClass);
        sw2.suspend();
      } catch (IOException exc) {
        System.err.println(String.format("Failed to read %s - %s", file.getName(), exc.getMessage()));
        continue;
      }
      boolean retry = true;
      while (retry) {
        int count = exec.getActiveCount();
        try {
          // Fails if the maximum of the worker threads was created and all are busy.
          // This prevents us from loading all the files in memory and getting the OOM exception.
          exec.submit(task);
          retry = false;
        } catch (RejectedExecutionException exc) {
          // Wait for any worker thread to finish
          while (exec.getActiveCount() == count) {
            Thread.sleep(100);
          }
        }
      }
    }
  }
  exec.shutdown();
  exec.awaitTermination(1, TimeUnit.HOURS);
  sw1.stop();
  sw2.stop();
  System.out.println(String.format("Max concurrent threads = %d", n));
  System.out.println(String.format("Total file count = %d", m_stats.getFileCount()));
  System.out.println(String.format("Total lines = %d", m_stats.getTotalLineCount()));
  System.out.println(String.format("Total good lines = %d", m_stats.getGoodLineCount()));
  System.out.println(String.format("Total coordinates = %d", allCoordinates.size()));
  System.out.println(String.format("Overall elapsed time = %d sec, excluding I/O = %d sec", sw1.getTime() / 1000, (sw1.getTime() - sw2.getTime()) / 1000));
}

public class MyTask<H extends CsvFileHeader, R extends CsvFileRow<H>> implements Runnable {
  private final byte[] m_buffer;
  private final String m_name;
  private final CoordinateCollector m_coordinateCollector;
  private final Set<Long> m_allCoordinates;
  private final Class<H> m_headerClass;
  private final Class<R> m_rowClass;

  public MyTask(File file, CoordinateCollector coordinateCollector, Set<Long> allCoordinates,
                Class<H> headerClass, Class<R> rowClass) throws IOException {
    m_coordinateCollector = coordinateCollector;
    m_allCoordinates = allCoordinates;
    m_headerClass = headerClass;
    m_rowClass = rowClass;
    m_name = file.getName();
    m_buffer = Files.toByteArray(file);
  }

  @Override
  public void run() {
    try {
      m_coordinateCollector.collect(m_name, m_buffer, m_allCoordinates, m_headerClass, m_rowClass);
    } catch (IOException e) {
      e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
    }
  }
}

请在下面找到结果(我稍微改变了输出省略重复部分):

Max concurrent threads = 4
Total file count = 84
Total lines = 56395333
Total good lines = 35119231
Total coordinates = 987045
Overall elapsed time = 274 sec, excluding I/O = 266 sec

Max concurrent threads = 6
Overall elapsed time = 218 sec, excluding I/O = 209 sec

Max concurrent threads = 7
Overall elapsed time = 209 sec, excluding I/O = 199 sec

Max concurrent threads = 8
Overall elapsed time = 201 sec, excluding I/O = 192 sec

Max concurrent threads = 9
Overall elapsed time = 198 sec, excluding I/O = 186 sec

你可以自由地得出自己的结论,但我就是不超线程提高我的具体情况下的性能。 此外,具有6个工作线程似乎是这个任务,我的机器是正确的选择。

Answer 1:

对于Windows ,如果逻辑内核的数量比内核数量越高,你有hyper-threading启用。 了解更多关于它在这里 。

你可以使用wmic查找此信息:

C:\WINDOWS\system32>wmic CPU Get NumberOfCores,NumberOfLogicalProcessors /Format:List


NumberOfCores=4
NumberOfLogicalProcessors=8

因此,我的系统具有hyper-threading 。 逻辑处理器的数量是双核。

但是你可能甚至不需要知道。 Runtime.getRuntime().availableProcessors()已经返回的逻辑处理器的数量。

在获得物理核心计数完整的例子( Windows仅):

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class PhysicalCores
{
    public static void main(String[] arguments) throws IOException, InterruptedException
    {
        int physicalNumberOfCores = getPhysicalNumberOfCores();
        System.out.println(physicalNumberOfCores);
    }

    private static int getPhysicalNumberOfCores() throws IOException, InterruptedException
    {
        ProcessBuilder processBuilder = new ProcessBuilder("wmic", "CPU", "Get", "NumberOfCores");
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
        String processOutput = getProcessOutput(process);
        String[] lines = processOutput.split(System.lineSeparator());
        return Integer.parseInt(lines[2]);
    }

    private static String getProcessOutput(Process process) throws IOException, InterruptedException
    {
        StringBuilder processOutput = new StringBuilder();

        try (BufferedReader processOutputReader = new BufferedReader(
                new InputStreamReader(process.getInputStream())))
        {
            String readLine;

            while ((readLine = processOutputReader.readLine()) != null)
            {
                processOutput.append(readLine);
                processOutput.append(System.lineSeparator());
            }

            process.waitFor();
        }

        return processOutput.toString().trim();
    }
}


Answer 2:

不幸的是,这是不可能的从Java。 如果您知道应用程序将在一个现代的Linux变种运行,就可以读取文件/ proc / cpuinfo中,如果启用HT推断。

读这个命令的输出的伎俩:

grep -i "physical id" /proc/cpuinfo | sort -u | wc -l


Answer 3:

将是决定你是否有超线程这是对,超线程是关闭或没有超线程没有可靠的方法。

相反,更好的方法是做一个第一校准运行运行在第一次测试,确定要使用的方法首次(或每次)。

另一种方法是使用全部处理器即使超线程没有帮助(只要不使代码慢得多)



Answer 4:

几个沉思:

  • 超线程可以具有每码多于2个线程(SPARC可以具有8)
  • 垃圾收集器需要CPU时间来正常工作。
  • 超线程技术可以帮助并发GC - 或可能不会; 或JVM可以请求是核心的独占(未超线程)所有者。 因此阻碍了GC得到一个测试过程中你更好的结果可能会在长远的伤害。
  • 超线程通常是有用的,如果有缓存缺失,所以CPU不会停滞,但切换到另一个任务。 因此,“以超线程或不”将工作负载和CPU L1 / L2高速缓存大小/存储器速度等取决于两个
  • OS的可能有对位/偏移对某些线程和Thread.setPriority可能无法兑现(在Linux上它通常不兑现)。
  • 它可以设置进程的亲缘性,不允许一些核心。 因此,了解有超线程不会有任何显著凭借在这样的情况下。

话虽这么说:你应该有一个工作线程和建议,如何建立给出的架构的具体大小设置。



Answer 5:

有没有办法确定要从纯Java(毕竟是一个合乎逻辑的核心是核心,如果使用HT或没有实现)。 要注意的是,到目前为止所提出的解决方案可以解决您的要求(如你要求),但不是唯一的英特尔CPU的报价超线程的形式(SPARC想到,我敢肯定有其他人也)。

您还没有考虑到, 即使你确定系统采用HT,你将无法控制与从Java核心线程一个亲和力。 所以,你还是在操作系统的线程调度的摆布。 虽然有可能出现的情况,其中少线程可能更好(因为减少了高速缓存捣毁的)执行有没有办法来确定静态多少线程应使用(所有CPU之后的确实有很大的不同缓存大小(在低端的范围为256KB到>在服务器16MB,可以合理预期时下,这必将有新的每一代改变)。

简单地使它成为一个可配置的设置,任何试图确定这一点没有确切知道目标系统是徒劳的。



Answer 6:

有没有办法做到这一点,有一两件事你可以做的是创建一个线程池Runtime.getRuntime().availableProcessors()线程在应用程序和要求时谈到在使用。

这样你就可以有0 - Runtime.getRuntime().availableProcessors()的线程数。



Answer 7:

您可能无法查询操作系统或运行可靠,但你可以运行一个快速基准。

逐步增加自旋锁的线程,测试,看看每一个新的线程迭代以及前面。 一旦一个线程的性能低于周围以前的测试各占一半(至少对于英特尔来说,我不知道SPARC),你知道你已经开始分享了超线程核心。



文章来源: Is it possible to check in Java if the CPU is hyper threading?