วิธีจับเวลาความเร็วในการเรียกใช้โปรแกรม Java


85

คุณใช้เวลาในการทำงานของโปรแกรม java ได้อย่างไร? ฉันไม่แน่ใจว่าควรใช้คลาสอะไรในการทำสิ่งนี้

ฉันกำลังมองหาสิ่งที่ชอบ:

// Some timer starts here
for (int i = 0; i < length; i++) {
  // Do something
}
// End timer here

System.out.println("Total execution time: " + totalExecutionTime);

คำตอบ:


139
final long startTime = System.currentTimeMillis();
for (int i = 0; i < length; i++) {
  // Do something
}
final long endTime = System.currentTimeMillis();

System.out.println("Total execution time: " + (endTime - startTime));

2
มันควรจะเป็น nanoTime จริงๆ
— Eugene

6
ไม่ควรเป็น nanoTime ดูคำตอบของ rhu
— fabspro

4
มีเหตุผลบางอย่างที่คุณใช้ "สุดท้าย" ที่นี่หรือไม่ จะแตกต่างกันอย่างไรหากคุณทิ้งคีย์เวิร์ดนั้น
— dijxtra

9
การใช้ @dijxtra finalมีข้อดีที่คุณไม่สามารถกำหนดให้โดยบังเอิญได้ (เช่นเดียวกับข้อดีอื่น ๆ เช่นการเข้าถึงคลาสแบบไม่ระบุตัวตนเป็นต้น) ในรหัสนี้จะไม่สร้างความแตกต่าง เป็นวิธีปฏิบัติที่ค่อนข้างธรรมดาที่จะทำทุกอย่างfinalและยกเลิกการปรับขนาดเท่านั้นfinalหากคุณต้องการ
— wchargin

1
รหัสที่จะทดสอบพร้อมกับการวัดเวลาควรรันหลาย ๆ ครั้งและควรทิ้งผลลัพธ์แรก ครั้งแรกอาจรวมถึงเวลาในการโหลดคลาสเป็นต้นด้วยการรันหลายครั้งคุณจะได้รับค่าเฉลี่ยซึ่งมีประโยชน์และเชื่อถือได้มากกว่า
— อรุณราม

34

โปรดทราบว่ามีปัญหาบางอย่างที่System#nanoTime()ไม่สามารถใช้กับ CPU แบบมัลติคอร์ได้อย่างน่าเชื่อถือเพื่อบันทึกเวลาที่ผ่านไป ... แต่ละคอร์จะมี TSC ของตัวเอง ( Time Stamp Counter ) : ตัวนับนี้ใช้เพื่อรับเวลานาโน (จริงๆมันคือ จำนวนเห็บตั้งแต่ CPU บูต)

ดังนั้นเว้นแต่ว่า OS จะแปรปรวนเวลา TSC เพื่อให้คอร์ซิงค์กันอยู่ดังนั้นหากเธรดได้รับการกำหนดเวลาไว้ที่หนึ่งคอร์เมื่อใช้การอ่านเวลาเริ่มต้นจากนั้นเปลี่ยนไปใช้คอร์อื่นเวลาสัมพัทธ์อาจดูเหมือนกระโดดถอยหลังเป็นระยะ ๆ และส่งต่อ

ฉันสังเกตเห็นสิ่งนี้มานานแล้วใน AMD / Solaris ซึ่งเวลาที่ผ่านไประหว่างจุดเวลาสองจุดบางครั้งกลับมาเป็นค่าลบหรือจำนวนบวกที่มากโดยไม่คาดคิด มีแพทช์เคอร์เนล Solaris และการตั้งค่า BIOS ที่จำเป็นเพื่อบังคับใช้ AMD PowerNow! ปิดซึ่งดูเหมือนจะแก้ไขได้

นอกจากนี้ยังมี (AFAIK) บั๊กที่ยังไม่ได้แก้ไขเมื่อใช้ java System#nanoTime()ในสภาพแวดล้อม VirtualBox ทำให้เกิดปัญหาการเธรดแบบไม่ต่อเนื่องที่แปลกประหลาดสำหรับเราเนื่องจากjava.util.concurrencyแพคเกจส่วนใหญ่ต้องอาศัยเวลานาโน

ดูสิ่งนี้ด้วย:

System.nanoTime () ไร้ประโยชน์โดยสิ้นเชิงหรือไม่? http://vbox.innotek.de/pipermail/vbox-trac/2010- มกราคม/135631.html


9

คุณได้รับเวลาของระบบปัจจุบันเป็นมิลลิวินาที:

final long startTime = System.currentTimeMillis();

จากนั้นคุณจะทำในสิ่งที่คุณกำลังจะทำ:

for (int i = 0; i < length; i++) {
  // Do something
}

จากนั้นคุณจะเห็นว่าใช้เวลานานแค่ไหน:

final long elapsedTimeMillis = System.currentTimeMillis() - startTime;

คำตอบของ BalusC ก็ถูกต้องเช่นกัน ขึ้นอยู่กับความละเอียดของตัวจับเวลาที่ต้องการและเหตุใดคุณจึงต้องใช้เวลา
— Jonathan Feinberg

9

คุณสามารถใช้ประโยชน์จากSystem#nanoTime()ไฟล์. รับก่อนและหลังการดำเนินการและทำคณิตศาสตร์ เป็นที่ต้องการด้านบนSystem#currentTimeMillis()เนื่องจากมีความแม่นยำที่ดีกว่า ขึ้นอยู่กับฮาร์ดแวร์และแพลตฟอร์มที่ใช้มิฉะนั้นคุณอาจได้รับช่องว่างที่ไม่ถูกต้องในเวลาที่ผ่านไป ที่นี่ด้วย Core2Duo บน Windows ระหว่าง 0 ถึง ~ 15ms จริง ๆ แล้วไม่มีอะไรสามารถคำนวณได้

เครื่องมือที่สูงขึ้นเป็นProfiler


ตัวจับเวลาบน Windows ไม่มีความละเอียดที่ดีเป็นพิเศษโดยค่าเริ่มต้น มีเป็นตัวจับเวลาที่มีประสิทธิภาพสูงเกินไป แต่มันยากมากที่จะใช้แม้จะมาจาก C และ Java ไม่ได้ (AFAIK) ให้เข้าถึงต่ำว่าระดับของ hackery โดยไม่ต้อง thunk JNI
— Donal Fellows

1
nanoTime()มีปัญหาหนึ่งอย่าง (อย่างน้อยใน Windows); การประทับเวลาเฉพาะสำหรับคอร์โปรเซสเซอร์ ฉันมีโปรแกรมที่มีเวลาดำเนินการติดลบเนื่องจากมีการประทับเวลา "เริ่มต้น" บนหนึ่งคอร์และการประทับเวลา "หยุด" บนคอร์อื่น
— gustafc

3

สำหรับสิ่งง่ายๆSystem.currentTimeMillis ()สามารถทำงานได้

เป็นเรื่องปกติมากที่ IDE ของฉันถูกตั้งค่าดังนั้นเมื่อป้อน "t0" มันจะสร้างบรรทัดต่อไปนี้ให้ฉัน:

final long t0 = System.currentTimeMillis()

แต่สำหรับสิ่งที่ซับซ้อนกว่านั้นคุณอาจต้องการใช้การวัดเวลาทางสถิติเช่นที่นี่ (เลื่อนลงเล็กน้อยและดูการวัดเวลาที่แสดงรวมถึงค่าเบี่ยงเบนมาตรฐานเป็นต้น):

http://perf4j.codehaus.org/devguide.html


+1 สำหรับชี้รหัสตัวสร้างอัตโนมัติ ฉันใช้คำสั่งที่คล้ายกันตลอดเวลาและไม่รู้เกี่ยวกับการแทรกเทมเพลตโค้ด เพิ่งค้นพบวิธีทำคราสแล้วมันจะช่วยได้แน่นอน!
— Jason

บริการ Codehaus ทั้งหมดถูกยกเลิก ลิงก์ของคุณใช้งานไม่ได้แล้ว
— naXa

2

การใช้ AOP / AspectJ และ@Loggableคำอธิบายประกอบจากแง่มุมของ jcabiคุณสามารถทำได้ง่ายและกะทัดรัด:

@Loggable(Loggable.DEBUG)
public String getSomeResult() {
  // return some value
}

การเรียกใช้วิธีนี้ทุกครั้งจะถูกส่งไปยังระบบบันทึกข้อมูล SLF4J พร้อมDEBUGระดับการบันทึก และทุกข้อความบันทึกจะรวมเวลาดำเนินการด้วย


2

วิธีค้นหาเวลาดำเนินการใน Java มีดังนี้:

1) System.nanoTime ()

long startTime = System.nanoTime();
.....your code....
long endTime   = System.nanoTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in nanoseconds  : " + totalTime);
System.out.println("Execution time in milliseconds : " + totalTime / 1000000);

2) System.currentTimeMillis ()

long startTime = System.currentTimeMillis();
.....your code....
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds  : " + totalTime);

