20

I have a Spring application that I believe has some bottlenecks, so I'd like to run it with a profiler to measure what functions take how much time. Any recommendations to how I should do that?

I'm running STS, the project is a maven project, and I'm running Spring 3.0.1

Utku
  • 2,025
  • 22
  • 42
niklassaers
  • 8,480
  • 20
  • 99
  • 146
  • Profiling a Spring application isn't really any different to profiling any other java application. You might want to widen the question, to get a wider selection of answers. – skaffman Mar 19 '10 at 08:41

8 Answers8

22

I've done this using Spring AOP.

Sometime I need an information about how much time does it take to execute some methods in my project (Controller's method in example).

In servlet xml I put

<aop:aspectj-autoproxy/>

Also, I need to create the class for aspects:

@Component
@Aspect
public class SystemArchitecture {

    @Pointcut("execution(* org.mywebapp.controller..*.*(..))")
    public void businessController() {
    }
}

And profiler aspect:

@Component
@Aspect
public class TimeExecutionProfiler {

    private static final Logger logger = LoggerFactory.getLogger(TimeExecutionProfiler.class);

    @Around("org.mywebapp.util.aspects.SystemArchitecture.businessController()")
    public Object profile(ProceedingJoinPoint pjp) throws Throwable {
        long start = System.currentTimeMillis();
        logger.info("ServicesProfiler.profile(): Going to call the method: {}", pjp.getSignature().getName());
        Object output = pjp.proceed();
        logger.info("ServicesProfiler.profile(): Method execution completed.");
        long elapsedTime = System.currentTimeMillis() - start;
        logger.info("ServicesProfiler.profile(): Method execution time: " + elapsedTime + " milliseconds.");

        return output;
    }

    @After("org.mywebapp.util.aspects.SystemArchitecture.businessController()")
    public void profileMemory() {
        logger.info("JVM memory in use = {}", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));
    }
}

That's all. When I request a page from my webapp, the information about method executing time and JVM memory usage prints out in my webapp's log file.

Yuri.Bulkin
  • 1,384
  • 10
  • 8
  • 1
    Hehe, this is actually the same work-around I've used so far. :-) Not quite a profiler, but gets you a long way :-) – niklassaers Mar 19 '10 at 08:50
  • Speaking of, for some reason this works well on my business methods, but not on my controllers. Any idea why this might be? – niklassaers Mar 19 '10 at 09:00
  • Sorry, you did not say this in your question :) If your question is about web application and if you use tomcat servlet container, you may use SpringSource tc server with spring-insight – Yuri.Bulkin Mar 19 '10 at 09:04
  • For 2nd comment: is your applicationContext.xml contains – Yuri.Bulkin Mar 19 '10 at 09:08
  • Hi, sorry I didn't say this in my question, I think your answer is important to have here. :-) I do have a component-scan in the applicationContext.xml, but the minute I add this aspect to the controllers, the controllers don't show up anymore. Perhaps I've got them in the wrong order – niklassaers Mar 19 '10 at 10:10
  • Or can it be that my business component is tagged @Service, while my controller is annotated @Controller? Because if I do the same on my entities that are annotated @Repository or @Entity, I don't get to weave them in either? – niklassaers Mar 19 '10 at 10:15
  • It does not matter what annotation do you use. You may weave in object with no spring annotation at all. Maybe you have an inaccuracy in pointcut description. – Yuri.Bulkin Mar 19 '10 at 14:52
  • The problem here is that you'll be bundling code, that is not used for production, in your project. This can have negative impact, starting with version compability and ending with security – Shmarkus Mar 25 '19 at 20:42
4

I recommend VisualVM for general application profiling. It is available in the JDK from version 1.6_10, and imho much faster and usable than Eclipse TPTP.

(If your Spring application works in an application server (e.g. Tomcat) you could try to deploy it to the tc Server developer edition (available in the STS downloads). It has interesting monitoring capabilities. It seems that tc Server developer edition is not maintained anymore.)

UPDATE 2019.02.22.: updated VisualVM url (thanks for @Jeff) and tc Server information. Personally I currently use Glowroot for monitoring Spring applications running in an application server.

Csaba_H
  • 8,215
  • 1
  • 41
  • 42
  • Thanks for the suggestion. I'm working on OS X, and for some reason TPTP doesn't seem to exist there. I'd forgotten about tcServer, so I'll be sure to give that a whirl :-) – niklassaers Mar 19 '10 at 09:01
  • @Daimon, thanks for the URL update, I have updated it in the answer as well – Csaba_H Jul 02 '15 at 08:05
3

You can use an open source java profiler such as Profiler4J:

http://profiler4j.sourceforge.net/

