Класс секундомера для Java

Какой класс Java следует использовать для измерения производительности времени?

(Можно использовать любой класс даты/времени, но причина, по которой я спрашиваю, заключается в том, что в .Net есть назначенный Секундомер для этой цели)


person ripper234    schedule 06.08.2009    source источник
comment
Дубликат stackoverflow.com/questions/1237181/   -  person Mark    schedule 06.08.2009
comment
@Mark - на самом деле не дурак. Ответы на этот вопрос совсем другие.   -  person ripper234    schedule 10.03.2011


Ответы (10)



Это пример того, как использовать StopWatch для установки нескольких измерений путем аннотирования специальных методов. Очень полезно и очень просто использовать для измерения, например. Сервисный вызов через несколько встроенных вызовов/операций и так далее.

СекундомерИерархия

package ch.vii.spring.aop;

import java.util.Arrays;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Component
public class ProfilingMethodInterceptor implements MethodInterceptor {

    private static final Logger log = LoggerFactory.getLogger(ProfilingMethodInterceptor.class);

    public Object invoke(MethodInvocation invocation) throws Throwable {

        if (log.isInfoEnabled()) {
            String stopWatchName = invocation.getMethod().toGenericString();
            StopWatchHierarchy stopWatch = StopWatchHierarchy.getStopWatchHierarchy(stopWatchName);

            String taskName = invocation.getMethod().getName();
            stopWatch.start(taskName);

            try {
                return invocation.proceed();
            } finally {
                stopWatch.stop();
            }
        } else {
            return invocation.proceed();
        }
    }

    static class StopWatchHierarchy {
        private static final ThreadLocal<StopWatchHierarchy> stopwatchLocal = new ThreadLocal<StopWatchHierarchy>();
        private static final IndentStack indentStack = new IndentStack();

        static StopWatchHierarchy getStopWatchHierarchy(String id) {

            StopWatchHierarchy stopWatch = stopwatchLocal.get();
            if (stopWatch == null) {
                stopWatch = new StopWatchHierarchy(id);
                stopwatchLocal.set(stopWatch);
            }
            return stopWatch;
        }

        static void reset() {
            stopwatchLocal.set(null);
        }

        final StopWatch stopWatch;
        final Stack stack;

        StopWatchHierarchy(String id) {
            stopWatch = new StopWatch(id);
            stack = new Stack();
        }

        void start(String taskName) {
            if (stopWatch.isRunning()) {
                stopWatch.stop();
            }
            taskName = indentStack.get(stack.size) + taskName;
            stack.push(taskName);
            stopWatch.start(taskName);
        }

        void stop() {
            stopWatch.stop();
            stack.pop();
            if (stack.isEmpty()) {
                log.info(stopWatch.prettyPrint());
                StopWatchHierarchy.reset();
            } else {
                stopWatch.start(stack.get());
            }
        }

    }

    static class Stack {
        private int size = 0;
        String elements[];

        public Stack() {
            elements = new String[10];
        }

        public void push(String e) {
            if (size == elements.length) {
                ensureCapa();
            }
            elements[size++] = e;
        }

        public String pop() {
            String e = elements[--size];
            elements[size] = null;
            return e;
        }

        public String get() {
            return elements[size - 1];
        }

        public boolean isEmpty() {
            return size == 0;
        }

        private void ensureCapa() {
            int newSize = elements.length * 2;
            elements = Arrays.copyOf(elements, newSize);
        }
    }

    static class IndentStack {
        String elements[] = new String[0];

        public String get(int index) {
            if (index >= elements.length) {
                ensureCapa(index + 10);
            }
            return elements[index];
        }

        private void ensureCapa(int newSize) {
            int oldSize = elements.length;
            elements = Arrays.copyOf(elements, newSize);
            for (int i = oldSize; i < elements.length; i++) {
                elements[i] = new String(new char[i]).replace("\0", "|   ");
            }
        }
    }
}

Советник

package ch.vii.spring.aop;

import java.lang.reflect.Method;

import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class ProfilingAdvisor extends AbstractPointcutAdvisor {

    private static final long serialVersionUID = 1L;

    private final StaticMethodMatcherPointcut pointcut = new StaticMethodMatcherPointcut() {
        public boolean matches(Method method, Class<?> targetClass) {
            return method.isAnnotationPresent(ProfileExecution.class);
        }
    };

    @Autowired
    private ProfilingMethodInterceptor interceptor;

    public Pointcut getPointcut() {
        return this.pointcut;
    }

    public Advice getAdvice() {
        return this.interceptor;
    }
}

