简体   繁体   English

测量由 bukkit.event.Listener 处理的方法的运行时间

[英]Measure runtime of a method handled by bukkit.event.Listener

I need to accurately measure in ms ( #.### ms ), exactly how long a void method takes to run, without the measurement impacting the results.我需要以毫秒( #.### ms )为单位准确测量 void 方法运行所需的时间,而测量不会影响结果。

Normally I would simply do something like:通常我会简单地做类似的事情:

long startTime = System.nanoTime();
methodToTime();
long endTime = System.nanoTime();

long duration = (endTime - startTime);  //divide by 1000000 to get milliseconds.

This won't work because my code never calls the method directly;这不起作用,因为我的代码从不直接调用该方法; it only defines it.它只定义它。

import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;

public class BlockListener implements Listener {

    @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
    public void onPlace(BlockPlaceEvent event) {

    //...
    }
}

In the context of certain methods in this Minecraft Bukkit server I'm working on, 1ms is significant, meaning I need high precision to measure and then optimize time-sensitive methods.在我正在处理的这个 Minecraft Bukkit 服务器中的某些方法的上下文中,1ms 很重要,这意味着我需要高精度来测量然后优化对时间敏感的方法。

So, surely adding any code inside the method could affect the runtime of the method?那么,在方法中添加任何代码肯定会影响方法的运行时间吗?

What is the best way to measure this?衡量这一点的最佳方法是什么? Please and thank you谢谢,麻烦您了

Running Paper/Spigot with ProtocolLib (1.16.5)使用 ProtocolLib (1.16.5) 运行 Paper/Spigot

Performance measurement will always affect your performance, that's why it's I would suggest making this feature togglable.性能测量将始终影响您的性能,这就是为什么我建议将此功能设为可切换的原因。 Based on this answer , calling System.nanoTime() two times per method will take approximately 200 CPU clock cycles, which is not a big overhead.根据这个答案,每个方法调用System.nanoTime()两次大约需要 200 个 CPU 时钟周期,这不是很大的开销。

But after measuring the execution time, you need to save it somewhere or print a log.但是在测量执行时间之后,您需要将其保存在某处或打印日志。 Usually, I/O operations are the most expensive, thus it's better to avoid blocking outputs in your method.通常,I/O 操作是最昂贵的,因此最好避免在您的方法中阻塞输出。 For this purpose, you can utilize java.util.concurrent.BlockingQueue or other implementations of thread-safe pipes (like Disruptor or JCTools ) and log captured results in separate daemon thread.为此,您可以利用java.util.concurrent.BlockingQueue或线程安全管道的其他实现(如DisruptorJCTools )并将捕获的结果记录在单独的守护线程中。

Implementation proposal实施方案

public class ListenerPerformanceAuditor implements Listener {

    private final BlockingQueue<Long> executionTimeQueue;
    private final Listener auditedListener;

    public ListenerPerformanceAuditor(
            Listener auditedListener,
            BlockingQueue<Long> executionTimeQueue
    ) {
        this.auditedListener = auditedListener;
        this.executionTimeQueue = executionTimeQueue;
    }

    public void onPlace(BlockPlaceEvent event) {
        long startTime = System.nanoTime();
        auditedListener.onPlace(event);
        long endTime = System.nanoTime();

        long duration = (endTime - startTime);  //divide by 1000000 to get milliseconds.
        if(!executionTimeQueue.offer(duration)) {
            // if measuring each and every request isn't necessary,
            // this block can be eliminated, otherwise add error handling logic
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM