【问题标题】:Java on Linux: Measuring elapsed time using System.nanotime() for a thread that blocksLinux 上的 Java:使用 System.nanotime() 测量阻塞线程的经过时间
【发布时间】:2013-12-13 01:23:15
【问题描述】:

我有一个从ArrayBlockingQueue() connectionPool. 获取对象的线程如果 ArrayBlockingQueue() 为空,则该线程可能会被阻塞。为了测量调用线程被阻塞的时间,我使用以下代码:

long start = System.nanoTime();
DataBaseEndPoint dbep = connectionPool.take();
long end = System.nanoTime();
long elapsed = (end - start)/1000000;

现在,我担心未阻塞的线程可能会开始在多处理器机器中的不同处理器上运行。在这种情况下,我不完全确定不同处理器上使用的“系统计时器”是否相同。 这篇博文 (http://www.javacodegeeks.com/2012/02/what-is-behind-systemnanotime.html) 建议 Linux 为每个处理器使用不同的时间戳计数器(也用于 System.nanotime()),这确实会弄乱上面示例中的经过时间计算。

该值是从带有 CLOCK_MONOTONIC 标志的 clock_gettime 读取的 使用 TSC 或 HPET。与 Windows 的唯一区别是 Linux 甚至没有尝试同步从不同 CPU 读取的 TSC 值, 它只是按原样返回。这意味着价值可以反弹并且 与读取它的 CPU 的依赖关系向前跳转。

但是,此链接 (http://lwn.net/Articles/209101/) 表明 TSC 不再用于高分辨率计时器。

...最近更新的高分辨率计时器和动态滴答补丁 set 包括一项禁用 TSC 的更改。看来 高分辨率计时器和动态滴答功能不兼容 TSC...

那么,问题是,Linux 机器目前使用什么来将值返回给System.nanotime()?并且,在上述情况下使用System.nanotime() safe 来测量经过的时间(在另一个处理器上启动的阻塞线程)。如果不安全,还有什么办法?

【问题讨论】:

    标签: java linux benchmarking


    【解决方案1】:

    关于虚拟机(以及整个生活)的无价之宝是抽象。线程的执行时间不会因内核数量而异;不是在 Linux 中,也不是在 Windows 等中......我希望我没有误解你的问题。

    (虽然我用的是currentTimeMillis(),当然纳米时间在不同的尺度上是一样的)

    查看我制作的以下示例:

    public class SynchThreads {
    
        public static void main(String[] args) throws InterruptedException {
            GreedyTask gtA = new GreedyTask("A");
            GreedyTask gtB = new GreedyTask("B");
            Thread a = new Thread(gtA);
            Thread b = new Thread(gtB);
            a.start();
            b.start();
            a.join();
            b.join();
            System.out.println(gtA.toString()+" running time: "+gtA.getRunningTime());
            System.out.println(gtB.toString()+" running time: "+gtB.getRunningTime());
        }
    
        private static class GreedyTask implements Runnable {
    
            private long startedTime, finishedTime, totalRunTime;
            private String myName;
    
            public GreedyTask(String pstrName) {
                myName = pstrName;
            }
    
            public void run() {
                try {
                    startedTime = System.currentTimeMillis();
                    randomPowerNap(this);
                    finishedTime = System.currentTimeMillis();
                    totalRunTime = finishedTime - startedTime;
                } catch (Exception e) { System.err.println(e.getMessage()); }
            }
    
            public String toString() { return ("Task: " + myName); }
            public long getRunningTime() { return this.totalRunTime; }
        }
    
        private static synchronized void randomPowerNap(GreedyTask gt) throws       InterruptedException {
            System.out.println("Executing: "+gt.toString());
            long random = Math.round(Math.random()*15000);
            System.out.println("Random time for "+gt+" is: "+random);
            Thread.sleep(random);
        }
    }
    

    以下是在 4 核 windows 机器上运行的输出:

    Executing: Task: A
    Random time for Task: A is: 1225
    Executing: Task: B
    Random time for Task: B is: 4383
    Task: A running time: 1226
    Task: B running time: 5609 // what's funny about this? this is equal to Btime - Atime
    

    这是在 4 核 Linux 机器上运行的:

    Executing: Task: A
    Random time for Task: A is: 13577
    Executing: Task: B
    Random time for Task: B is: 5340
    Task: A running time: 13579
    Task: B running time: 18920 // same results
    

    结论:B 总时间增加了它在 randomPowerNap 被 A 阻塞时必须等待的时间,因此,由于虚拟机的硬件抽象,线程在运行时间上没有区别,因为它们都在“VIRTUAL BIG”中运行CORE',如果你知道我的意思的话。

    我希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-18
      • 2010-10-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多