如何分析java,eclipse,junit中哪个方法消耗的时间更多? [复制]

Posted

技术标签:

【中文标题】如何分析java,eclipse,junit中哪个方法消耗的时间更多? [复制]【英文标题】:How do I analyze which method consumed more time in java,eclipse,junit? [duplicate] 【发布时间】:2013-01-28 09:11:54 【问题描述】:

对于一些专业的 Java 程序员来说,这可能是一个愚蠢的问题,但我现在要疯了,所以我还在问。请有人指导我正确的方向。

如何分析在我的 java 程序中哪个方法/partOfMethod 消耗更多时间?

(我正在使用 Eclipse 和 Junit)

【问题讨论】:

我自己没有做过,但是这样的事情叫做 profiling,可能有助于你的谷歌搜索 ;) profiling tutorial 不再需要对此进行投票/评论/回答,我已经找到了解决方案。谢谢大家。 【参考方案1】:

使用 jvisualvm。它现在与 JDK 捆绑在一起,但也有一个独立版本,它是最新的。 通常,当您启动它时,您可以选择要连接到哪个正在运行的 java 进程(这很可能是我们正在运行的单元测试)。您可以指定需要跟踪的合格类名过滤器。通常,一些类检测会随之而来,您将能够跟踪分配给每个方法的处理时间(以及累积时间)。

【讨论】:

非常感谢您的及时回复,jvisualvm 似乎是答案,但仍在探索中......【参考方案2】:

您需要获得Java profiler。 Some of them integrate well in Eclipse.

除此之外,您还可以使用自定义分析器类(如果您没有太多的分析工作要做并且您已经怀疑存在一些瓶颈)。

这是一个简单的类:

/**
 * Small helper class to profile the code, take timing, ...
 * 
 * To use this, simply call the start method with an identifier. When you want to measure the time, call the stop method
 * with the same identifier. To output statistics, simply call the toString method or the toCsv method to create a CSV
 * file with the profiler information.
 * 
 * @author Vincent Prat @ MarvinLabs
 */
public class Profiler 

    private static final int THEORETICAL_MAX_NAME_LENGTH = 50;

    private static Profiler singletonInstance = null;

    private Map<String, Profile> profiles; // Fast access to profiles by name
    private List<Profile> profilesStack; // Profiles as created chronologically

    /**
     * Get access to the singleton instance (create it if necessary)
     */
    public static Profiler getInstance() 
        if (singletonInstance == null) 
            singletonInstance = new Profiler();
        
        return singletonInstance;
    

    /**
     * Protected constructor for singleton
     */
    protected Profiler() 
        profiles = new HashMap<String, Profiler.Profile>();
        profilesStack = new ArrayList<Profile>();
    

    /**
     * Start a profile. If the profile does not exist, it will be created. If it exists, a new round of measure is
     * taken.
     * 
     * @param name
     *            The name of the profile. If possible, less than Profiler.THEORETICAL_MAX_NAME_LENGTH characters
     * 
     * @see Profiler.THEORETICAL_MAX_NAME_LENGTH
     */
    public void start(String name) 
        Profile p = profiles.get(name);
        if (p == null) 
            p = new Profile(name);
            profiles.put(name, p);
            profilesStack.add(p);
        
        p.start();
    

    /**
     * Stop a profile and compute some statistics about it.
     * 
     * @param name
     *            The name of the profile as declared in the corresponding start method
     */
    public void stop(String name) 
        Profile p = profiles.get(name);
        if (p == null) 
            throw new RuntimeException("The profile " + name + " has not been created by a call to the start() method!");
        
        p.stop();
    

    /**
     * Clear all the current measures. Not to be called within any start/stop pair.
     */
    public void reset() 
        profiles.clear();
    

    /**
     * Build a string containing all the information about the measures we have taken so far.
     */
    @Override
    public String toString() 
        final StringBuffer sb = new StringBuffer();
        for (Profile p : profilesStack) 
            sb.append(p.toString());
            sb.append("\n");
        
        return sb.toString();
    

    /**
     * Output the measures to an output string
     */
    public void toCsvFile(OutputStream os) throws IOException 
        Profile.writeCsvHeader(os);
        for (Profile p : profilesStack) 
            p.writeCsvLine(os);
        
    

    /**
     * Profile information. It stores statistics per named profile.
     * 
     * @author Vincent Prat @ MarvinLabs
     */
    private static class Profile 
        private static final String CSV_HEADERS = "Name, Call Count, Total Time (ms), Average Time (ms), Min Time (ms), Max Time (ms), Delta Time (ms), Delta Ratio (%)\n";

        private static final String FORMAT_STRING = "%-" + THEORETICAL_MAX_NAME_LENGTH + "."
                + THEORETICAL_MAX_NAME_LENGTH
                + "s: %3d calls, total %5d ms, avg %5d ms, min %5d ms, max %5d ms, delta %5d ms (%d%%)";

        private static final String CSV_FORMAT_STRING = "%s,%d,%d,%d,%d,%d,%d,%d\n";

        private String name;
        private long startTime;
        private long callCount;
        private long totalTime;
        private long minTime;
        private long maxTime;

        public Profile(String name) 
            this.name = name;
            this.callCount = 0;
            this.totalTime = 0;
            this.startTime = 0;
            this.minTime = Long.MAX_VALUE;
            this.maxTime = Long.MIN_VALUE;
        

        public void start() 
            startTime = System.currentTimeMillis();
        

        public void stop() 
            final long elapsed = (System.currentTimeMillis() - startTime);
            if (elapsed < minTime) minTime = elapsed;
            if (elapsed > maxTime) maxTime = elapsed;
            totalTime += elapsed;
            callCount++;
        

        private String getFormattedStats(String format) 
            final long avgTime = callCount == 0 ? 0 : (long) totalTime / callCount;
            final long delta = maxTime - minTime;
            final double deltaRatio = avgTime == 0 ? 0 : 100.0 * ((double) 0.5 * delta / (double) avgTime);

            return String
                    .format(format, name, callCount, totalTime, avgTime, minTime, maxTime, delta, (int) deltaRatio);
        

        @Override
        public String toString() 
            return getFormattedStats(FORMAT_STRING);
        

        public static void writeCsvHeader(OutputStream os) throws IOException 
            os.write(CSV_HEADERS.getBytes());
        

        public void writeCsvLine(OutputStream os) throws IOException 
            os.write(getFormattedStats(CSV_FORMAT_STRING).getBytes());
        
    

