4

この質問はベンチマークに関するものではありません。

私は、期間時間Tの近くで動作するはずのJavaスレッドサイクルを持っています:

public class MyRunnable implements Runnable {

    private final long period = 10000L; //period T, in this case 10 secs

    public void run() {
        while() {
            long startTime = this.getTime();

            this.doStuff();

            long endTime = this.getTime();
            long executionTime = endTime - startTime;
            if(executionTime < this.period) {
                long sleepTime = (this.period - executionTime);
                try {
                     Thread.sleep(sleepTime);
                } catch(InterruptedException iex) {/*handle iex*/}
            }
        }
    }

    private long getTime() {
        return System.currentTimeMillis();
    }

    private void doStuff() {/*do stuff*/}

} 

もちろん、スケジュール プリプションの選択によっては、Thread.sleep(sleepTime)よりわずかに大きくなる可能性がありますsleepTime。しかし、平均すると、このアプローチは周期 T に近い平均近似値を提供します。

問題

メソッド:

private long getTime() {
    return System.currentTimeMillis();
}

壁時計の基準時間を提供します。マシンのクロックが前後に変化した場合、この実装は周期 T の近似値を提供できません。たとえば、次のようになります。

long t1 = getTime();
Thread.sleep(30000);
long t2 = getTime();
System.out.println(t2 - t1);

Thread.sleep(30000)「実行」中に誰かが手動で時計を 3 分進めると、204283 のように表示されます。

システム クロックは常に変化しているため (タイムサーバーの同期、システムの負荷、ユーザー設定など) System.currentTimeMillis()、私のニーズを満たすには十分な信頼性がありません。

失敗した解決策

より堅牢な時間参照を提供するために、getTime メソッドの次の実装を試しました。

long getTime() {
    long result;
    ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
    if (mxBean.isThreadCpuTimeSupported()) {
        result = mxBean.getCurrentThreadCpuTime()/1000000L;
    } else {
        throw new RuntimeException("unsupported thread cpu time");
    }
    return result;
}

の問題は、結果として得られる時間が、その瞬間に残された時間ではなく、スレッドによって消費さgetCurrentThreadCpuTimeれた CPU 時間になることです。スレッドがスリープまたはブロックされている残り時間は考慮されません。例えば:

long t1 = getTime();
Thread.sleep(30000);
long t2 = getTime();
System.out.println(t2 - t1);

getCurrentThreadCpuTime驚くべきことに、 getTime の実装によって "0" (ゼロ) が出力されます。

私が欲しいもの

私が必要としているのは次のようなものだと思います:

private long getTime() {
    long cpuCycles = getAmountOfCPUCyclesSinceTheProgramStarted();
    long cpuFrequency = getCPUFrequency();
    long result = cpuCycles / cpuFrequency;
    return result;
}

問題は、クロスプラットフォームの方法getAmountOfCPUCyclesSinceTheProgramStarted()でJava を実装する方法を見つけられなかったことです。getCPUFrequency()

最後に、私の質問は次のとおりです。信頼性の高いクロスプラットフォームの方法で Java のメソッドに費やされた時間を取得するにはどうすればよいですか?

4

1 に答える 1