or Netbeans comes with a built in profiler and Eclipse also has profiling capabilities, however I found Profiler4J easier to use since it has a nice graph showing you the most time consuming methods.

This works well in STS (eclipse), just follow the instructions on the site.

Neal Donnan
  • 1,733
  • 1
  • 13
  • 18
  • Thanks for the tip. It seems that the last beta of Profiler4J was posted in 2006, is this still an active project? – niklassaers Mar 19 '10 at 08:02
  • Looks like it may not still be actively developed, but when I used it a few months ago it worked well. I guess it's not going to be deployed with your project so if it works as a once off tool you don't need to worry. There are loads of others which are commercially available, otherwise just use the one that comes with eclipse. – Neal Donnan Mar 19 '10 at 08:18
  • Hmm, I tried it out, but it turns out that neither the Call Graph nor the Call Tree are populated even though I've instrumented all my classes and the proxy classes. Memory and Threads works well, though – niklassaers Mar 19 '10 at 13:07
  • Did you push the little snapshot button? That should populate the graph. In a web app you can clear the registers using the button on the toolbar, perform the action you want to profile and then click the snapshot button to populate the graph for that action. – Neal Donnan Mar 19 '10 at 13:54
2

Here's a general discussion with recommended tools & techniques.

Basically, it is entirely natural to assume if you want to find out how to make an app faster, that you should start by measuring how long functions take. That's a top-down approach.

There's a bottom-up approach that when you think about it is just as natural. That is not to ask about time, but to ask what it is doing, predominantly, and why it is doing it.

Community
  • 1
  • 1
Mike Dunlavey
  • 40,059
  • 14
  • 91
  • 135
2

We developed a JMX & Spring AOP based @Profiled annotation which does production monitoring (active invocations, invocations count, time spent during invocations, exceptions count, etc) . Metrics are exposed via JMX and can be collected via Visual VM / JConsole and by monitoring systems ; we developed an Hyperic HQ Plugin.

This @profiled annotation is packaged with many other JMX extras to ease monitoring of common components (dbcp, util.concurrent, cxf, jms, etc) and proposed under a business friendly Apache Software License at http://code.google.com/p/xebia-france/wiki/XebiaManagementExtras .

Hope this helps,

Cyrille (Xebia)

Cyrille Le Clerc
  • 111
  • 1
  • 4
  • 12
1

I liked JRat, although like profiler4j it doesn't seem to be actively developed. In any case, it was simple to use.

laura
  • 7,280
  • 4
  • 35
  • 43
  • It looks really simple to use, but when I tried it out, I got Nullpointer errors from the aspect weaving. No idea why, when I disabled JRat they went away. Although I wouldn't be surprised if they are my errors, but I don't know what triggered them or where they came from. :-I – niklassaers Mar 19 '10 at 12:47
1

A bit modified version of Yuri's answer on top (the selected answer) that auto calculates the totals of durations and arranges them desc. The totals gets printed in the end only. Might save you 10 mns.

    @Component
    @Aspect
    public class SystemArchitecture
    {

         @Pointcut("execution(* erp..*.*(..))")
         public void businessController()
         {
         }

         @Pointcut("execution(* TestMain..*.*(..))")
         public void theEnd()
         {
         }
    }



    @Component
    @Aspect
    public class TimeExecutionProfiler
    {

        static Hashtable<String, Long>  ht  = new Hashtable<String, Long>();

        @Around("profiler.SystemArchitecture.businessController()")
        public Object profile(ProceedingJoinPoint pjp) throws Throwable
        {
            long start = System.nanoTime();
            Object output = pjp.proceed();
            long elapsedTime = System.nanoTime() - start;
            String methodName = pjp.getSignature().toString();
            if (ht.get(methodName) == null)
            {
                ht.put(methodName, elapsedTime);
            }
            else
            {
                ht.put(methodName, ht.get(methodName) + elapsedTime);
            }
            // System.out.println(methodName + " : " + elapsedTime + " milliseconds.");

            return output;
        }

        @After("profiler.SystemArchitecture.theEnd()")
        public void profileMemory()
        {
            List<Object> keys = Arrays.asList(ht.keySet().toArray());
            java.util.Collections.sort(keys, new Comparator<Object>()
            {

                @Override
                public int compare(Object arg0, Object arg1)
                {
                    return ht.get(arg1).compareTo(ht.get(arg0));
                }
            });

            System.out.println("totals Used:");
            for (Object name : keys)
            {
                System.out.println("--" + name + " : " + (ht.get(name) / 1000000));
            }
            System.out.println("JVM memory in use = " + (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()));
        }
    }
AhHatem
  • 1,415
  • 3
  • 14
  • 23
0

You could always use Java Mission Controls Flight Recorder that is bundled with Java, to profile your code execution

Shmarkus
  • 178
  • 1
  • 11