3) ทันทีตอนนี้ ()

long startTime = Instant.now().toEpochMilli();
.....your code....
long endTime = Instant.now().toEpochMilli();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

หรือ

Instant start = Instant.now();
.....your code....
Instant end = Instant.now();
Duration interval = Duration.between(start, end);
System.out.println("Execution time in seconds: " +interval.getSeconds());

4) Date.getTime ()

long startTime = new Date().getTime();
.....your code....
long endTime = new Date().getTime();
long totalTime = endTime - startTime;
System.out.println("Execution time in milliseconds: " + totalTime);

1

ใช้เวลาstartTime=System.currentTimeMillis()เริ่มต้นนานที่ด้านบนของลูป

วางไว้long endTime= System.currentTimeMillis();นอกส่วนท้ายของลูป คุณจะต้องลบค่าเพื่อให้ได้รันไทม์เป็นมิลลิวินาที

หากคุณต้องการเวลาเป็นนาโนวินาทีลองดู System.nanoTime()


1

ฉันสร้างฟังก์ชันลำดับที่สูงขึ้นซึ่งใช้รหัสที่คุณต้องการวัดเป็นแลมบ์ดา:

class Utils {

    public static <T> T timeIt(String msg, Supplier<T> s) {
        long startTime = System.nanoTime();
        T t = s.get();
        long endTime = System.nanoTime();
        System.out.println(msg + ": " + (endTime - startTime) + " ns");
        return t;
    }

    public static void timeIt(String msg, Runnable r) {
       timeIt(msg, () -> {r.run(); return null; });
    }
}

เรียกแบบนั้น:

Utils.timeIt("code 0", () ->
        System.out.println("Hallo")
);

// in case you need the result of the lambda
int i = Utils.timeIt("code 1", () ->
        5 * 5
);

เอาท์พุต:

รหัส 0: 180528 ns
รหัส 1: 12003 ns

ขอขอบคุณเป็นพิเศษสำหรับAndy Turnerที่ช่วยฉันลดความซ้ำซ้อน ดูที่นี่ .



0

คุณอาจลอง Perf4J เป็นวิธีที่เรียบร้อยในการทำสิ่งที่คุณกำลังมองหาและช่วยในการรวบรวมสถิติประสิทธิภาพเช่นค่าเฉลี่ยค่าต่ำสุดค่าเบี่ยงเบนมาตรฐานและธุรกรรมต่อวินาทีในช่วงเวลาที่กำหนด สารสกัดจากhttp://perf4j.codehaus.org/devguide.html :

StopWatch stopWatch = new LoggingStopWatch();

try {
    // the code block being timed - this is just a dummy example
    long sleepTime = (long)(Math.random() * 1000L);
    Thread.sleep(sleepTime);
    if (sleepTime > 500L) {
        throw new Exception("Throwing exception");
    }

    stopWatch.stop("codeBlock2.success", "Sleep time was < 500 ms");
} catch (Exception e) {
    stopWatch.stop("codeBlock2.failure", "Exception was: " + e);
}

เอาท์พุต:

INFO: start[1230493236109] time[447] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493236719] time[567] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493237286] time[986] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493238273] time[194] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238467] time[463] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493238930] time[310] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239241] time[610] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]
INFO: start[1230493239852] time[84] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239937] time[30] tag[codeBlock2.success] message[Sleep time was < 500 ms]
INFO: start[1230493239968] time[852] tag[codeBlock2.failure] message[Exception was: java.lang.Exception: Throwing exception]

0
public class someClass
{
   public static void main(String[] args) // your app start point
   {
       long start = java.util.Calendar.getInstance().getTimeInMillis();

       ... your stuff ...

       long end = java.util.Calendar.getInstance().getTimeInMillis();
       System.out.println("it took this long to complete this stuff: " + (end - start) + "ms");
   }
}

0

การใช้ System.currentTimeMillis () เป็นวิธีที่เหมาะสมในการดำเนินการนี้ แต่ถ้าคุณใช้บรรทัดคำสั่งและคุณต้องการกำหนดเวลาทั้งโปรแกรมโดยประมาณและรวดเร็วให้นึกถึง:

time java App

ซึ่งช่วยให้คุณไม่ต้องแก้ไขรหัสและเวลาแอปของคุณ


ขึ้นอยู่กับว่าคุณเรียกใช้โค้ดอย่างไร หากเป็นโค้ดที่ใช้เซิร์ฟเวอร์แสดงว่าคุณจะระบุเวลาเริ่มต้นซึ่งไม่ถูกต้อง
— อรุณราม
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.