及示例用法:

Profiler.getInstance().start("marker1");
// Do something...

Profiler.getInstance().start("marker2");

// Something else...

Profiler.getInstance().stop("marker2");

// And some more...

Profiler.getInstance().stop("marker1");

// Output the profiling result
System.out.println(Profiler.getInstance().toString());

【讨论】:

这个类也有一个严重的缺陷,它依赖于使用系统时钟来测量时间顺序,而不是测量进程消耗的实际CPU时间。当方法执行时有后台进程占用CPU时间时,会影响结果。 这个类确实有利有弊,它是为了简单易用。只要您了解它们并且要进行的分析非常简单,它应该可以让您大致了解您在哪里花费时间。就我而言,我在开发时将它用于 android 应用程序的一些基本分析。【参考方案3】:

你可以看看Yourkit(商业软件),它可以监控内存、CPU 等等。它有特殊的视图显示方法花费了多少时间(例如你可以看到 40% 的执行时间花费在方法 xyz() 上)。

【讨论】:

不知道为什么不赞成,yourkit 是目前最好的工具之一,但大多数分析问题都可以用 jvisualvm 处理【参考方案4】:

称我为老式,但这是我认为最简单的方法:

long a, b, c, d;
a = System.currentTimeMillis();
// some code 1
b = System.currentTimeMillis();
// some code 2
c = System.currentTimeMillis();
// some code 3
d = System.currentTimeMillis();

System.out.println("Some code 1 took "+(b-a)+"mil to execute. ("+((b-a)/1000)+" seconds)");
System.out.println("Some code 2 took "+(c-b)+"mil to execute. ("+((c-b)/1000)+" seconds)");
System.out.println("Some code 3 took "+(d-c)+"mil to execute. ("+((d-c)/1000)+" seconds)");

希望这会有所帮助:)

【讨论】:

是的,这很简单,但是当执行是多线程的并且我正在寻找的差异在几毫秒内时,那么在这个过程中,我查看了所有控制台输出。 Jvisualvm 似乎是一个正确的解决方案,有助于快速直观地找到问题!【参考方案5】:

测量程序的哪个部分需要多少运行时间的过程称为“分析”。

eclipse 有很多分析插件。一个is described here。

【讨论】:

这和我提到的一样,取决于是否需要测量或进行分析。【参考方案6】:

有一些在线工具,例如IdeOne,可以让您节省执行代码块的时间。试试看!

【讨论】:

以上是关于如何分析java,eclipse,junit中哪个方法消耗的时间更多? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

JUnit 5 Eclipse Java测试

当依赖于 EBean 增强模型时,如何在 Eclipse 中运行 JUNIT?

第八章:Junit——selnium IDE 录制完成以后 导入 Eclipse 中 分析

使用 plexus-compiler-eclipse 编译 java 类并将其作为 JUnit 测试运行

关于eclipse中java项目管理中如何查找哪个类文件包含main

关于 eclipse run configurations 设置问题