Time-consuming statistics tool - StopWatch stopwatch

[ Preface ] In the process of program performance analysis, the most intuitive way is to measure the performance of the code by counting the actual time consumption of the program, so as to understand the overall performance of the program, so as to quickly locate the time-consuming position for analysis and optimization.

In the past, the running time of the program we counted was often used in the following way:

public class StaticTimeTest {
    
    

    public static void main(String[] args) throws InterruptedException {
    
    
        long startTime = System.currentTimeMillis();
        Thread.sleep(1000);
        long endTime = System.currentTimeMillis();
        System.out.println("执行耗时(ms):"+ (endTime - startTime));
    }
}

// 输出:执行耗时(ms):1012

If you want to obtain the time consumption of each stage and give the execution time statistics of each code block in a more friendly way, you often need to encapsulate more code to complete it. StopWatch provides us with a more elegant way to count the time-consuming of each part of the program, allowing us to focus more purely on the business logic itself, which can be called a powerful tool for time-consuming statistics.

StopWatch core method

We can find this tool class under the org.springframework.util package. The description information marked by the author in the source code is as follows:

Simple stop watch, allowing for timing of a number of tasks, exposing total running time and running time for each named task.
Conceals use of System.nanoTime(), improving the readability of application code and reducing the likelihood of calculation errors.
Note that this object is not designed to be thread-safe and does not use synchronization.
This class is normally used to verify performance during proof-of-concept work and in development, rather than as part of production applications.
As of Spring Framework 5.2, running time is tracked and reported in nanoseconds.

Since: May 2, 2001
Author: Rod Johnson, Juergen Hoeller, Sam Brannen

From the author's description, we can see that the StopWatch tool allows multiple tasks to be timed, and displays the total time spent on the program and the running time of each specified task.

It hides the use of System.nanoTime(), and is encapsulated by this tool to improve the readability of the application code and reduce the possibility of calculation errors.

Note that this object is not designed to be thread-safe and does not use synchronization. Typically used for proof-of-concept work and to test a program's performance during development, rather than as part of a production application. Starting with Spring Framework 5.2, runtimes are tracked and reported in nanoseconds.

Hutool is based on the tool class of Spring Framework, and further encapsulates the stopwatch tool. The common methods are as follows:

  • create(String id) : Create a timing task with a specified id
  • getId() : Get the ID of StopWatch, which is used to distinguish between multiple stopwatch objects
  • setKeepTaskList(boolean keepTaskList) : Set whether to keep tasks after stopping
  • start() : Start the default new task timing
  • start(String taskName) : start timing of a new task with the specified name
  • stop() : End the timing of the current task
  • getTotalTimeNanos() : Get the execution time of all tasks (nanoseconds)
  • getTotalTimeMillis() : Get the execution time of all tasks (in milliseconds)
  • getTotalTimeSeconds() : Get the execution time of all tasks (in seconds)
  • shortSummary() : get simple statistics
  • prettyPrint() : output the total statistical time and the execution time of tasks in each stage in a friendly way

StopWatch in action

The Spring framework tool class StopWatch can be used to time the code blocks or methods in the program, and supports multi-stage timing, and statistics such as the proportion of time in stages. The code is relatively simple and lightweight to use. Examples are as follows:

public class StaticTimeTest {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        StopWatch stopWatch = new StopWatch("测试 task");
        stopWatch.start("任务阶段1");
        Thread.sleep(1000);
        stopWatch.stop();
        stopWatch.start("任务阶段2");
        Thread.sleep(2000);
        stopWatch.stop();
        stopWatch.start("任务阶段3");
        System.out.println("任务执行...");
        stopWatch.stop();
        System.out.println(stopWatch.prettyPrint());  
    }
}
		// 运行结果如下:
		任务执行...
		StopWatch '测试 task': running time = 3019289500 ns
		---------------------------------------------
		ns         %     Task name
		---------------------------------------------
		1008034300  033%  任务阶段1
		2010897200  067%  任务阶段2
		000358000  000%  任务阶段3

Source code analysis

The source code implementation of StopWatch is very simple. You can see the source code of springframework as follows:

	/**
	 * Start a named task.
	 * <p>The results are undefined if {@link #stop()} or timing methods are
	 * called without invoking this method first.
	 * @param taskName the name of the task to start
	 * @see #start()
	 * @see #stop()
	 */
	public void start(String taskName) throws IllegalStateException {
    
    
		if (this.currentTaskName != null) {
    
    
			throw new IllegalStateException("Can't start StopWatch: it's already running");
		}
		this.currentTaskName = taskName;
		this.startTimeNanos = System.nanoTime();
	}

	/**
	 * Stop the current task.
	 * <p>The results are undefined if timing methods are called without invoking
	 * at least one pair of {@code start()} / {@code stop()} methods.
	 * @see #start()
	 * @see #start(String)
	 */
	public void stop() throws IllegalStateException {
    
    
		if (this.currentTaskName == null) {
    
    
			throw new IllegalStateException("Can't stop StopWatch: it's not running");
		}
		long lastTime = System.nanoTime() - this.startTimeNanos;
		this.totalTimeNanos += lastTime;
		this.lastTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
		if (this.keepTaskList) {
    
    
			this.taskList.add(this.lastTaskInfo);
		}
		++this.taskCount;
		this.currentTaskName = null;
	}

Seeing this, you may suddenly realize that StopWatch mainly operates around System.nanoTime with a layer of time subtraction.
But the wonderful thing is that this layer of coat is beautiful enough and elegant enough. Through the internal static class TaskInfo, you can record the time-consuming information of each subtask name, and print the results according to the format, which is more friendly especially for multi-task statistics.

PS. The difference between System.nanoTime and System.currentTimeMillis
System.nanoTime provides relatively accurate timing, but it cannot be used to calculate the current date. Returns the current value of the most accurate available system timer, in nanoseconds. This method can only be used to measure elapsed time and has nothing to do with any other notion of time, system or clock time.
System.currentTimeMillis returns the time from 1970.1.1 UTC zero to the present, accurate to milliseconds. Usually, we can calculate the current date, day of the week, etc. according to System.currentTimeMillis, which can be easily converted with Date.

Summarize

The package of StopWatch is very beautiful, and you can use the stopwatch daily for time-consuming statistics, performance evaluation, and troubleshooting.
Read more source code and learn from experts. Fighting…

Guess you like

Origin blog.csdn.net/zhzh980/article/details/129372239