Аннотация ProfileExecution

package ch.vii.spring.aop;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Inherited
public @interface ProfileExecution {

}

Аннотируйте свой код

package ch.vii.spring;                                                                                                                                                                 
import org.springframework.beans.factory.annotation.Autowired;                                      
import org.springframework.stereotype.Component;                                                    

import ch.vii.spring.aop.ProfileExecution;                                                          

@Component                                                                                          
public class Bean {                                                                                 
    @Autowired                                                                                      
    InnerBean innerBean;  

    @ProfileExecution                                                                               
    public void foo() {                                                                             
        innerBean.innerFoo();                                                                      
        innerBean.innerFoo2();                                                                      
        innerBean.innerFoo();                                                                       
    }                                                                                                                                                                                         
}  

public class InnerBean {
    @Autowired
    InnerInnerBean innerInnerBean;

    @ProfileExecution
    public void innerFoo() {
    }

    @ProfileExecution
    public void innerFoo2() {
        innerInnerBean.innerInnerFoo();
        innerInnerBean.innerInnerFoo();
        innerInnerBean.innerInnerFoo();
    }
}                                                                                                    

Выход

09:58:39.627 [main] INFO  c.v.s.aop.ProfilingMethodInterceptor - StopWatch 'public void ch.vii.spring.Bean.foo()': running time (millis) = 215
-----------------------------------------
ms     %     Task name
-----------------------------------------
00018  008 %  foo
00026  012 %  |   innerFoo
00001  000 %  foo
00016  007 %  |   innerFoo2
00038  018 %  |   |   innerInnerFoo
00000  000 %  |   innerFoo2
00024  011 %  |   |   innerInnerFoo
00028  013 %  |   innerFoo2
00024  011 %  |   |   innerInnerFoo
00029  013 %  |   innerFoo2
00000  000 %  foo
00011  005 %  |   innerFoo
00000  000 %  foo
person e double you    schedule 20.02.2016
comment
Чувак, этот ответ потрясающий, и у тебя 31 балл... это весело. Спасибо за код, с которого я начал, очень чистый. - person Stephen Patten; 20.05.2020

person Kevin Crowell    schedule 06.08.2009
comment
nanoTime имеет гораздо более высокое разрешение (по крайней мере, в Windows): 1-2 микросекунды против 16 миллисекундсекунд для currentTimeMillis - person Daniel Fortunov; 21.12.2009
comment
Google guava, похоже, использует наносекунды: Секундомер - person Luke Quinane; 06.09.2012
comment
В новой версии Apache Commons используется метод nanoTime() вместо метода currentTimeMillis(). - person Vinay Lodha; 02.01.2013

Проверьте perf4j. Весенний секундомер предназначен в основном для местного развития. Perf4j может поддерживать синхронизацию как вашего типа POC, так и в производственной среде.

person user2262148    schedule 09.04.2013

Вы можете попробовать System.currentTimeMillis(), но также есть хорошие параметры профилирования в некоторых известных IDE, таких как eclipse и netbeans. Кроме того, вне среды IDE вы можете попробовать автономные профилировщики в задачах измерения производительности. Я думаю, что с помощью профилировщиков вы получите лучшие результаты, чем с помощью System.currentTimeMillis().

person daniel    schedule 06.08.2009
comment
Я хотел бы написать простой интеграционный тест, который удостоверится, что что-то «достаточно производительно». - person ripper234; 06.08.2009

Если вы просто хотите измерить это, используйте класс секундомера или, может быть, просто секундомер.

Если вы хотите сделать это быстрее, рассмотрите это.

person Mike Dunlavey    schedule 17.11.2009

Лучше всего использовать System.nanoTime(), однако, если вы хотите получить тики (истекшие тики), такие как System.Diagnostics.Stopwatch, вам нужно преобразовать наносекунды в тики (1 тик = 100 наносекунд), а затем начать преобразование между нано и миллисекунды, секунды, минуты, часы, а затем, наконец, отформатируйте вывод в представление времени, такое как метод Elapsed() (чч: мм: сс.сссссссс), однако похоже, что даты в Java используют только 3 миллисекунды (чч:мм:сс.сссс), так что вам также нужно отработать формат.

