0

I am trying to log the method execution time of every JAVA method in my app. I tried many aspectj plugin such as uPhyca, aspectx but all fails due to Java 8 compatibility or gradle plugin compatibility or mostly because I am using data binding in my App. (I can't remove data binding because it is used wildly in the app). The I found Hugo. This is a plugin which can be used to log any method time in the app with @Debuggable annotation. This project under the hood also used aspectj I did not expected it to work with current gradle but it works and even I can write my own Aspect classes which can be used to intercept methods. I wrote a class which can log method time here it is

@Aspect
public class LoggingAspect {
    private static volatile boolean enabled = true;
    private static DisposableObserver<List<LogData>> subscription;
    private static final String TAG = LoggingAspect.class.getName();
    final static ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(2);

    @Pointcut("execution(* example.aspect.dunmmy(..))")
    public void onClickEntryPoint() {
    }

    @Before("onClickEntryPoint()")
    public void onClickBefore(JoinPoint joinPoint) {
        Log.d(TAG, "Before Advice ==> Clicked on : " + joinPoint.getSignature().getName());
    }

    @Around("execution(* example.application..*(..))")
    public Object onClickAround(ProceedingJoinPoint joinPoint) throws Throwable {
        if (joinPoint != null && joinPoint.getTarget() != null) {
            long startNanos = System.nanoTime();
            Object result = joinPoint.proceed();
            long stopNanos = System.nanoTime();
            long lengthMillis = TimeUnit.NANOSECONDS.toMillis(stopNanos - startNanos);
            if (lengthMillis <= 10) {
                return result;
            }
            bufferResult(joinPoint, lengthMillis);
            return result;
        }
        return joinPoint.proceed();
    }

    @After("onClickEntryPoint()")
    public void onClickAfter(JoinPoint joinPoint) {
        Log.d(TAG, "After Advice ==> Clicked on : " + joinPoint.getSignature().getName());
    }

    @AfterReturning(pointcut = "onClickEntryPoint()")
    public void onClickAfterReturning() {
        Log.d(TAG, "AfterReturning Advice ==>");
    }

    private static void bufferResult(ProceedingJoinPoint joinPoint, long lengthMillis) {
        subscription = Observable.fromCallable(() -> {
            LogData data = new LogData();
            data.setClassName(joinPoint.getTarget().getClass().getSimpleName());
            data.setMethodName(joinPoint.getSignature().getName());
            data.setTimeTaken(lengthMillis);
            return data;
        }).buffer(2, TimeUnit.SECONDS)
                .observeOn(Schedulers.from(threadPoolExecutor))
                .observeOn(Schedulers.from(threadPoolExecutor))
                .subscribeWith(new DisposableObserver<List<LogData>>() {
                    @Override
                    public void onNext(List<LogData> logData) {
                        for (LogData logDatum : logData) {
                            Log.e("time taken: ", logDatum.getClassName() + "=>" +
                                    logDatum.getMethodName() + " " + "=> " + logDatum
                                    .getTimeTaken() + "ms");
                        }
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onComplete() {
                    }
                });
    }
}

It works fine and Log every method which is under example.application but the problem arises that app got so slow that it takes 20-50 seconds to load an Activity or Fragment.

How can I tune the performance of the app. I don't know which part of the code is taking too long to run.

Sunny
  • 14,522
  • 15
  • 84
  • 129
  • I cannot say anything intelligent about why your code becomes slow without seeing the application, but if it is quick without Hugo and slow with Hugo, chances are that either Hugo itself is slow (don't know, never used it) or that you are just logging way too many methods. Have you tried building your app with Maven and use AspectJ Maven plugin or the AspectJ compiler (ajc) directly? I never had any problems with Java 8 and AspectJ Maven. Performance is not an issue if your aspect code does not do expensive things too often. Or could `bufferResult()` be slow? – kriegaex Feb 08 '18 at 15:08
  • I removed `bufferResult()` even I limit the scope of aspectj to only one Activity class, but it is still very slow. I removed the `hugo` library and used `aspectjx` the build was successful but it also has same problem. Both plugins makes the app slower. – Sunny Feb 09 '18 at 06:27
  • Logging always has a certain performance impact, AOP or not. But if it is really dramatical, I am sure that either there must be something wrong in the way you use it or your Android device has so little RAM that the AspectJ runtime, even though small, slows things down due to memory consumption. But the former is far more likely than the latter. Many Android apps use AspectJ without suffering from dramatic performance loss. Without a complete [MCVE](http://stackoverflow.com/help/mcve) on GitHub probably nobody can really help you, we can only make educated guesses (like shots in the dark). – kriegaex Feb 09 '18 at 13:55
  • Some small optimisations in your aspect can be made, though: (1) No need to check if the joinpoint is null because if it was the advice would never fire. (2) Log the full joinpoint instead of extracting the signature. (3) Simplify millis calculation by not calculating with nanos and then converting into millis, but using millis right away. Et cetera. But still I think the problem is the logging framework itself or the way you use it rather than AspectJ. This is just guesswork though, as I said. – kriegaex Feb 09 '18 at 14:01
  • @kriegaex thanks for clarification. I removed the aspectj plugin and then tried to run the app. Surprisingly the app was still very slow. After that I used aspecjx and reinstall the app but still with no success. After that I removed all aspectjx cleared all the builds and cache and uninstall the app. I then freshly install Hugo plugin and it did work!!! Thanks :) – Sunny Feb 09 '18 at 18:16
  • Like so often, the problem sat in front of the PC. No offense meant, in many situations I was in the same position during my career, i.e. being the problem and noticing later than necessary. :-) I am happy it works for you now. – kriegaex Feb 09 '18 at 18:30

0 Answers0