- メソッドの実行時間を取得するにはどうすればよいですか?
Timer
タスクにかかる時間を計るなど のユーティリティ クラスはありますか?
Google での検索のほとんどは、スレッドとタスクをスケジュールするタイマーの結果を返しますが、これは私が望んでいるものではありません。
Timer
タスクにかかる時間を計るなど のユーティリティ クラスはありますか?Google での検索のほとんどは、スレッドとタスクをスケジュールするタイマーの結果を返しますが、これは私が望んでいるものではありません。
常に昔ながらの方法があります。
long startTime = System.nanoTime();
methodToTime();
long endTime = System.nanoTime();
long duration = (endTime - startTime); //divide by 1000000 to get milliseconds.
私は単純な答えで行きます。私のために働きます。
long startTime = System.currentTimeMillis();
doReallyLongThing();
long endTime = System.currentTimeMillis();
System.out.println("That took " + (endTime - startTime) + " milliseconds");
それは非常にうまく機能します。解像度は明らかにミリ秒単位であり、System.nanoTime() を使用するとより適切に処理できます。どちらにもいくつかの制限があります (オペレーティング システムのスケジュール スライスなど) が、これはかなりうまく機能します。
数回実行して平均すると (多いほど良い)、まともなアイデアが得られます。
みんなおいでよ!誰もそれを行うためのGuavaの方法について言及していません(これは間違いなく素晴らしいです):
import com.google.common.base.Stopwatch;
Stopwatch timer = Stopwatch.createStarted();
//method invocation
LOG.info("Method took: " + timer.stop());
良い点は、Stopwatch.toString() が測定の時間単位を適切に選択することです。つまり、値が小さい場合は 38 ns を出力し、長い場合は 5m 3s を表示します。
さらに良い:
Stopwatch timer = Stopwatch.createUnstarted();
for (...) {
timer.start();
methodToTrackTimeFor();
timer.stop();
methodNotToTrackTimeFor();
}
LOG.info("Method took: " + timer);
注: Google Guava には Java 1.6 以降が必要です
プロファイラー (JProfiler、Netbeans プロファイラー、Visual VM、Eclipse プロファイラーなど) を使用します。最も正確な結果が得られ、最も邪魔になりません。これらはプロファイリングに組み込みの JVM メカニズムを使用し、必要に応じてスタック トレース、実行パス、およびより包括的な結果などの追加情報を提供することもできます。
完全に統合されたプロファイラーを使用する場合、メソッドのプロファイリングは簡単ではありません。右クリックして、プロファイラー -> ルート メソッドに追加します。次に、テスト実行またはデバッガーを行っていたのと同じように、プロファイラーを実行します。
System.currentTimeMillis();
アルゴリズムのパフォーマンスを測定するための良いアプローチではありません。ユーザーがコンピュータ画面を見ている合計時間を測定します。バックグラウンドでコンピューター上で実行されている他のすべての時間も含まれます。ワークステーションで多くのプログラムを実行している場合、これは大きな違いを生む可能性があります。
適切なアプローチはjava.lang.management
パッケージを使用することです。
http://nadeausoftware.com/articles/2008/03/java_tip_how_get_cpu_and_user_time_benchmarking Web サイト (アーカイブ リンク)から:
getCpuTime()
メソッドはそれらの合計を提供します:
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
public class CPUUtils {
/** Get CPU time in nanoseconds. */
public static long getCpuTime( ) {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
bean.getCurrentThreadCpuTime( ) : 0L;
}
/** Get user time in nanoseconds. */
public static long getUserTime( ) {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
bean.getCurrentThreadUserTime( ) : 0L;
}
/** Get system time in nanoseconds. */
public static long getSystemTime( ) {
ThreadMXBean bean = ManagementFactory.getThreadMXBean( );
return bean.isCurrentThreadCpuTimeSupported( ) ?
(bean.getCurrentThreadCpuTime( ) - bean.getCurrentThreadUserTime( )) : 0L;
}
}
これはおそらくあなたが私に言いたかったことではありませんが、これは AOP の良い使い方です。メソッドの周りにプロキシインターセプターを巻き付け、そこでタイミングをとります。
残念ながら、AOP の内容、理由、方法は、この回答の範囲を超えていますが、それが私が行う方法です。
編集:熱心な場合は、開始するための Spring AOP へのリンクを次に示します。これは、Iive が Java で見つけた最もアクセスしやすい AOP の実装です。
また、他のすべての人の非常に単純な提案を考えると、AOP は、タイミングなどのものがコードに侵入したくない場合に使用されることを追加する必要があります。しかし、多くの場合、そのような単純で簡単なアプローチは問題ありません。
Java 8 では、すべての通常のメソッドで次のようなこともできます。
Object returnValue = TimeIt.printTime(() -> methodeWithReturnValue());
//do stuff with your returnValue
TimeIt のように:
public class TimeIt {
public static <T> T printTime(Callable<T> task) {
T call = null;
try {
long startTime = System.currentTimeMillis();
call = task.call();
System.out.print((System.currentTimeMillis() - startTime) / 1000d + "s");
} catch (Exception e) {
//...
}
return call;
}
}
このメソッドを使用すると、コードを壊すことなく、コードのどこでも簡単に時間を測定できます。この簡単な例では、時間を出力するだけです。たとえば、DebugMode などでのみ時間を出力するために、TimeIt のスイッチを追加できますか。
Functionを使用している場合は、次のようなことができます。
Function<Integer, Integer> yourFunction= (n) -> {
return IntStream.range(0, n).reduce(0, (a, b) -> a + b);
};
Integer returnValue = TimeIt.printTime2(yourFunction).apply(10000);
//do stuff with your returnValue
public static <T, R> Function<T, R> printTime2(Function<T, R> task) {
return (t) -> {
long startTime = System.currentTimeMillis();
R apply = task.apply(t);
System.out.print((System.currentTimeMillis() - startTime) / 1000d
+ "s");
return apply;
};
}
また、時間の計測には Apache commons の StopWatch クラスを利用できます。
サンプルコード
org.apache.commons.lang.time.StopWatch sw = new org.apache.commons.lang.time.StopWatch();
System.out.println("getEventFilterTreeData :: Start Time : " + sw.getTime());
sw.start();
// Method execution code
sw.stop();
System.out.println("getEventFilterTreeData :: End Time : " + sw.getTime());
参考までに、JEP 230: Microbenchmark Suiteは、次のことを行うOpenJDKプロジェクトです。
マイクロベンチマークの基本的なスイートを JDK ソース コードに追加し、開発者が既存のマイクロベンチマークを簡単に実行して新しいマイクロベンチマークを作成できるようにします。
この機能はJava 12で導入されました。
以前のバージョンの Java については、JEP 230 のベースとなっているJava Microbenchmark Harness (JMH)プロジェクトを参照してください。
ツールを使用せず、実行時間の短いメソッドの時間を計測したい場合は、少しひねりを加えてください。1秒に達するまで、実行回数を2倍にするなど、何度も実行してください。したがって、System.nanoTimeの呼び出しなどの時間も、System.nanoTimeの精度も結果に大きく影響しません。
int runs = 0, runsPerRound = 10;
long begin = System.nanoTime(), end;
do {
for (int i=0; i<runsPerRound; ++i) timedMethod();
end = System.nanoTime();
runs += runsPerRound;
runsPerRound *= 2;
} while (runs < Integer.MAX_VALUE / 2 && 1000000000L > end - begin);
System.out.println("Time for timedMethod() is " +
0.000000001 * (end-begin) / runs + " seconds");
もちろん、壁掛け時計の使用に関する注意事項が適用されます。JITコンパイルの影響、複数のスレッド/プロセスなど。したがって、最初にメソッドを何度も実行して、JITコンパイラがその作業を実行するようにする必要があります。このテストを複数回繰り返し、実行時間を最短にします。
この目的のために、AspectJ および Java アノテーションを使用しています。メソッドの実行時間を知る必要がある場合は、単純に注釈を付けます。より高度なバージョンでは、実行時に有効または無効にできる独自のログ レベルを使用できます。
public @interface Trace {
boolean showParameters();
}
@Aspect
public class TraceAspect {
[...]
@Around("tracePointcut() && @annotation(trace) && !within(TraceAspect)")
public Object traceAdvice ( ProceedingJintPoint jP, Trace trace ) {
Object result;
// initilize timer
try {
result = jp.procced();
} finally {
// calculate execution time
}
return result;
}
[...]
}
本当に良いコードです。
http://www.rgagnon.com/javadetails/java-0585.html
import java.util.concurrent.TimeUnit;
long startTime = System.currentTimeMillis();
........
........
........
long finishTime = System.currentTimeMillis();
String diff = millisToShortDHMS(finishTime - startTime);
/**
* converts time (in milliseconds) to human-readable format
* "<dd:>hh:mm:ss"
*/
public static String millisToShortDHMS(long duration) {
String res = "";
long days = TimeUnit.MILLISECONDS.toDays(duration);
long hours = TimeUnit.MILLISECONDS.toHours(duration)
- TimeUnit.DAYS.toHours(TimeUnit.MILLISECONDS.toDays(duration));
long minutes = TimeUnit.MILLISECONDS.toMinutes(duration)
- TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(duration));
long seconds = TimeUnit.MILLISECONDS.toSeconds(duration)
- TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(duration));
if (days == 0) {
res = String.format("%02d:%02d:%02d", hours, minutes, seconds);
}
else {
res = String.format("%dd%02d:%02d:%02d", days, hours, minutes, seconds);
}
return res;
}
Perf4jを使用できます。非常にクールなユーティリティ。使い方は簡単
String watchTag = "target.SomeMethod";
StopWatch stopWatch = new LoggingStopWatch(watchTag);
Result result = null; // Result is a type of a return value of a method
try {
result = target.SomeMethod();
stopWatch.stop(watchTag + ".success");
} catch (Exception e) {
stopWatch.stop(watchTag + ".fail", "Exception was " + e);
throw e;
}
詳細については、開発者ガイドをご覧ください
new Timer(""){{
// code to time
}}.timeMe();
public class Timer {
private final String timerName;
private long started;
public Timer(String timerName) {
this.timerName = timerName;
this.started = System.currentTimeMillis();
}
public void timeMe() {
System.out.println(
String.format("Execution of '%s' takes %dms.",
timerName,
started-System.currentTimeMillis()));
}
}
AOP/AspectJ とjcabi-aspects の@Loggable
注釈を使用すると、簡単かつコンパクトに実行できます。
@Loggable(Loggable.DEBUG)
public String getSomeResult() {
// return some value
}
このメソッドへのすべての呼び出しは、DEBUG
ログ レベルとともに SLF4J ログ機能に送信されます。また、すべてのログ メッセージには実行時間が含まれます。
私は基本的にこれのバリエーションを行いますが、ホットスポットのコンパイルがどのように機能するかを考えると、正確な結果を得たい場合は、最初のいくつかの測定値を捨てて、実際の (アプリケーション固有の読み取り) アプリケーションでメソッドを使用していることを確認する必要があります。
JIT がそれをコンパイルすることを決定した場合、数値は大きく異なります。だから気をつけて
それにはいくつかの方法があります。私は通常、次のようなものを使用するだけに戻ります。
long start = System.currentTimeMillis();
// ... do something ...
long end = System.currentTimeMillis();
または System.nanoTime(); と同じこと
物事のベンチマーク側の何かについては、これもあるようです: http://jetm.void.fm/ただし、試したことはありません。
壁時計の時間が必要な場合
long start_time = System.currentTimeMillis();
object.method();
long end_time = System.currentTimeMillis();
long execution_time = end_time - start_time;
long startTime = System.currentTimeMillis();
// code goes here
long finishTime = System.currentTimeMillis();
long elapsedTime = finishTime - startTime; // elapsed time in milliseconds
「skaffman」が言ったように、AOP を使用するか、ランタイム バイトコード ウィービングを使用できます。これは、ユニット テスト メソッド カバレッジ ツールが呼び出されたメソッドにタイミング情報を透過的に追加するために使用するのと同じです。
Emma ( http://downloads.sourceforge.net/emma/emma-2.0.5312-src.zip?modtime=1118607545&big_mirror=0 )などのオープン ソース ツール ツールで使用されるコードを確認できます。もう 1 つのオープンソース カバレッジ ツールはhttp://prdownloads.sourceforge.net/cobertura/cobertura-1.9-src.zip?downloadです。
あなたが最終的にあなたが設定したことをなんとかすることができたら、pls. Ant タスク/jar を使用して、ここのコミュニティと共有してください。
正解からコードを修正して、数秒で結果を取得しました。
long startTime = System.nanoTime();
methodCode ...
long endTime = System.nanoTime();
double duration = (double)(endTime - startTime) / (Math.pow(10, 9));
Log.v(TAG, "MethodName time (s) = " + duration);
自分のマシンでのパフォーマンス測定
System.nanoTime() : 750ns
System.currentTimeMillis() : 18ns
前述のように、System.nanoTime()
経過時間を測定すると考えられます。ループ内などで使用する場合は、コストに注意してください。
わかりました、これは関数の単純な単純なタイミングに使用される単純なクラスです。その下に例があります。
public class Stopwatch {
static long startTime;
static long splitTime;
static long endTime;
public Stopwatch() {
start();
}
public void start() {
startTime = System.currentTimeMillis();
splitTime = System.currentTimeMillis();
endTime = System.currentTimeMillis();
}
public void split() {
split("");
}
public void split(String tag) {
endTime = System.currentTimeMillis();
System.out.println("Split time for [" + tag + "]: " + (endTime - splitTime) + " ms");
splitTime = endTime;
}
public void end() {
end("");
}
public void end(String tag) {
endTime = System.currentTimeMillis();
System.out.println("Final time for [" + tag + "]: " + (endTime - startTime) + " ms");
}
}
使用例:
public static Schedule getSchedule(Activity activity_context) {
String scheduleJson = null;
Schedule schedule = null;
/*->*/ Stopwatch stopwatch = new Stopwatch();
InputStream scheduleJsonInputStream = activity_context.getResources().openRawResource(R.raw.skating_times);
/*->*/ stopwatch.split("open raw resource");
scheduleJson = FileToString.convertStreamToString(scheduleJsonInputStream);
/*->*/ stopwatch.split("file to string");
schedule = new Gson().fromJson(scheduleJson, Schedule.class);
/*->*/ stopwatch.split("parse Json");
/*->*/ stopwatch.end("Method getSchedule");
return schedule;
}
コンソール出力のサンプル:
Split time for [file to string]: 672 ms
Split time for [parse Json]: 893 ms
Final time for [get Schedule]: 1565 ms
spring core プロジェクトのストップウォッチ クラスを使用できます。
コード:
StopWatch stopWatch = new StopWatch()
stopWatch.start(); //start stopwatch
// write your function or line of code.
stopWatch.stop(); //stop stopwatch
stopWatch.getTotalTimeMillis() ; ///get total time
ストップウォッチのドキュメント: シンプルなストップ ウォッチで、多数のタスクのタイミングを計り、合計実行時間と各名前付きタスクの実行時間を公開します。System.currentTimeMillis() の使用を隠して、アプリケーション コードの読みやすさを改善し、計算エラーの可能性を減らします。このオブジェクトはスレッドセーフになるように設計されておらず、同期を使用しないことに注意してください。このクラスは通常、運用アプリケーションの一部としてではなく、概念実証中および開発中にパフォーマンスを検証するために使用されます。
時間を知りたい場合は、この方法を試すことができます。
long startTime = System.currentTimeMillis();
//@ Method call
System.out.println("Total time [ms]: " + (System.currentTimeMillis() - startTime));
これは、Google 検索で検索にかかった時間と同じように、整形済みの経過秒数をきれいに印刷した文字列です。
long startTime = System.nanoTime();
// ... methodToTime();
long endTime = System.nanoTime();
long duration = (endTime - startTime);
long seconds = (duration / 1000) % 60;
// formatedSeconds = (0.xy seconds)
String formatedSeconds = String.format("(0.%d seconds)", seconds);
System.out.println("formatedSeconds = "+ formatedSeconds);
// i.e actual formatedSeconds = (0.52 seconds)
測定が必要なアクションをブロックにラップできるように、java がより優れた機能サポートを持っているとよいでしょう。
measure {
// your operation here
}
Java では、これは冗長に見える無名関数によって実行できます。
public interface Timer {
void wrap();
}
public class Logger {
public static void logTime(Timer timer) {
long start = System.currentTimeMillis();
timer.wrap();
System.out.println("" + (System.currentTimeMillis() - start) + "ms");
}
public static void main(String a[]) {
Logger.logTime(new Timer() {
public void wrap() {
// Your method here
timeConsumingOperation();
}
});
}
public static void timeConsumingOperation() {
for (int i = 0; i<=10000; i++) {
System.out.println("i=" +i);
}
}
}
System.nanoTime()
実行時間を測定するための非常に正確なシステム ユーティリティです。ただし、プリエンプティブ スケジューラ モード (デフォルト) で実行している場合、このユーティリティは実際には CPU 時間ではなく壁時計時間を測定します。したがって、システムの負荷に応じて、実行ごとに異なる実行時間の値に気付く場合があります。CPU 時間を探す場合は、プログラムをリアルタイム モードで実行するとうまくいくと思います。RT Linux を使用する必要があります。リンク: Linux でのリアルタイム プログラミング