Я сделал один класс секундомера для Java, который вы можете получить по адресу: http://carlosqt.blogspot.com/2011/05/stopwatch-class-for-java.html

Пример:

package stopwatchapp;
import java.math.BigInteger;
public class StopwatchApp {
    public static void main(String[] args) {

        Stopwatch timer = new Stopwatch();
        timer.start();
        Fibonacci(40);
        timer.stop();

        System.out.println("Elapsed time in ticks: " 
            + timer.getElapsedTicks());
        System.out.println("Elapsed time in milliseconds: " 
            + timer.getElapsedMilliseconds());
        System.out.println("Elapsed time in seconds: " 
            + timer.getElapsedSeconds());
        System.out.println("Elapsed time in minutes: " 
            + timer.getElapsedMinutes());
        System.out.println("Elapsed time in hours: " 
            + timer.getElapsedHours());
        System.out.println("Elapsed time with format: " 
            + timer.getElapsed());
    }

    private static BigInteger Fibonacci(int n)
    {
        if (n < 2)
            return BigInteger.ONE;
        else
            return Fibonacci(n - 1).add(Fibonacci(n - 2));
    }
}

Выход:

// Elapsed time in ticks: 33432284
// Elapsed time in milliseconds: 3343
// Elapsed time in seconds: 3
// Elapsed time in minutes: 0
// Elapsed time in hours: 0
// Elapsed time with format: 00:00:03.3432284

Надеюсь это поможет.

person Carlos Quintanilla    schedule 12.05.2011

Если вы используете JDK 9+, вы можете использовать Flight Recorder. Он имеет чрезвычайно низкие накладные расходы и использует инвариантный TSC для синхронизации, что менее навязчиво, чем System.nanoTime().

@StackTrace(false)
static class StopWatch extends Event {
  int fib;
}

public static void main(String... args) throws IOException {
    Recording r = new Recording();
    r.start();
    for (int i = 0; i < 500000; i++) {
        StopWatch s = new StopWatch();
        s.begin();
        s.fib = fib(i%100);
        s.commit();
    }
    r.stop();
    Path p = Paths.get("recording.jfr");
    r.dump(p);
    for (RecordedEvent e : RecordingFile.readAllEvents(p)) {
        System.out.println(e.getValue("fib") + " " + e.getDuration().toNanos() + " ns");
    }
}

Вы также можете запустить запись из командной строки (-XX:StartFlightRecording), а затем включить событие в файле конфигурации (.jfc) (если вы отключите его по умолчанию, @Enable(false))

Таким образом, JIT обычно оптимизирует вызовы StopWatch (анализ экранирования, встраивание, устранение мертвого кода и т. д.), поэтому вы платите штраф только тогда, когда хотите что-то измерить.

person Kire Haglin    schedule 14.11.2018

Performetrics предоставляет удобный класс секундомера. Он может измерять время настенных часов и многое другое: он также измеряет время процессора, время пользователя и системное время, если вам нужна большая точность. Он небольшой, бесплатный и его можно скачать с Maven Central. Дополнительную информацию и примеры можно найти здесь: https://obvj.net/performetrics

Stopwatch sw = new Stopwatch();
sw.start();

// Your code here

sw.stop();
sw.printStatistics(System.out);

Это приводит к выводу, подобному следующему:

+-----------------+----------------------+--------------+
| Counter         |         Elapsed time | Time unit    |
+-----------------+----------------------+--------------+
| Wall clock time |             85605718 | nanoseconds  |
| CPU time        |             78000500 | nanoseconds  |
| User time       |             62400400 | nanoseconds  |
| System time     |             15600100 | nanoseconds  |
+-----------------+----------------------+--------------+

Вы можете преобразовать метрики в любую единицу времени (наносекунды, миллисекунды, секунды и т. д.), просто передав настраиваемый параметр.

PS: я автор инструмента.

person Oswaldo Junior    schedule 21.01.2020

person    schedule
comment
Это заставит поток ЦП быть занятым в ожидании истечения указанного времени. Не лучший способ заснуть по программе. - person Eric J.; 17.01.2013
comment
Это действительно плохая идея. Thread.sleep сделает это, не занимая всего процессорного времени. В любом случае первоначальный вопрос касался измерения времени производительности, а не ожидания. - person AgilePro; 23.01.2013