0. Sequence

The author has been developing Android for nearly 7 years, and has experienced the APP development of many first-line companies, such as petrochina, Ali, jingdong, etc., so he wants to share the excellent experience of some first-line apps. He plans to update a series of APP Performance Optimization in his rest time, which is about 20 chapters. But I didn’t pass the review, so I plan to share it for free. I will update 2 chapters every week. If you like it, please remember to add your attention and thumbs up. Please point out any clerical errors.

The topics covered include asynchronous optimization, startup optimization, lag optimization, memory optimization, ARTHook, monitoring time blind area, network, power, slimming and APP disaster recovery

1. Introduction

This article, the first in this series, mainly introduces how to locate the problem if the APP suffers from lag in the actual projects of some first-line big factories. It mainly introduces the time consuming process


2. Measure time mode

First, there are three ways to look at how long a page takes to load

  1. Adb command
  2. Manual ordering
  3. traceView


3. The adb command

With a single command, you can see when the page loads.

Adb shell am start -w Adb shell name ActivityCopy the code

It will be displayed after use

ThisTime: how long it took to start the last Activity TotalTime: how long it took to start all activities WaitTime: how long it took AMS to start all activities

Note: The default exported attribute is false without an intent-filter. The exported component is only accessible by the user of the application. This value changes to true with intent-filter, allowing external calls.

Disadvantages: THE ADB command can only view the configured activities, but other activities cannot be viewed, and the specific time consumed by the method cannot be accurately viewed. Therefore, due to its limitations, we can not solve our problem well, so we use the manual way to view.


4. Manually dial the number

Look at the code

public class MyApplication extends Application {

    @Override
    public void onCreate(a) {
        super.onCreate(); initBugly(); initBaiduMap(); initJPushInterface(); initShareSDK(); . }private void initBugly(a) throws InterruptedException {

        Thread.sleep(1000); // Time spent in simulation
    }

    private void initBaiduMap(a)  throws InterruptedException {

        Thread.sleep(2000); // Time spent in simulation
    }

    private void initJPushInterface(a) throws InterruptedException {

        Thread.sleep(3000); // Time spent in simulation
    }

    private void initShareSDK(a) throws InterruptedException {

        Thread.sleep(500); // Time spent in simulation}}Copy the code

I don’t need to tell you about the code, which is common in the project. The problem is that the APP starts and loads slowly, so how to accurately query the specific time-consuming method?

  long startTime = System.currentTimeMillis();
  initBugly();
  Log.d("lybj"."InitBugly () method time:"+ (System.currentTimeMillis() - startTime));
  
  long startTime = System.currentTimeMillis();
  initBaiduMap();
  Log.d("lybj".InitBaiduMap () method time:+ (System.currentTimeMillis() - startTime)); .Copy the code

Is that ok? Of course not, the coupling is too big, each method is added, then the test finished, delete code is also a physical work, accidentally delete a wrong, it will cause a disastrous problem, in the actual project, such as some of the oil projects, will use AOP to measure the method of spending time.

4.1 AOP

AOP: Aspect Oriented Programming abbreviation, meaning: Aspect Oriented Programming

Advantages:

  1. A unified approach to the same problem
  2. Non-intrusive add code

Here we are using Aspectj

4.2 Use of Aspectj

1. Add dependencies

Build. Gradle in the root directory

buildscript {
    ...
    dependencies {
        ...
        classpath 'com. Hujiang. Aspectjx: gradle - android plugin - aspectjx: 2.0.0'}}Copy the code

Gradle for your app project and build. Gradle for your new Module

apply plugin: 'android-aspectjx'

dependencies {
    ...
    implementation 'org. Aspectj: aspectjrt: 1.8 +'
}
Copy the code

2. Create a section

@Aspect
public class PerformanceAop {

    @Around("call(* com.bj.performance.MyApplication.**(..) )")
    public void getTime(ProceedingJoinPoint joinPoint){

        long startTime = System.currentTimeMillis();
        String methodName = joinPoint.getSignature().getName();
        try {
            joinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        Log.d("lybj", methodName + "Method time:"+ (System.currentTimeMillis() - startTime)); }}Copy the code

Look, you don’t need to change any engineering code at all, you can get the running time, hit Run display

AspectJ syntax reference

Disadvantages: If the project is huge and there are hundreds of methods, it is impossible to do all of them. Then, we need an intuitive tool to see which method takes too long at a glance.


5. Use of traceView

5.1 the characteristics of

  1. Graphical presentation of its run-time call stack
  2. Comprehensive information, including all processes

5.2 Usage Mode

Debug.startMethodTracing("File name");

Debug.stopMethodTracing();
Copy the code

StartMethodTracing has three construction parameters

  1. TracePath: file name/path
  2. BufferSize: indicates the file capacity
  3. Flag: TRACE_COUNT_ALLOCS only has the default value

When the code runs, it will run in

MNT/sdcard/Android/data/files/package name

Generates a file with the suffix.trace, which can be opened by adding Profiler.

Of course, the recording function of Profiler can also be used, but the hand speed of clicking to record is not so accurate to measure the startup time. Therefore, trace files are obtained by burying points for analysis.

5.3 Performance Analysis

Open the file as shown in the figure above

5.4 Time Mode

Figure 1 shows wallclock time and CPU time

  1. Wall Clock Time: The Time elapsed from the start of a process to the end of the process. This includes the Time spent in the blocked and waiting states.
  2. Thread Time: the Time it takes the CPU to execute the user’s command.

Note: If Thread A executes function B, but Thread A enters the wait state because function B is locked, wallclock time also counts time, while Thread time only counts the amount of time the CPU spends on it.

As a rule of thumb, the wall duration is long, and the value Thread time indicates how much time the CPU spends on it. A few can be directly asynchronous (because it does not preempt the CPU). A few need to properly schedule the execution order.

5.5 Call Chart

As shown in label 2 above: Call Chart

The X-axis is the time line of the call, the wider it is, the longer it takes, and the Y-axis is the depth of the call, that is, the submethods of the call. The parent class is at the top, and the initBottomTab () method call is obviously the most time-consuming.

Hover mouse can view time, double click can jump to the corresponding code

  • Orange: system method
  • Blue: Third-party apis (including those for the Java language)
  • Green: App’s own methods

A simple diagram is as follows:

5.6 Flame Chart

Flame Chart is also called a Flame Chart

The Y-axis represents the call stack, and each layer is a function. The deeper the call stack, the higher the flame, with the executing function at the top and its parent functions below. The X-axis represents the number of samples. The wider a function occupies along the X-axis, the more times it is drawn, or the longer it takes to execute. Note that the X-axis does not represent time, but rather all call stacks are grouped in alphabetical order.

The flame diagram is to see which function on the top takes up the most width. Any “flat top” (plateaus) indicates that the function may have a performance problem.

Exercise 1:

If the flame diagram looks like the one above, do we need to analyze any function?

A: The top-level function g() takes the most CPU time. D () has the largest width, but it consumes very little CPU directly. B () and C () do not consume CPU directly. Therefore, if you want to investigate performance issues, you should investigate G () first and I () second. In addition, it can be seen from the figure that A () has two branches b() and H (), which indicates that there may be a conditional statement in A (), and the B () branch consumes much more CPU than H ().

Different from Call Chart

Method D makes multiple calls to B(B1, B2, and B3), some of which call B to C(C1 and C3). If it is represented by Call Chart, then

Because B1, B2, and B3 share the same sequence caller (A→D→B) aggregation, as shown below. Similarly,C1 and C3 are aggregated because they share the same sequence caller (A→D→B→C). Note that C2 is not included because it has A different sequence of callers (A→D→C).

So if the flame chart is used, it means:

That is, the same methods that collect the same sequence of calls are collected and represented as one longer column in the flame chart (instead of displaying them as multiple shorter bars)

5.7 the Top Down

As shown in label 4 above: Top Down displays a list of function calls in which expanding the function node shows the function called

Look at the area on the right of the image above:

  • Self: The amount of time a method call spends executing its own code instead of its subclasses.
  • Children: Method calls spend time executing their callers, not their own code
  • Total: The sum of the time of the method Self and Children. This represents the total amount of time the application takes to execute method calls

5.8 Bottom Up

As shown in tag 5 above: Bottom Up displays a list of function calls where expanding the function node shows the caller of the function.

The Bottom Up TAB is useful for sorting methods that consume the most (or least)CPU time. Each node can be examined to determine which callers are spending the most CPU time calling these methods.

  • Self: The amount of time a method call spends executing its own code instead of its subclasses.
  • Children: Method calls spend time executing their callers, not their own code
  • Total: The sum of the time of the method Self and Children. This represents the sum of method calls performed by the application

Schematic diagram is as follows

Disadvantages: Call Chart and Top Down are most commonly used in projects. However, the principle of traceView is to capture information in all functions of all threads, which will slow Down the program. Therefore, SysTrace is commonly used

SysTrace author use not much, interested friends can search their own, the use of traceView and the use of similar, not analysis